import { DatePicker } from '@mui/lab' import { addDays } from 'date-fns/fp' import { Checkbox, Button, Select, FormControl, InputLabel, MenuItem, Stack, TextField, SelectChangeEvent, FormControlLabel, Box, Typography, } from '@mui/material' import Page from 'components/page' import { format } from 'date-fns' import useOus, { enSort, nbSort, OuData } from 'hooks/useOus' import useRoleTypes, { RoleTypeData } from 'hooks/useRoleTypes' import { Guest } from 'interfaces' import { useState } from 'react' import { Controller, useForm } from 'react-hook-form' import { useTranslation } from 'react-i18next' import { Link, useHistory, useParams } from 'react-router-dom' import SponsorInfoButtons from 'routes/components/sponsorInfoButtons' import { submitJsonOpts } from 'utils' import { useFeatureContext } from 'contexts/featureContext' type AddRoleFormData = { orgunit: number type: string end_date: Date start_date: Date contact_person_unit?: string comments?: string available_in_search?: boolean } type AddRolePayload = { orgunit: number person: string type: string end_date: string start_date?: string contact_person_unit?: string comments?: string available_in_search?: boolean } type GuestInfoParams = { pid: string } interface NewGuestRoleProps { guest: Guest reloadGuestInfo: () => void } const postRole = async (formData: AddRoleFormData, pid: string) => { const payload: AddRolePayload = { orgunit: formData.orgunit, person: pid, type: formData.type, end_date: format(formData.end_date as Date, 'yyyy-MM-dd'), } if (formData.start_date) { payload.start_date = format(formData.start_date as Date, 'yyyy-MM-dd') } if (formData.contact_person_unit) { payload.contact_person_unit = formData.contact_person_unit } if (formData.comments) { payload.comments = formData.comments } if (formData.available_in_search) { payload.available_in_search = formData.available_in_search } console.log('submitting', JSON.stringify(payload)) fetch('/api/ui/v1/role', submitJsonOpts('POST', payload)) .then((res) => { if (!res.ok) { console.log('result', res) return null } console.log('result', res) return res.text() }) .then((result) => { if (result !== null) { console.log('result', result) } }) .catch((error) => { console.log('error', error) }) } function NewGuestRole({ guest, reloadGuestInfo }: NewGuestRoleProps) { const { register, control, handleSubmit, formState: { errors }, setValue, getValues, } = useForm<AddRoleFormData>() const { displayContactAtUnit, displayComment } = useFeatureContext() const { pid } = useParams<GuestInfoParams>() const history = useHistory() const onSubmit = handleSubmit(async () => { await postRole(getValues(), pid) reloadGuestInfo() history.push(`/sponsor/guest/${pid}`) }) const ous = useOus() const roleTypes = useRoleTypes() const [ouChoice, setOuChoice] = useState<string>('') const [roleTypeChoice, setRoleTypeChoice] = useState<string>('') const [t, i18n] = useTranslation('common') const today = new Date() const [maxDate, setMaxDate] = useState(today) const todayPlusMaxDays = (roleTypeId?: number) => { if (roleTypeId) { const role = roleTypes === undefined ? undefined : roleTypes.find((rt) => rt.id === roleTypeId) if (role !== undefined) { return addDays(role.max_days)(today) } } return addDays(0)(today) } 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) } // Handling choices in menus const handleRoleTypeChange = (event: SelectChangeEvent) => { setValue('type', event.target.value) setRoleTypeChoice(event.target.value) setMaxDate(todayPlusMaxDays(Number(event.target.value))) } const handleOuChange = (event: SelectChangeEvent) => { if (event.target.value) { setOuChoice(event.target.value) setValue('orgunit', parseInt(event.target.value, 10)) } } // Functions for menu items const rolesToItem = (roleType: RoleTypeData) => ( <MenuItem key={roleType.id.toString()} value={roleType.id}> {i18n.language === 'en' ? roleType.name_en : roleType.name_nb} </MenuItem> ) // Show ou name in correct language if present. If not use other. const ouToItem = (ou: OuData) => { let name = '' if (i18n.language === 'en') { name = ou.en ? ou.en : ou.nb } else { name = ou.nb ? ou.nb : ou.en } return ( <MenuItem key={ou.id.toString()} value={ou.id}> {name} ({ou.id}) </MenuItem> ) } return ( <Page> <SponsorInfoButtons to={`/sponsor/guest/${pid}`} name={`${guest.first} ${guest.last}`} /> <Typography variant="h2">{t('guest.headerText')}</Typography> <Typography variant="body1">{t('guest.bodyText')}</Typography> <form onSubmit={onSubmit}> <Stack spacing={2}> <FormControl> <InputLabel id="roletype-select-label"> {t('input.roleType')} </InputLabel> <Select id="roletype-select" defaultValue="" value={roleTypeChoice} error={!!errors.type} label={t('input.roleType')} onChange={handleRoleTypeChange} > {(roleTypes === undefined ? [] : roleTypes) .sort(roleTypeSort()) .map((rt) => rolesToItem(rt))} </Select> </FormControl> <FormControl> <InputLabel id="ou-select-label-id">{t('common:ou')}</InputLabel> <Select labelId="ou-select-label" id="ou-select-label" defaultValue="" value={ouChoice.toString()} label={t('common:ou')} onChange={handleOuChange} > {ous !== undefined && ous.length > 0 && ous .sort(i18n.language === 'en' ? enSort : nbSort) .map((ou) => ouToItem(ou))} </Select> </FormControl> <Controller name="start_date" control={control} rules={{ required: true, validate: () => Number(getValues('start_date')) <= Number(getValues('end_date')), }} defaultValue={today} render={({ field }) => ( <DatePicker mask="____-__-__" label={t('input.roleStartDate')} disabled={!roleTypeChoice} value={field.value} maxDate={maxDate} inputFormat="yyyy-MM-dd" onChange={(value) => { field.onChange(value) }} renderInput={(params) => <TextField {...params} />} /> )} /> {errors.start_date && errors.start_date.type === 'required' && ( <Box sx={{ typography: 'caption', color: 'error.main' }}> {t('validation.startDateMustBeSet')} </Box> )} {errors.start_date && errors.start_date.type === 'validate' && ( <Box sx={{ typography: 'caption', color: 'error.main' }}> {t('validation.startDateMustBeBeforeEndDate')} </Box> )} <Controller name="end_date" control={control} rules={{ required: true, validate: () => Number(getValues('start_date')) <= Number(getValues('end_date')), }} defaultValue={today} render={({ field }) => ( <DatePicker mask="____-__-__" label={t('input.roleEndDate')} disabled={!roleTypeChoice} value={field.value} maxDate={maxDate} inputFormat="yyyy-MM-dd" onChange={(value) => { field.onChange(value) }} renderInput={(params) => <TextField {...params} />} /> )} /> {displayContactAtUnit && ( <TextField id="contact" label={t('input.contactPersonUnit')} multiline rows={5} {...register('contact_person_unit')} /> )} {displayComment && ( <TextField id="comments" label={t('input.comment')} multiline rows={5} {...register('comments')} /> )} <FormControlLabel control={ <Checkbox id="available_in_search" {...register('available_in_search')} /> } label={t('input.searchable')} /> <Button variant="contained" color="secondary" type="submit"> {t('button.save')} </Button> <Button component={Link} color="secondary" to={`/sponsor/guest/${pid}`} > {t('button.cancel')} </Button> </Stack> </form> </Page> ) } export default NewGuestRole