From d20d36f7f29c518f63489291b56ddcbc9b9e4a08 Mon Sep 17 00:00:00 2001 From: Marko Haarni Date: Thu, 5 Dec 2024 12:58:23 +0200 Subject: [PATCH] HAI-934 Make sure that user sending johtoselvitys taydennys is added as a contact person (#1006) If user is not added as contact person, send button is disabled and a notification is shown. --- .../applicationView/ApplicationView.tsx | 2 +- .../hooks/useSendTaydennys.tsx | 43 ++++++++++++++----- .../JohtoselvitysTaydennys.test.tsx | 32 ++++++++++++++ .../JohtoselvitysTaydennysContainer.tsx | 26 ++++++++++- 4 files changed, 90 insertions(+), 13 deletions(-) diff --git a/src/domain/application/applicationView/ApplicationView.tsx b/src/domain/application/applicationView/ApplicationView.tsx index 23bb4de7..03a206bc 100644 --- a/src/domain/application/applicationView/ApplicationView.tsx +++ b/src/domain/application/applicationView/ApplicationView.tsx @@ -425,7 +425,7 @@ function ApplicationView({ const informationRequestFeatureEnabled = useIsInformationRequestFeatureEnabled(applicationType); - const { sendTaydennysButton, sendTaydennysDialog } = useSendTaydennys(application); + const { sendTaydennysButton, sendTaydennysDialog } = useSendTaydennys(application, signedInUser); async function onSendApplication(pdr: PaperDecisionReceiver | undefined | null) { applicationSendMutation.mutate({ diff --git a/src/domain/application/applicationView/hooks/useSendTaydennys.tsx b/src/domain/application/applicationView/hooks/useSendTaydennys.tsx index 41ab71e4..bcf2ddaf 100644 --- a/src/domain/application/applicationView/hooks/useSendTaydennys.tsx +++ b/src/domain/application/applicationView/hooks/useSendTaydennys.tsx @@ -1,18 +1,23 @@ import { useState } from 'react'; -import { Button, IconEnvelope, IconQuestionCircle } from 'hds-react'; +import { Button, IconEnvelope, IconQuestionCircle, Notification } from 'hds-react'; import { useTranslation } from 'react-i18next'; import { AlluStatus, Application } from '../../types/application'; import { validationSchema as johtoselvitysValidationSchema } from '../../../johtoselvitysTaydennys/validationSchema'; import ConfirmationDialog from '../../../../common/components/HDSConfirmationDialog/ConfirmationDialog'; import useIsInformationRequestFeatureEnabled from '../../taydennys/hooks/useIsInformationRequestFeatureEnabled'; import useSendTaydennysMutation from '../../taydennys/hooks/useSendTaydennys'; +import { isContactIn } from '../../utils'; +import { SignedInUser } from '../../../hanke/hankeUsers/hankeUser'; const validationSchemas = { CABLE_REPORT: johtoselvitysValidationSchema, EXCAVATION_NOTIFICATION: null, }; -export default function useSendTaydennys(application: Application) { +export default function useSendTaydennys( + application: Application, + signedInUser: SignedInUser | undefined, +) { const { t } = useTranslation(); const informationRequestFeatureEnabled = useIsInformationRequestFeatureEnabled( application.applicationType, @@ -27,6 +32,9 @@ export default function useSendTaydennys(application: Application) { application.taydennys.muutokset.length > 0; const [showSendTaydennysDialog, setShowSendTaydennysDialog] = useState(false); const sendTaydennysMutation = useSendTaydennysMutation(); + const isContact = + application.taydennys && isContactIn(signedInUser, application.taydennys.applicationData); + const disableSendButton = Boolean(!isContact); function openSendTaydennysDialog() { setShowSendTaydennysDialog(true); @@ -44,15 +52,28 @@ export default function useSendTaydennys(application: Application) { } const sendTaydennysButton = showSendTaydennysButton ? ( - + <> + + {disableSendButton && ( + + {t('hakemus:notifications:sendApplicationDisabled')} + + )} + ) : null; const sendTaydennysDialog = ( diff --git a/src/domain/johtoselvitysTaydennys/JohtoselvitysTaydennys.test.tsx b/src/domain/johtoselvitysTaydennys/JohtoselvitysTaydennys.test.tsx index d4be942a..d9427bf3 100644 --- a/src/domain/johtoselvitysTaydennys/JohtoselvitysTaydennys.test.tsx +++ b/src/domain/johtoselvitysTaydennys/JohtoselvitysTaydennys.test.tsx @@ -8,6 +8,7 @@ import hankkeet from '../mocks/data/hankkeet-data'; import hakemukset from '../mocks/data/hakemukset-data'; import { server } from '../mocks/test-server'; import { Taydennys } from '../application/taydennys/types'; +import { SignedInUser } from '../hanke/hankeUsers/hankeUser'; function setup( options: { @@ -179,4 +180,35 @@ describe('Sending taydennys', () => { expect(screen.queryByRole('button', { name: /lähetä täydennys/i })).not.toBeInTheDocument(); }); + + test('Should show and disable send button and show notification when user is not a contact person', async () => { + server.use( + http.get('/api/hankkeet/:hankeTunnus/whoami', async () => { + return HttpResponse.json({ + hankeKayttajaId: 'not-a-contact-person-id', + kayttooikeustaso: 'KATSELUOIKEUS', + kayttooikeudet: ['VIEW'], + }); + }), + ); + + const { user } = setup({ + taydennys: { + id: 'c0a1fe7b-326c-4b25-a7bc-d1797762c01c', + applicationData: cloneDeep(hakemukset[10] as Application) + .applicationData, + muutokset: ['name'], + }, + }); + + await user.click(screen.getByRole('button', { name: /yhteenveto/i })); + + expect(screen.queryByRole('button', { name: /lähetä täydennys/i })).toBeInTheDocument(); + expect(screen.queryByRole('button', { name: /lähetä täydennys/i })).toBeDisabled(); + expect( + screen.queryAllByText( + 'Hakemuksen voi lähettää ainoastaan hakemuksen yhteyshenkilönä oleva henkilö.', + ), + ).toHaveLength(2); + }); }); diff --git a/src/domain/johtoselvitysTaydennys/JohtoselvitysTaydennysContainer.tsx b/src/domain/johtoselvitysTaydennys/JohtoselvitysTaydennysContainer.tsx index 842b6a1b..5e5905d5 100644 --- a/src/domain/johtoselvitysTaydennys/JohtoselvitysTaydennysContainer.tsx +++ b/src/domain/johtoselvitysTaydennys/JohtoselvitysTaydennysContainer.tsx @@ -1,7 +1,14 @@ import { useState } from 'react'; import { FieldPath, FormProvider, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; -import { Button, IconEnvelope, IconQuestionCircle, IconSaveDiskette, StepState } from 'hds-react'; +import { + Button, + IconEnvelope, + IconQuestionCircle, + IconSaveDiskette, + Notification, + StepState, +} from 'hds-react'; import { yupResolver } from '@hookform/resolvers/yup'; import { useQueryClient } from 'react-query'; import { Taydennys } from '../application/taydennys/types'; @@ -34,6 +41,8 @@ import ApplicationSaveNotification from '../application/components/ApplicationSa import { changeFormStep } from '../forms/utils'; import ConfirmationDialog from '../../common/components/HDSConfirmationDialog/ConfirmationDialog'; import useSendTaydennys from '../application/taydennys/hooks/useSendTaydennys'; +import { isContactIn } from '../application/utils'; +import { usePermissionsForHanke } from '../hanke/hankeUsers/hooks/useUserRightsForHanke'; type Props = { taydennys: Taydennys; @@ -54,6 +63,7 @@ export default function JohtoselvitysTaydennysContainer({ useUpdateTaydennys(); const sendTaydennysMutation = useSendTaydennys(); const [showSendDialog, setShowSendDialog] = useState(false); + const { data: signedInUser } = usePermissionsForHanke(hankeData.hankeTunnus); const formContext = useForm({ mode: 'onTouched', @@ -240,6 +250,9 @@ export default function JohtoselvitysTaydennysContainer({ const lastStep = activeStepIndex === formSteps.length - 1; const showSendButton = lastStep && taydennys.muutokset.length > 0 && isValid; + const isContact = isContactIn(signedInUser, getValues('applicationData')); + const disableSendButton = showSendButton && !isContact; + const saveAndQuitIsLoading = taydennysUpdateMutation.isLoading; const saveAndQuitLoadingText = t('common:buttons:savingText'); return ( @@ -265,10 +278,21 @@ export default function JohtoselvitysTaydennysContainer({ iconLeft={