From 097612c0de9750fe7d5b75daf6a82db1f45cae88 Mon Sep 17 00:00:00 2001 From: Andreas Ellewsen <ae@uio.no> Date: Mon, 13 Dec 2021 14:31:19 +0100 Subject: [PATCH] Modify register step form for guests - Passport Country now displays two letter code after selection. - A heading has been added for identity information. - An error message is now displayed if the user inputs both national id and passport information. Resolves: GREG-120 --- frontend/public/locales/en/common.json | 3 + frontend/public/locales/nb/common.json | 3 + frontend/public/locales/nn/common.json | 3 + .../src/routes/guest/register/index.test.tsx | 2 +- .../routes/guest/register/steps/register.tsx | 176 +++++++++++------- 5 files changed, 115 insertions(+), 72 deletions(-) diff --git a/frontend/public/locales/en/common.json b/frontend/public/locales/en/common.json index fc1eda76..cd7f9f96 100644 --- a/frontend/public/locales/en/common.json +++ b/frontend/public/locales/en/common.json @@ -100,6 +100,7 @@ "startDateMustBeSet": "Start date must be set", "startDateMustBeBeforeEndDate": "Start date has to be before end date", "passportNationalityAndNumber": "Both passport nationality and number need to be set", + "doubleIdentity": "*You have input both national ID and passport. Please choose only one.", "nationalIdOrPassport": "National ID or passport information need to be entered" }, "button": { @@ -134,6 +135,8 @@ "registerNewGuest": "Register new guest", "guestOverview": "Guest overview", "guestRegisterWizardText": { + "identityHeader": "Identify yourself ", + "identityBody": "Enter national identity number if you have one. Otherwise use passport information.", "yourContactInformation": "Your contact information", "contactInformationDescription": "Fill in your mobile phone number.", "yourGuestPeriod": "Your guest period", diff --git a/frontend/public/locales/nb/common.json b/frontend/public/locales/nb/common.json index 79d565aa..0b21b590 100644 --- a/frontend/public/locales/nb/common.json +++ b/frontend/public/locales/nb/common.json @@ -100,6 +100,7 @@ "startDateMustBeSet": "Startdato må være satt", "startDateMustBeBeforeEndDate": "Startdato må være før sluttdato", "passportNationalityAndNumber": "Både passnasjonalitet og nummer må være satt", + "doubleIdentity": "*Du har fylt inn begge feltene over. Bruk kun ett av de.", "nationalIdOrPassport": "Fødselsnummer/D-nummer eller passinformasjon må spesifiseres" }, "button": { @@ -134,6 +135,8 @@ "registerNewGuest": "Registrer ny gjest", "guestOverview": "Oversikt over gjest", "guestRegisterWizardText": { + "identityHeader": "Identifiser deg ", + "identityBody": "Fyll inn fødselsnummer hvis du har. <1>Eller</1> nasjonalitet og passnummer.", "yourContactInformation": "Din kontaktinfo", "contactInformationDescription": "Fyll inn ditt mobilnummer.", "yourGuestPeriod": "Din gjesteperiode", diff --git a/frontend/public/locales/nn/common.json b/frontend/public/locales/nn/common.json index c49aa0b3..a16fe804 100644 --- a/frontend/public/locales/nn/common.json +++ b/frontend/public/locales/nn/common.json @@ -101,6 +101,7 @@ "startDateMustBeSet": "Startdato må vere satt", "startDateMustBeBeforeEndDate": "Startdato må vere før sluttdato", "passportNationalityAndNumber": "Både passnasjonalitet og nummer må vere satt", + "doubleIdentity": "*Du har fylt inn begge feltene over. Bruk kun ett av de.", "nationalIdOrPassport": "Fødselsnummer/D-nummer eller passinformasjon må spesifiserast" }, "button": { @@ -135,6 +136,8 @@ "registerNewGuest": "Registrer ny gjest", "guestOverview": "Oversikt over gjest", "guestRegisterWizardText": { + "identityHeader": "Identifiser deg ", + "identityBody": "Fyll inn fødselsnummer hvis du har. <1>Eller</1> nasjonalitet og passnummer.", "yourContactInformation": "Din kontaktinfo", "contactInformationDescription": "Fyll inn ditt mobilnummer.", "yourGuestPeriod": "Din gjesteperiode", diff --git a/frontend/src/routes/guest/register/index.test.tsx b/frontend/src/routes/guest/register/index.test.tsx index 0ac01aee..8b09debb 100644 --- a/frontend/src/routes/guest/register/index.test.tsx +++ b/frontend/src/routes/guest/register/index.test.tsx @@ -50,7 +50,7 @@ test('Field showing values correctly', async () => { await screen.findByDisplayValue(testData.person.fnr) // Passport nationality. The i18n-mock sets up en as the i18n.language property, so look for the English name - await screen.findByText('Denmark') + await screen.findByText('DK') await screen.findByDisplayValue('123456') await screen.findByDisplayValue(testData.person.date_of_birth) diff --git a/frontend/src/routes/guest/register/steps/register.tsx b/frontend/src/routes/guest/register/steps/register.tsx index 3b4fbb35..cc4366c8 100644 --- a/frontend/src/routes/guest/register/steps/register.tsx +++ b/frontend/src/routes/guest/register/steps/register.tsx @@ -1,5 +1,6 @@ import { Box, + Divider, MenuItem, Select, SelectChangeEvent, @@ -16,7 +17,7 @@ import React, { useImperativeHandle, useState, } from 'react' -import { useTranslation } from 'react-i18next' +import { useTranslation, Trans } from 'react-i18next' import { CountryCallingCode, CountryCode, @@ -81,6 +82,7 @@ const GuestRegisterStep = forwardRef( console.log('submit data is', data) const result = await trigger() console.log('trigger result is', result) + const tohandler = data if ( !data.nationalIdNumber && !data.passportNumber && @@ -92,6 +94,22 @@ const GuestRegisterStep = forwardRef( return } + // Users should only input NIN or passport + if (data.passportNumber && data.nationalIdNumber) { + setIdErrorState(t('validation.doubleIdentity')) + return + } + // Reset passportNationality if NIN is set and passport is empty + if ( + data.nationalIdNumber && + !data.passportNumber && + data.passportNationality + ) { + setValue('passportNationality', '') + setPassportNationality('') + tohandler.passportNationality = '' + } + // if one on the passport fields are set, check that both are set if ( (data.passportNumber && !data.passportNationality) || @@ -105,7 +123,7 @@ const GuestRegisterStep = forwardRef( console.log('register submit errors', errors) if (!Object.keys(errors).length) { - nextHandler(data) + nextHandler(tohandler) } } const onSubmit = handleSubmit<GuestRegisterData>(submit) @@ -173,21 +191,41 @@ const GuestRegisterStep = forwardRef( useImperativeHandle(ref, () => ({ doSubmit: () => onSubmit() })) + const passportCountries = Object.keys(getAlpha2Codes()) + .map((countryAlphaCode: string) => { + const countryTuple: [string, string] = [ + countryAlphaCode, + getName(countryAlphaCode, i18n.language), + ] + return countryTuple + }) + .filter( + (countryTuple: [string, string]) => + // All countries are expected to have a name, this filtering + // is here to make some tests run in an environment where the + // internationalization is not set up + countryTuple[1] !== undefined + ) + .sort( + (countryTuple1: [string, string], countryTuple2: [string, string]) => + countryTuple1[1].localeCompare(countryTuple2[1]) + ) return ( <> - <Typography - variant="h5" - sx={{ - paddingTop: '1rem', - paddingBottom: '1rem', - }} - > - {t('guestRegisterWizardText.yourContactInformation')} - </Typography> - <Typography sx={{ paddingBottom: '2rem' }}> - {t('guestRegisterWizardText.contactInformationDescription')} - </Typography> <Box sx={{ maxWidth: '30rem' }}> + <Typography + variant="h5" + sx={{ + paddingTop: '1rem', + paddingBottom: '1rem', + }} + > + {t('guestRegisterWizardText.yourContactInformation')} + </Typography> + <Typography sx={{ paddingBottom: '2rem' }}> + {t('guestRegisterWizardText.contactInformationDescription')} + <Divider sx={{ border: '1px solid' }} /> + </Typography> <form onSubmit={onSubmit}> <Stack spacing={2}> {/* The name is only editable if it is it is not coming from some trusted source */} @@ -395,6 +433,15 @@ const GuestRegisterStep = forwardRef( {initialGuestData.authentication_method === AuthenticationMethod.Invite && ( <> + <Typography variant="h5" sx={{ paddingTop: '1rem' }}> + {t('guestRegisterWizardText.identityHeader')} + </Typography> + <Typography sx={{ paddingBottom: '1rem' }}> + <Trans i18nKey="common:guestRegisterWizardText.identityBody"> + Placeholder with <strong>asd</strong> text + </Trans> + <Divider sx={{ border: '1px solid' }} /> + </Typography> {/* The guest should fill in one of national ID number or passport number */} <Controller name="nationalIdNumber" @@ -419,68 +466,54 @@ const GuestRegisterStep = forwardRef( /> )} /> - - <Controller - name="passportNumber" - control={control} - render={({ field }) => ( - <TextField - id="passportNumber" - data-testid="passport_number_input" - value={field.value} - label={t('input.passportNumber')} - onChange={field.onChange} - /> - )} - /> - - <Select + <Box sx={{ - maxHeight: '2.5rem', - }} - id="passport-nationality-id" - labelId="passport-nationality-label" - label={t('input.passportNationality')} - displayEmpty - value={passportNationality ?? ''} - onChange={handlePassportNationalityChange} - renderValue={(selected: any) => { - if (!selected || selected.length === 0) { - return t('input.passportNationality') - } - return getName(selected, i18n.language) + display: 'flex', + flexDirection: 'row', }} > - <MenuItem disabled value=""> - {t('input.passportNationality')} - </MenuItem> - {Object.keys(getAlpha2Codes()) - .map((countryAlphaCode: string) => { - const countryTuple: [string, string] = [ - countryAlphaCode, - getName(countryAlphaCode, i18n.language), - ] - return countryTuple - }) - .filter( - (countryTuple: [string, string]) => - // All countries are expected to have a name, this filtering - // is here to make some tests run in an environment where the - // internationalization is not set up - countryTuple[1] !== undefined - ) - .sort( - ( - countryTuple1: [string, string], - countryTuple2: [string, string] - ) => countryTuple1[1].localeCompare(countryTuple2[1]) - ) - .map((countryTuple) => ( - <MenuItem key={countryTuple[0]} value={countryTuple[0]}> - {countryTuple[1]} + <Select + sx={{ + maxHeight: '2.5rem', + minWidth: '5rem', + marginRight: '0.5rem', + }} + id="passport-nationality-id" + labelId="passport-nationality-label" + label={t('input.passportNationality')} + displayEmpty + value={passportNationality ?? ''} + onChange={handlePassportNationalityChange} + renderValue={(selected: any) => { + if (!selected || selected.length === 0) { + return t('input.passportNationality') + } + return selected + }} + > + <MenuItem disabled value=""> + {t('input.passportNationality')} + </MenuItem> + {passportCountries.map((countryTuple) => ( + <MenuItem key={countryTuple[1]} value={countryTuple[0]}> + {`${countryTuple[1]} (${countryTuple[0]})`} </MenuItem> ))} - </Select> + </Select> + <Controller + name="passportNumber" + control={control} + render={({ field }) => ( + <TextField + id="passportNumber" + data-testid="passport_number_input" + value={field.value} + label={t('input.passportNumber')} + onChange={field.onChange} + /> + )} + /> + </Box> {idErrorState && ( <Typography color="error">{idErrorState}</Typography> )} @@ -502,6 +535,7 @@ const GuestRegisterStep = forwardRef( </Typography> <Typography sx={{ paddingBottom: '1rem' }}> {t('guestRegisterWizardText.guestPeriodDescription')} + <Divider sx={{ border: '1px solid' }} /> </Typography> <TextField id="ou-unit" -- GitLab