Skip to content
Snippets Groups Projects
Commit 65b687df authored by Tore.Brede's avatar Tore.Brede
Browse files

Merge branch 'GREG-85_add_passport_nationality' into 'master'

GREG-85: Add passport nationality

See merge request !116
parents 4321ed1b e49784b4
No related branches found
No related tags found
1 merge request!116GREG-85: Add passport nationality
Pipeline #97703 passed
......@@ -20,7 +20,9 @@
"email": "E-mail",
"fullName": "Full name",
"mobilePhone": "Mobile phone",
"passportNumber": "Passport number"
"passportNumber": "Passport number",
"passportNationality": "Passport nationality",
"countryCallingCode": "Country code"
},
"sponsor": {
"contactInfo": "Contact information",
......@@ -64,7 +66,8 @@
"emailRequired": "E-mail is required",
"invalidMobilePhoneNumber": "Invalid phone number",
"invalidEmail": "Invalid e-mail address",
"passportNumberRequired": "Passport number required"
"passportNumberRequired": "Passport number required",
"mobilePhoneRequired": "Mobile phone is required"
},
"button": {
"back": "Back",
......
......@@ -20,7 +20,9 @@
"email": "E-post",
"fullName": "Fullt navn",
"mobilePhone": "Mobilnummer",
"passportNumber": "Passport number"
"passportNumber": "Passnummer",
"passportNationality": "Passnasjonalitet",
"countryCallingCode": "Landkode"
},
"sponsor": {
"contactInfo": "Kontaktinformasjon",
......@@ -63,7 +65,8 @@
"emailRequired": "E-post er obligatorisk",
"invalidMobilePhoneNumber": "Ugyldig telefonnummer",
"invalidEmail": "Ugyldig e-postadresse",
"passportNumberRequired": "Passnummer er obligatorisk"
"passportNumberRequired": "Passnummer er obligatorisk",
"mobilePhoneRequired": "Mobilnummer er obligatorisk"
},
"button": {
"back": "Tilbake",
......
......@@ -21,7 +21,9 @@
"email": "E-post",
"fullName": "Fullt namn",
"mobilePhone": "Mobilnummer",
"passportNumber": "Passport number"
"passportNumber": "Passnummer",
"passportNationality": "Passnasjonalitet",
"countryCallingCode": "Landkode"
},
"sponsor": {
"contactInfo": "Kontaktinformasjon",
......@@ -64,7 +66,8 @@
"emailRequired": "E-post er obligatorisk",
"invalidMobilePhoneNumber": "Ugyldig telefonnummer",
"invalidEmail": "Ugyldig e-postadresse",
"passportNumberRequired": "Passnummer er obligatorisk"
"passportNumberRequired": "Passnummer er obligatorisk",
"mobilePhoneRequired": "Mobilnummer er obligatorisk"
},
"button": {
"back": "Tilbake",
......
......@@ -7,4 +7,5 @@ export type EnteredGuestData = {
mobilePhone: string
nationalIdNumber?: string
passportNumber?: string
passportNationality?: string
}
......@@ -21,6 +21,7 @@ export type ContactInformationBySponsor = {
mobile_phone?: string
fnr?: string
passport?: string
passportNationality?: string
authentication_method: AuthenticationMethod
}
......@@ -11,7 +11,7 @@ import { GuestRegisterCallableMethods } from './guestRegisterCallableMethods'
import { EnteredGuestData } from './enteredGuestData'
import { ContactInformationBySponsor } from './guestDataForm'
import AuthenticationMethod from './authenticationMethod'
import { postJsonOpts } from '../../../utils'
import { submitJsonOpts } from '../../../utils'
enum SubmitState {
NotSubmitted,
......@@ -51,9 +51,12 @@ export default function GuestRegister() {
mobile_phone: '',
fnr: '',
passport: '',
passportNationality: '',
authentication_method: AuthenticationMethod.Invite,
})
const [errorState, setErrorState] = useState<string>('')
const guestContactInfo = async () => {
try {
const response = await fetch('/api/ui/v1/invited')
......@@ -82,6 +85,8 @@ export default function GuestRegister() {
mobile_phone: jsonResponse.person.mobile_phone,
fnr: jsonResponse.fnr,
passport: jsonResponse.passport,
// TODO Separate out nationality based on what is in the server response
passportNationality: '',
authentication_method: authenticationMethod,
})
......@@ -112,15 +117,35 @@ export default function GuestRegister() {
const handleForwardFromRegister = (
updateFormData: EnteredGuestData
): void => {
const payload = {
person: {
mobile_phone: updateFormData.mobilePhone,
fnr: updateFormData.nationalIdNumber,
passport: updateFormData.passportNumber,
},
const payload: any = {}
payload.person = {}
payload.person.mobile_phone = updateFormData.mobilePhone
if (updateFormData.passportNumber && updateFormData.passportNationality) {
// The user has entered some passport information, check that both nationality and number are present
if (
(updateFormData.passportNumber &&
!updateFormData.passportNationality) ||
(!updateFormData.passportNumber && updateFormData.passportNationality)
) {
// TODO Make better text and use translation
setErrorState(
'Both passport nationality and passport number need to be set'
)
return
}
setErrorState('')
payload.person.passport = `${updateFormData.passportNationality}-${updateFormData.passportNumber}`
}
if (updateFormData.nationalIdNumber) {
payload.person.fnr = updateFormData.nationalIdNumber
}
fetch('/api/ui/v1/invited/', postJsonOpts(payload))
// TODO Remove after development
console.log(`Payload: ${JSON.stringify(payload)}`)
fetch('/api/ui/v1/invited/', submitJsonOpts('POST', payload))
.then((response) => {
if (response.ok) {
setSubmitState(SubmitState.Submitted)
......@@ -130,8 +155,8 @@ export default function GuestRegister() {
}
})
.catch((error) => {
console.error(error)
setSubmitState(SubmitState.SubmittedError)
console.error(error)
})
}
......@@ -177,6 +202,9 @@ export default function GuestRegister() {
{/* TODO This button is only for testing while developing */}
<Button onClick={handleSave}>{t('button.save')}</Button>
</Box>
{/* TODO Give better feedback to user */}
{errorState && <h2>{errorState}</h2>}
</Page>
)
}
......@@ -12,10 +12,11 @@ import React, { forwardRef, Ref, useImperativeHandle, useState } from 'react'
import { useTranslation } from 'react-i18next'
import {
CountryCallingCode,
CountryCode,
getCountries,
getCountryCallingCode,
} from 'libphonenumber-js'
import { getName } from 'i18n-iso-countries'
import { getAlpha2Codes, getName } from 'i18n-iso-countries'
import { ContactInformationBySponsor } from './guestDataForm'
import { EnteredGuestData } from './enteredGuestData'
import { GuestRegisterCallableMethods } from './guestRegisterCallableMethods'
......@@ -65,7 +66,7 @@ const GuestRegisterStep = forwardRef(
setValue,
trigger,
formState: { errors },
} = useForm()
} = useForm<EnteredGuestData>()
const onSubmit = handleSubmit<EnteredGuestData>(submit)
function doSubmit() {
......@@ -73,7 +74,7 @@ const GuestRegisterStep = forwardRef(
}
register('mobilePhone', {
required: t<string>('validation.roleTypeRequired'),
required: t<string>('validation.mobilePhoneRequired'),
validate: isValidMobilePhoneNumber,
})
......@@ -112,7 +113,7 @@ const GuestRegisterStep = forwardRef(
<TextField
id="email"
label={t('input.email')}
value={guestData.email}
value={!guestData.email ? '' : guestData.email}
disabled
/>
......@@ -120,7 +121,6 @@ const GuestRegisterStep = forwardRef(
sx={{
display: 'flex',
flexDirection: 'row',
paddingBottom: '2rem',
}}
>
<Select
......@@ -131,12 +131,26 @@ const GuestRegisterStep = forwardRef(
}}
labelId="phone-number-select"
id="phone-number-select"
displayEmpty
defaultValue=""
onChange={handleCountryCodeChange}
renderValue={(selected: any) => {
if (selected.length === 0 || selected === '') {
return t('input.countryCallingCode')
}
return `${getName(
selected,
i18n.language
)} (${getCountryCallingCode(selected as CountryCode)})`
}}
>
<MenuItem disabled value="">
{t('input.countryCallingCode')}
</MenuItem>
{getCountries().map((country) => (
<MenuItem key={country} value={country}>
{getName(country, i18n.language)} +
{getCountryCallingCode(country)}
{getName(country, i18n.language)} (
{getCountryCallingCode(country)})
</MenuItem>
))}
</Select>
......@@ -160,30 +174,64 @@ const GuestRegisterStep = forwardRef(
}}
/>
</Box>
{guestData.authentication_method ===
AuthenticationMethod.Invite && (
<>
<TextField
id="passport"
data-testid="passport_number_input"
label={t('input.passportNumber')}
{...register('passportNumber', {
required: t<string>('validation.passportNumberRequired'),
})}
/>
{/* The guest should fill in one of national ID number or passport number */}
<TextField
id="national_id_number"
label={t('input.nationalIdNumber')}
error={!!errors.national_id_number}
error={!!errors.nationalIdNumber}
helperText={
errors.nationalIdNumber && errors.nationalIdNumber.message
}
{...register('nationalIdNumber', {
validate: isValidFnr,
// It is not required that the national ID number be filled in, the guest may not have
// one, so allow empty values for the validation to pass
validate: (value) => isValidFnr(value, true),
})}
/>
<TextField
id="passport-number-id"
data-testid="passport_number_input"
label={t('input.passportNumber')}
{...register('passportNumber', {
required: false,
})}
/>
<Select
sx={{
maxHeight: '2.5rem',
}}
id="passport-nationality-id"
labelId="passport-nationality-label"
label={t('input.passportNationality')}
displayEmpty
defaultValue=""
{...register('passportNationality', {
required: false,
})}
renderValue={(selected: any) => {
if (!selected || selected.length === 0) {
return t('input.passportNationality')
}
return getName(selected, i18n.language)
}}
>
<MenuItem disabled value="">
{t('input.passportNationality')}
</MenuItem>
{Object.keys(getAlpha2Codes()).map((countryAlpha2Code) => (
<MenuItem
key={countryAlpha2Code}
value={countryAlpha2Code}
>
{getName(countryAlpha2Code, i18n.language)}
</MenuItem>
))}
</Select>
</>
)}
......
......@@ -43,8 +43,14 @@ export function submitJsonOpts(method: string, data: object): RequestInit {
}
}
export function isValidFnr(data: string | undefined): boolean | string {
if (data === undefined) {
export function isValidFnr(
data: string | undefined,
allowEmpty = false
): boolean | string {
if (!data) {
if (allowEmpty) {
return true
}
return i18n.t<string>('common:validation.invalidIdNumber').toString()
}
const valid = validator.idnr(data as string).status === 'valid'
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment