Skip to content
Snippets Groups Projects
Commit c567d7b8 authored by Sivert Kronen Hatteberg's avatar Sivert Kronen Hatteberg
Browse files

Merge branch 'GREG-274-guest-email-form' into 'master'

Fix problems with submit button not being disabled and some UX improvements

See merge request !339
parents 0ffe7c1a 65a0b72c
No related branches found
No related tags found
1 merge request!339Fix problems with submit button not being disabled and some UX improvements
Pipeline #148905 passed
...@@ -214,5 +214,8 @@ ...@@ -214,5 +214,8 @@
"duplicate_private_national_id_number": "There is already a guest with the national ID number given", "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" "duplicate_private_passport_number": "There is already a guest with the passport number given"
} }
},
"update": {
"email": "E-mail updated successful"
} }
} }
...@@ -214,5 +214,8 @@ ...@@ -214,5 +214,8 @@
"duplicate_private_national_id_number": "Det eksisterer allerede en gjest med gitt fødselsnummer/D-nummer", "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" "duplicate_private_passport_number": "Det eksisterer allerede en gjest med gitt passnummer"
} }
},
"update": {
"email": "E-postadressen ble endret"
} }
} }
...@@ -214,5 +214,8 @@ ...@@ -214,5 +214,8 @@
"duplicate_private_national_id_number": "Det eksisterer allereie ein gjest med dette fødselsnummeret/D-nummeret", "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" "duplicate_private_passport_number": "Det eksisterer allereie ein gjest med dette passnummeret"
} }
},
"update": {
"email": "E-postadressa ble endra"
} }
} }
import { Link, useParams, useNavigate } from 'react-router-dom' import { useEffect, useState } from 'react'
import Page from 'components/page'
import RoleLine from 'components/roleLine'
import { useTranslation } from 'react-i18next'
import { import {
Alert,
Button, Button,
Table,
TableBody,
Box, Box,
Dialog, Dialog,
DialogTitle, DialogTitle,
DialogContent, DialogContent,
DialogActions, DialogActions,
Table,
TableBody,
TextField, TextField,
Typography, Typography,
} from '@mui/material' } 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 { import {
TableCell,
TableContainer, TableContainer,
TableHead, TableHead,
TableHeadCell, TableHeadCell,
TableRow, TableRow,
TableCell,
} from 'components/table' } from 'components/table'
import { Guest } from 'interfaces' import { Guest } from 'interfaces'
import SponsorInfoButtons from 'routes/components/sponsorInfoButtons' 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 { isValidEmail, submitJsonOpts } from 'utils'
import ServerErrorReport, {
ServerErrorReportData,
} from '../../../../components/errorReport'
type GuestInfoParams = { type GuestInfoParams = {
pid: string pid: string
...@@ -99,16 +100,18 @@ export default function GuestInfo({ ...@@ -99,16 +100,18 @@ export default function GuestInfo({
const [confirmCancelDialogOpen, setConfirmCancelDialogOpen] = useState(false) const [confirmCancelDialogOpen, setConfirmCancelDialogOpen] = useState(false)
const [emailUpdateError, setEmailUpdateError] = const [emailUpdateError, setEmailUpdateError] =
useState<ServerErrorReportData>() 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 // Using useForm even though only the e-mail is allow to change at present, since useForm makes setup and validation easier
const { const {
control,
handleSubmit, handleSubmit,
setValue, setValue,
register,
reset, reset,
formState: { errors, isValid, isDirty }, formState: { errors, isValid, isDirty },
} = useForm<Email>({ } = useForm<Email>({
mode: 'onChange', mode: 'onTouched',
defaultValues: { email: guest.email ?? '' },
}) })
// This function inspects the errorText and tries to // This function inspects the errorText and tries to
...@@ -172,11 +175,14 @@ export default function GuestInfo({ ...@@ -172,11 +175,14 @@ export default function GuestInfo({
}) })
} }
}) })
if (!emailUpdateError?.statusCode) {
setUpdateOKMsg('update.email')
}
// Reload guests to update status on sponsor frontpage // Reload guests to update status on sponsor frontpage
// in case the email was invalid before update // in case the email was invalid before update
reloadGuests() reloadGuests()
} }
const onSubmit = handleSubmit(submit)
const handleCancel = () => { const handleCancel = () => {
setConfirmCancelDialogOpen(true) setConfirmCancelDialogOpen(true)
...@@ -215,19 +221,15 @@ export default function GuestInfo({ ...@@ -215,19 +221,15 @@ export default function GuestInfo({
} }
} }
const { ref, onChange, ...inputProps } = register('email', {
validate: isValidEmail,
})
useEffect(() => { 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) setValue('email', guest.email)
}, [guest]) }, [guest])
return ( return (
<Page> <Page>
<SponsorInfoButtons to="/sponsor" name={`${guest.first} ${guest.last}`} /> <SponsorInfoButtons to="/sponsor" name={`${guest.first} ${guest.last}`} />
<form onSubmit={onSubmit}> <form onSubmit={handleSubmit(submit)}>
<Box sx={{ marginBottom: '2rem' }}> <Box sx={{ marginBottom: '2rem' }}>
<Typography sx={{ marginBottom: '1rem' }} variant="h2"> <Typography sx={{ marginBottom: '1rem' }} variant="h2">
{t('guestInfo.contactInfo')} {t('guestInfo.contactInfo')}
...@@ -235,7 +237,25 @@ export default function GuestInfo({ ...@@ -235,7 +237,25 @@ export default function GuestInfo({
<Typography sx={{ marginBottom: '1rem' }} variant="body1"> <Typography sx={{ marginBottom: '1rem' }} variant="body1">
{t('guestInfo.contactInfoBody')} {t('guestInfo.contactInfoBody')}
</Typography> </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> <TableContainer>
<Table sx={{ minWidth: 650 }} aria-label="simple table"> <Table sx={{ minWidth: 650 }} aria-label="simple table">
<TableHead> <TableHead>
...@@ -257,18 +277,25 @@ export default function GuestInfo({ ...@@ -257,18 +277,25 @@ export default function GuestInfo({
<TableCell align="left">{t('input.email')}</TableCell> <TableCell align="left">{t('input.email')}</TableCell>
<TableCell align="left"> <TableCell align="left">
<Box> <Box>
<TextField <Controller
InputLabelProps={{ shrink: true }} name="email"
id="email" control={control}
label={t('input.email')} rules={{
error={!!errors.email} validate: (value) => isValidEmail(value),
helperText={errors?.email?.message} }}
defaultValue={guest.email} render={({ field: { onBlur, onChange, value } }) => (
inputRef={ref} <TextField
onChange={onChange} InputLabelProps={{ shrink: true }}
{...inputProps} 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 */} {/* If the guest has not completed the registration process, he should have an invitation he has not responded to */}
{!guest.registered && ( {!guest.registered && (
<Box <Box
...@@ -330,16 +357,6 @@ export default function GuestInfo({ ...@@ -330,16 +357,6 @@ export default function GuestInfo({
> >
{t('button.save')} {t('button.save')}
</Button> </Button>
{emailUpdateError !== undefined && (
<Box sx={{ marginTop: '1rem' }}>
<ServerErrorReport
errorHeading={emailUpdateError?.errorHeading}
statusCode={emailUpdateError?.statusCode}
statusText={emailUpdateError?.statusText}
errorBodyText={emailUpdateError?.errorBodyText}
/>
</Box>
)}
</Box> </Box>
</form> </form>
<Typography sx={{ marginBottom: '1rem' }} variant="h2"> <Typography sx={{ marginBottom: '1rem' }} variant="h2">
......
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