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

Merge branch 'GREG-60_update_wizard_fields' into 'master'

GREG-60: Update wizard fields

See merge request !80
parents 9e39a2cd 2f2606f2
No related branches found
No related tags found
1 merge request!80GREG-60: Update wizard fields
Pipeline #95809 passed
......@@ -20,7 +20,8 @@
"roleType": "Role",
"roleStartDate": "From",
"roleEndDate": "To",
"comment": "Comment"
"comment": "Comment",
"email": "E-mail"
},
"loading": "Loading...",
"termsHeader": "Terms",
......@@ -48,7 +49,8 @@
"invalidIdNumber": "Invalid national ID number",
"nationalIdNumberRequired": "National ID number required",
"roleTypeRequired": "Role type is required",
"roleEndRequired": "Role end date is required"
"roleEndRequired": "Role end date is required",
"emailRequired": "E-mail is required"
},
"button": {
"back": "Back",
......
......@@ -20,7 +20,8 @@
"roleType": "Gjesterolle",
"roleStartDate": "Fra",
"roleEndDate": "Til",
"comment": "Kommentar"
"comment": "Kommentar",
"email": "E-post"
},
"loading": "Laster...",
"termsHeader": "Vilkår",
......@@ -48,7 +49,8 @@
"invalidIdNumber": "Ugyldig fødselsnummer",
"nationalIdNumberRequired": "Fødselsnummer er påkrevd",
"roleTypeRequired": "Rolletype er påkrevd",
"roleEndRequired": "Sluttdato for rolle er påkrevd"
"roleEndRequired": "Sluttdato for rolle er påkrevd",
"emailRequired": "E-post er obligatorisk"
},
"button": {
"back": "Tilbake",
......
......@@ -21,7 +21,8 @@
"roleType": "Gjesterolle",
"roleStartDate": "Frå",
"roleEndDate": "Til",
"comment": "Kommentar"
"comment": "Kommentar",
"email": "E-post"
},
"loading": "Lastar...",
"termsHeader": "Vilkår",
......@@ -49,7 +50,8 @@
"invalidIdNumber": "Ugyldig fødselsnummer",
"nationalIdNumberRequired": "Fødselsnummer er påkrevd",
"roleTypeRequired": "Rolletype er påkrevd",
"roleEndRequired": "Sluttdato for rolle er påkrevd"
"roleEndRequired": "Sluttdato for rolle er påkrevd",
"emailRequired": "E-post er obligatorisk"
},
"button": {
"back": "Tilbake",
......
import { createContext } from 'react'
// eslint-disable-next-line import/prefer-default-export
export const RolesContext = createContext<any[]>([])
import { useState, useEffect } from 'react'
type RoleTypeData = {
identifier: string
name_en: string
name_nb: string
}
function useRoleTypes(): RoleTypeData[] {
const [roleTypes, setRoleTypes] = useState<RoleTypeData[]>([])
async function fetchRoleTypes() {
fetch(`http://localhost:3000/api/ui/v1/roletypes`)
.then(data => data.text())
.then((result => {
// The response is a JSON-array
setRoleTypes(JSON.parse(result))
}))
.catch(error => {
console.error(error)
})
}
useEffect(() => {
fetchRoleTypes()
}, [])
return roleTypes
}
export type { RoleTypeData }
export default useRoleTypes
......@@ -25,9 +25,6 @@ export default function FrontPage() {
<li>
<Link to="/register/">Registration</Link>
</li>
<li>
<Link to="/registerwizard/">Registration wizard</Link>
</li>
</ul>
</p>
<Debug />
......
export type RegisterFormData = {
first_name?: string
last_name?: string
date_of_birth?: Date
national_id_number?: string
role_type?: string
role_start?: Date
role_end?: Date
comment?: string
ou?: { value: string; label: string }
ou_id?: number
email?: string
}
\ No newline at end of file
import React, { useEffect, useState, useRef } from 'react'
import React, { useState, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { Box, Button, Step, StepLabel, Stepper } from '@mui/material'
......@@ -12,53 +12,26 @@ import StepPersonForm from './stepPersonForm'
import { PersonFormMethods } from './personFormMethods'
import { SummaryFormMethods } from './summaryFormMethods'
import { RolesContext } from '../../context'
const steps = ['Register', 'Summary']
export default function StepRegistration() {
const { t } = useTranslation(['common'])
const [roletypes, setRoletypes] = useState<any[]>([])
const [formData, setFormData] = useState<RegisterFormData>({
first_name: undefined,
last_name: undefined,
date_of_birth: undefined,
national_id_number: undefined,
role_type: undefined,
role_start: undefined,
role_end: undefined,
comment: undefined,
ou: undefined,
ou_id: undefined,
email: undefined,
})
const history = useHistory()
const REGISTER_STEP = 0
const SUMMARY_STEP = 1
async function fetchRoletypes(onSuccess: (result: Array<any>) => void, onError: (error: any) => void) {
fetch(`http://localhost:3000/api/ui/v1/roletypes/`)
.then(data => data.text())
.then((result => {
// The response is a JSON-array
onSuccess(JSON.parse(result))
}))
.catch(error => {
onError(error)
})
}
useEffect(() => {
fetchRoletypes(
(result) => {
setRoletypes(result)
},
(error) => {
console.log(error)
})
// Having an empty dependency array causes the role types only to be loaded once
}, [])
const [activeStep, setActiveStep] = useState(0)
const personFormRef = useRef<PersonFormMethods>(null)
const summaryStepRef = useRef<SummaryFormMethods>(null)
......@@ -93,65 +66,63 @@ export default function StepRegistration() {
}
return (
<RolesContext.Provider value={roletypes}>
<Page header='Register as a guest'>
{/* Stepper at top of wizard */}
<Stepper activeStep={activeStep}>
{/* eslint-disable-next-line @typescript-eslint/no-unused-vars */}
{steps.map((label, index) => {
const stepProps = {}
const labelProps = {}
return (
<Step key={label} {...stepProps}>
<StepLabel {...labelProps}>{label}</StepLabel>
</Step>
)
})}
</Stepper>
{/* Current page in wizard */}
<Box sx={{ width: '100%' }}>
{activeStep === REGISTER_STEP && (
<StepPersonForm nextHandler={handleForwardFromRegister} formData={formData}
ref={personFormRef} />
<Page header='Register as a guest'>
{/* Stepper at top of wizard */}
<Stepper activeStep={activeStep}>
{/* eslint-disable-next-line @typescript-eslint/no-unused-vars */}
{steps.map((label, index) => {
const stepProps = {}
const labelProps = {}
return (
<Step key={label} {...stepProps}>
<StepLabel {...labelProps}>{label}</StepLabel>
</Step>
)
}
{activeStep === SUMMARY_STEP && (
<StepSummary formData={formData} ref={summaryStepRef} />
)}
</Box>
<Box sx={{ display: 'flex', flexDirection: 'row', pt: 2, color: 'primary.main' }}>
{activeStep === REGISTER_STEP && (
<Button data-testid='button-next' onClick={handleNext}>
{t('button.next')}
</Button>
)}
{activeStep === SUMMARY_STEP && (
<>
<Button
onClick={handleBack}
sx={{ mr: 1 }}
>
{t('button.back')}
</Button>
<Button onClick={registerGuest}
sx={{ mr: 1 }}
>
{t('button.save')}
</Button>
</>
)}
<Button onClick={handleCancel}>
{t('button.cancel')}
})}
</Stepper>
{/* Current page in wizard */}
<Box sx={{ width: '100%' }}>
{activeStep === REGISTER_STEP && (
<StepPersonForm nextHandler={handleForwardFromRegister} formData={formData}
ref={personFormRef} />
)
}
{activeStep === SUMMARY_STEP && (
<StepSummary formData={formData} ref={summaryStepRef} />
)}
</Box>
<Box sx={{ display: 'flex', flexDirection: 'row', pt: 2, color: 'primary.main' }}>
{activeStep === REGISTER_STEP && (
<Button data-testid='button-next' onClick={handleNext}>
{t('button.next')}
</Button>
</Box>
)}
{activeStep === SUMMARY_STEP && (
<>
<Button
onClick={handleBack}
sx={{ mr: 1 }}
>
{t('button.back')}
</Button>
<Button onClick={registerGuest}
sx={{ mr: 1 }}
>
{t('button.save')}
</Button>
</>
)}
<Button onClick={handleCancel}>
{t('button.cancel')}
</Button>
</Box>
</Page>
</RolesContext.Provider>
</Page>
)
}
import { Box, FormControl, InputLabel, MenuItem, Select, SelectChangeEvent, Stack, TextField } from '@mui/material'
import { Controller, SubmitHandler, useForm } from 'react-hook-form'
import { DatePicker } from '@mui/lab'
import React, { forwardRef, Ref, useEffect, useImperativeHandle, useContext, useState } from 'react'
import React, { forwardRef, Ref, useEffect, useImperativeHandle, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { isValidFnr } from '../../utils'
import { RegisterFormData } from './formData'
import { PersonFormMethods } from './personFormMethods'
import { RolesContext } from '../../context'
import useOus, { OuData } from '../../hooks/useOus'
import useRoleTypes, { RoleTypeData } from '../../hooks/useRoleTypes'
interface StepPersonFormProperties {
......@@ -19,9 +18,18 @@ interface StepPersonFormProperties {
const StepPersonForm = forwardRef((props: StepPersonFormProperties, ref: Ref<PersonFormMethods>) => {
const { i18n, t } = useTranslation(['common'])
const { nextHandler, formData } = props
const roletypes = useContext(RolesContext)
const ous = useOus()
const [ouChoice, setOuChoice] = useState('')
const [ouChoice, setOuChoice] = useState(formData.ou_id ? formData.ou_id : '')
const [selectedRoleType, setSelectedRoleType] = useState(formData.role_type ? formData.role_type : '')
const roleTypes = useRoleTypes()
const roleTypeSort = () => (a: RoleTypeData, b: RoleTypeData) => {
if (i18n.language === 'en') {
return a.name_nb.localeCompare(b.name_nb)
}
return a.name_en.localeCompare(b.name_en)
}
const enSort = (a: OuData, b: OuData) => {
if (a.en > b.en) {
......@@ -53,6 +61,7 @@ const StepPersonForm = forwardRef((props: StepPersonFormProperties, ref: Ref<Per
handleSubmit,
formState: { errors },
reset,
setValue,
} = useForm<RegisterFormData>()
const onSubmit = handleSubmit(submit)
......@@ -61,15 +70,28 @@ const StepPersonForm = forwardRef((props: StepPersonFormProperties, ref: Ref<Per
reset(formData)
}, [])
const handleChange = (event: SelectChangeEvent) => {
setOuChoice(event.target.value)
const handleOuChange = (event: SelectChangeEvent) => {
if (event.target.value) {
setOuChoice(event.target.value)
setValue('ou_id', parseInt(event.target.value, 10))
} else {
setValue('ou_id', undefined)
}
}
register('role_type', {
required: t('validation.roleTypeRequired').toString(),
})
const handleRoleTypeChange = (event: any) => {
setValue('role_type', event.target.value)
setSelectedRoleType(event.target.value)
}
function doSubmit() {
return onSubmit()
}
useImperativeHandle(ref, () => ({ doSubmit }))
return (
......@@ -94,49 +116,23 @@ const StepPersonForm = forwardRef((props: StepPersonFormProperties, ref: Ref<Per
required: t('validation.lastNameRequired').toString(),
})}
/>
<Controller name='date_of_birth'
control={control}
rules={{
required: t(
'validation.dateOfBirthRequired').toString(),
}}
render={({ field }) => (
<DatePicker
mask='____-__-__'
label={t('input.dateOfBirth')}
value={field.value}
inputFormat='yyyy-MM-dd'
onChange={(value) => {
field.onChange(value)
}}
renderInput={(params) => <TextField {...params} />}
/>)}
/>
<TextField
id='nationalIdNumber'
label={t('input.nationalIdNumber')}
error={!!errors.national_id_number}
helperText={
errors.national_id_number && errors.national_id_number.message
}
{...register('national_id_number', {
required: t(
'validation.nationalIdNumberRequired',
).toString(),
validate: isValidFnr,
id='email'
label={t('input.email')}
error={!!errors.email}
helperText={errors.email && errors.email.message}
{...register(`email`, {
required: t('validation.emailRequired').toString(),
})}
/>
<FormControl fullWidth>
<InputLabel id='ou-select-label'>{t('common:ou')}</InputLabel>
<Select
labelId='ou-select-label'
id='ou-select-label'
value={ouChoice}
value={ouChoice?.toString()}
label={t('common:ou')}
onChange={handleChange}
onChange={handleOuChange}
>
{ous.length > 0 ? (
ous
......@@ -155,18 +151,17 @@ const StepPersonForm = forwardRef((props: StepPersonFormProperties, ref: Ref<Per
<TextField
id='roletype-select'
select
defaultValue=''
value={selectedRoleType}
error={!!errors.role_type}
label={t('input.roleType')}
{...register(`role_type`, {
required: t('validation.roleTypeRequired').toString(),
})}
onChange={handleRoleTypeChange}
>
{
// TODO Use selected language in role type list
roletypes.map((roletype) => (
<MenuItem value={roletype.identifier}>{roletype.name_nb}</MenuItem>
))
roleTypes.sort(roleTypeSort())
.map((roleType) => (
<MenuItem
value={roleType.identifier}>{i18n.language === 'en' ? roleType.name_en : roleType.name_nb}</MenuItem>
))
}
</TextField>
......
......@@ -9,6 +9,8 @@ import { DatePicker } from '@mui/lab'
import { RegisterFormData } from './formData'
import { postJsonOpts } from '../../utils'
import { PersonFormMethods } from './personFormMethods'
import useOus from '../../hooks/useOus'
import useRoleTypes from '../../hooks/useRoleTypes'
interface StepSummaryProperties {
......@@ -16,20 +18,21 @@ interface StepSummaryProperties {
}
const StepSummary = forwardRef((props: StepSummaryProperties, ref: Ref<PersonFormMethods>) => {
const { t } = useTranslation(['common'])
const { i18n, t } = useTranslation(['common'])
const { formData } = props
const ous = useOus()
const roleTypes = useRoleTypes()
const submit: SubmitHandler<RegisterFormData> = (data) => {
const payload = {
first_name: data.first_name,
last_name: data.last_name,
date_of_birth: data.date_of_birth === null ? null : format(data.date_of_birth as Date, 'yyyy-MM-dd'),
national_id_number: data.national_id_number,
role_type: data.role_type,
role_start: data.role_start === null ? null : format(data.role_start as Date, 'yyyy-MM-dd'),
role_end: data.role_end === null ? null : format(data.role_end as Date, 'yyyy-MM-dd'),
comment: data.comment,
ou: data.ou,
ou: data.ou_id,
email: data.email,
}
console.log('submitting', JSON.stringify(payload))
fetch('http://localhost:3000/api/ui/v1/register/', postJsonOpts(payload))
......@@ -42,6 +45,38 @@ const StepSummary = forwardRef((props: StepSummaryProperties, ref: Ref<PersonFor
})
}
const getSelectedOrganisationalUnit = () => {
if (formData?.ou_id) {
const ousArray = ous.filter(((value) => value.id === formData.ou_id))
if (ousArray.length === 0) {
return ''
}
if (i18n.language === 'en') {
return ousArray[0].en
}
return ousArray[0].nb
}
return ''
}
const getSelectedRoleType = () => {
if (formData?.role_type) {
const roleTypeArray = roleTypes.filter(((value) => value.identifier === formData.role_type))
if (roleTypeArray.length === 0) {
return ''
}
if (i18n.language === 'en') {
return roleTypeArray[0].name_en
}
return roleTypeArray[0].name_nb
}
return ''
}
const {
reset,
register,
......@@ -81,35 +116,25 @@ const StepSummary = forwardRef((props: StepSummaryProperties, ref: Ref<PersonFor
{...register('last_name')}
/>
<Controller name='date_of_birth'
control={control}
render={({ field }) => (
<DatePicker
mask='____-__-__'
label={t('input.dateOfBirth')}
disabled
value={field.value}
inputFormat='yyyy-MM-dd'
onChange={(value) => {
field.onChange(value)
}}
renderInput={(params) => <TextField {...params} />}
/>)}
<TextField
id='email'
label={t('input.email')}
disabled
{...register('email')}
/>
<TextField
id='nationalIdNumber'
label={t('input.nationalIdNumber')}
id='ou'
value={getSelectedOrganisationalUnit()}
label={t('ou')}
disabled
{...register('national_id_number')}
/>
<TextField
id='roletype-select'
defaultValue=''
value={getSelectedRoleType()}
label={t('input.roleType')}
disabled
{...register(`role_type`)}
/>
<Controller name='role_start'
......
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