diff --git a/frontend/public/locales/en/common.json b/frontend/public/locales/en/common.json index aadefb1877f8d79e9f9d49a7d81f3ffab098ec31..e298c202361e0ab9080cf7c5adc308af7db36770 100644 --- a/frontend/public/locales/en/common.json +++ b/frontend/public/locales/en/common.json @@ -214,5 +214,8 @@ "duplicate_private_national_id_number": "There is already a guest with the national ID number given", "duplicate_private_passport_number": "There is already a guest with the passport number given" } + }, + "update": { + "email": "E-mail updated successful" } } diff --git a/frontend/public/locales/nb/common.json b/frontend/public/locales/nb/common.json index dba5a06fa24c774442e9d6e1dbfd23f70b9142cb..b142ab0bd836e6885f4b1659943e46342c12c9f6 100644 --- a/frontend/public/locales/nb/common.json +++ b/frontend/public/locales/nb/common.json @@ -214,5 +214,8 @@ "duplicate_private_national_id_number": "Det eksisterer allerede en gjest med gitt fødselsnummer/D-nummer", "duplicate_private_passport_number": "Det eksisterer allerede en gjest med gitt passnummer" } + }, + "update": { + "email": "E-postadressen ble endret" } } diff --git a/frontend/public/locales/nn/common.json b/frontend/public/locales/nn/common.json index 694a29a27484eec471c68b392cd2e0557983a40d..28d7a797b56102c66a7f540d1e1092c83640df62 100644 --- a/frontend/public/locales/nn/common.json +++ b/frontend/public/locales/nn/common.json @@ -214,5 +214,8 @@ "duplicate_private_national_id_number": "Det eksisterer allereie ein gjest med dette fødselsnummeret/D-nummeret", "duplicate_private_passport_number": "Det eksisterer allereie ein gjest med dette passnummeret" } + }, + "update": { + "email": "E-postadressa ble endra" } } diff --git a/frontend/src/routes/sponsor/guest/guestInfo/index.tsx b/frontend/src/routes/sponsor/guest/guestInfo/index.tsx index 1a6fb58d3db0a4853b6ec6093af37f05a581da25..09af68476d1a06e4e81f2e1d5e5dc2e228abf283 100644 --- a/frontend/src/routes/sponsor/guest/guestInfo/index.tsx +++ b/frontend/src/routes/sponsor/guest/guestInfo/index.tsx @@ -1,36 +1,37 @@ -import { Link, useParams, useNavigate } from 'react-router-dom' - -import Page from 'components/page' -import RoleLine from 'components/roleLine' -import { useTranslation } from 'react-i18next' +import { useEffect, useState } from 'react' import { + Alert, Button, - Table, - TableBody, Box, Dialog, DialogTitle, DialogContent, DialogActions, + Table, + TableBody, TextField, Typography, } from '@mui/material' +import { Controller, SubmitHandler, useForm } from 'react-hook-form' +import { useTranslation } from 'react-i18next' +import { Link, useNavigate, useParams } from 'react-router-dom' + +import ServerErrorReport, { + ServerErrorReportData, +} from 'components/errorReport' +import IdentityLine from 'components/identityLine' +import Page from 'components/page' +import RoleLine from 'components/roleLine' import { + TableCell, TableContainer, TableHead, TableHeadCell, TableRow, - TableCell, } from 'components/table' import { Guest } from 'interfaces' import SponsorInfoButtons from 'routes/components/sponsorInfoButtons' -import React, { useEffect, useState } from 'react' -import { SubmitHandler, useForm } from 'react-hook-form' -import IdentityLine from 'components/identityLine' import { isValidEmail, submitJsonOpts } from 'utils' -import ServerErrorReport, { - ServerErrorReportData, -} from '../../../../components/errorReport' type GuestInfoParams = { pid: string @@ -99,16 +100,18 @@ export default function GuestInfo({ const [confirmCancelDialogOpen, setConfirmCancelDialogOpen] = useState(false) const [emailUpdateError, setEmailUpdateError] = useState<ServerErrorReportData>() + const [updateOKMsg, setUpdateOKMsg] = useState<string>('') // Using useForm even though only the e-mail is allow to change at present, since useForm makes setup and validation easier const { + control, handleSubmit, setValue, - register, reset, formState: { errors, isValid, isDirty }, } = useForm<Email>({ - mode: 'onChange', + mode: 'onTouched', + defaultValues: { email: guest.email ?? '' }, }) // This function inspects the errorText and tries to @@ -172,11 +175,14 @@ export default function GuestInfo({ }) } }) + + if (!emailUpdateError?.statusCode) { + setUpdateOKMsg('update.email') + } // Reload guests to update status on sponsor frontpage // in case the email was invalid before update - reloadGuests() + reloadGuests() } - const onSubmit = handleSubmit(submit) const handleCancel = () => { setConfirmCancelDialogOpen(true) @@ -215,19 +221,15 @@ export default function GuestInfo({ } } - const { ref, onChange, ...inputProps } = register('email', { - validate: isValidEmail, - }) - useEffect(() => { - reset() // Forces defaultValue to be set to the new value, making the form not dirty + reset({ email: guest.email }) // Forces defaultValue to be set to the new value, making the form not dirty setValue('email', guest.email) }, [guest]) return ( <Page> <SponsorInfoButtons to="/sponsor" name={`${guest.first} ${guest.last}`} /> - <form onSubmit={onSubmit}> + <form onSubmit={handleSubmit(submit)}> <Box sx={{ marginBottom: '2rem' }}> <Typography sx={{ marginBottom: '1rem' }} variant="h2"> {t('guestInfo.contactInfo')} @@ -235,7 +237,25 @@ export default function GuestInfo({ <Typography sx={{ marginBottom: '1rem' }} variant="body1"> {t('guestInfo.contactInfoBody')} </Typography> - + {emailUpdateError !== undefined && ( + <Box sx={{ marginTop: '1rem', marginBottom: '1rem' }}> + <ServerErrorReport + errorHeading={emailUpdateError?.errorHeading} + statusCode={emailUpdateError?.statusCode} + statusText={emailUpdateError?.statusText} + errorBodyText={emailUpdateError?.errorBodyText} + /> + </Box> + )} + {updateOKMsg !== '' && ( + <Alert + severity="success" + sx={{ marginBottom: '1rem' }} + onClose={() => setUpdateOKMsg('')} + > + {t(updateOKMsg)} + </Alert> + )} <TableContainer> <Table sx={{ minWidth: 650 }} aria-label="simple table"> <TableHead> @@ -257,18 +277,25 @@ export default function GuestInfo({ <TableCell align="left">{t('input.email')}</TableCell> <TableCell align="left"> <Box> - <TextField - InputLabelProps={{ shrink: true }} - id="email" - label={t('input.email')} - error={!!errors.email} - helperText={errors?.email?.message} - defaultValue={guest.email} - inputRef={ref} - onChange={onChange} - {...inputProps} + <Controller + name="email" + control={control} + rules={{ + validate: (value) => isValidEmail(value), + }} + render={({ field: { onBlur, onChange, value } }) => ( + <TextField + InputLabelProps={{ shrink: true }} + id="email" + label={t('input.email')} + value={value} + onBlur={onBlur} + onChange={onChange} + error={!!errors.email} + helperText={errors?.email?.message} + /> + )} /> - {/* If the guest has not completed the registration process, he should have an invitation he has not responded to */} {!guest.registered && ( <Box @@ -330,16 +357,6 @@ export default function GuestInfo({ > {t('button.save')} </Button> - {emailUpdateError !== undefined && ( - <Box sx={{ marginTop: '1rem' }}> - <ServerErrorReport - errorHeading={emailUpdateError?.errorHeading} - statusCode={emailUpdateError?.statusCode} - statusText={emailUpdateError?.statusText} - errorBodyText={emailUpdateError?.errorBodyText} - /> - </Box> - )} </Box> </form> <Typography sx={{ marginBottom: '1rem' }} variant="h2">