-
Marte Fossum authoredMarte Fossum authored
import { useEffect, useState } from 'react'
import format from 'date-fns/format'
import { addDays } from 'date-fns/fp'
import {
Alert,
Button,
Table,
TableBody,
TextField,
Typography,
} from '@mui/material'
import TableHeadMui from '@mui/material/TableHead'
import { styled } from '@mui/system'
import TableContainerMui from '@mui/material/TableContainer'
import TableRowMui from '@mui/material/TableRow'
import TableCellMui from '@mui/material/TableCell'
import Page from 'components/page'
import { Guest, Role } from 'interfaces'
import { useTranslation } from 'react-i18next'
import { useNavigate, useParams } from 'react-router-dom'
import SponsorInfoButtons from 'routes/components/sponsorInfoButtons'
import { DatePicker } from '@mui/lab'
import { Controller, SubmitHandler, useForm } from 'react-hook-form'
import { getRoleName, getRoleOuName, submitJsonOpts } from 'utils'
import { useFeatureContext } from 'contexts/featureContext'
import ConfirmDialog from '../../../../components/confirmDialog'
import useOus from '../../../../hooks/useOus'
interface GuestRoleInfoProps {
guest: Guest
reloadGuest: () => void
reloadGuests: () => void
}
const endPeriodPost = (
id: string,
data: { end_date: Date },
reloadGuests: () => void
) => {
const payload = {
end_date: format(data.end_date as Date, 'yyyy-MM-dd'),
}
console.log('submitting', JSON.stringify(payload))
fetch(`/api/ui/v1/role/${id}`, submitJsonOpts('PATCH', payload))
.then((res) => {
if (!res.ok) {
return null
}
return res.text()
})
.then((result) => {
if (result !== null) {
console.log('result', result)
reloadGuests()
}
})
.catch((error) => {
console.log('error', error)
})
}
type GuestRoleInfoParams = {
pid: string
id: string
}
type RoleFormData = {
start_date: Date
end_date: Date
comments: string
contact_person_unit: string
}
const TableHeadCell = styled(TableCellMui)({
fontWeight: 'bold',
border: 'none',
})
const TableHead = styled(TableHeadMui)(({ theme }) => ({
borderTop: '0',
borderLeft: '0',
borderRight: '0',
borderBottom: '3px solid',
borderColor: theme.palette.secondary.main,
borderRadius: '0',
}))
const TableRow = styled(TableRowMui)({
borderTop: '0',
borderLeft: '0',
borderRight: '0',
borderBottom: '0px solid',
borderColor: 'black',
borderRadius: '0',
})
const TableCell = styled(TableCellMui)({
borderBottom: 'none',
})
const TableContainer = styled(TableContainerMui)({
marginBottom: '1rem',
borderRadius: '1%',
borderStyle: 'solid',
borderColor: 'black',
borderWidth: '0.125rem',
boxShadow: 'none',
paddingLeft: '3.125rem',
paddingRight: '3.125rem',
paddingTop: '1.5625rem',
paddingBottom: '1.5625rem',
})
export default function GuestRoleInfo({
guest,
reloadGuest,
reloadGuests,
}: GuestRoleInfoProps) {
const { pid, id } = useParams<GuestRoleInfoParams>()
const { ous } = useOus()
const [t, i18n] = useTranslation('common')
const { displayContactAtUnit, displayComment } = useFeatureContext()
const navigate = useNavigate()
const [showRoleChange, setShowRoleChange] = useState<Boolean>(false)
const [showRoleChangeFailed, setShowRoleChangeFailed] =
useState<Boolean>(false)
const [badEndDate, setBadEndDate] = useState<Boolean>(false)
const [role, setRole] = useState<Role>({
id: '',
name_nb: '',
name_en: '',
ou_nb: '',
ou_en: '',
start_date: new Date(),
end_date: new Date(),
max_days: 365,
contact_person_unit: null,
comments: null,
sponsor_name: '',
ou_id: -1,
})
// Prepare min and max date values
const today = new Date()
const todayPlusMaxDays = addDays(role.max_days)(today)
// Make a function for use with onClick of the end role button
const endPeriod = (role_id: string) => () => {
// Set the role to have ended yesterday so that the change is immediate.
// If the role was set to end today, the change will not be active
// until the next date since the end date is inclusive
const newEndDate = addDays(-1)(today)
if (role.start_date !== undefined && role.start_date > newEndDate) {
setBadEndDate(true)
setShowRoleChange(false)
setShowRoleChangeFailed(false)
} else {
role.end_date = newEndDate
endPeriodPost(role_id, { end_date: newEndDate }, reloadGuests)
// Go back to guest overview page
navigate(`/sponsor/guest/${guest.pid}`, {
state: {
cancelledRoleName:
i18n.language === 'en' ? role.name_en : role.name_nb,
},
})
}
}
const {
register,
control,
handleSubmit,
setValue,
reset,
formState: { isDirty, isValid },
} = useForm<RoleFormData>({ mode: 'onTouched' })
// A sponsor can only edit roles belonging to departments where he is a sponsor.
// Look at the unit where the role is registered and see if that unit is present
// in the list of units where a sponsor can assign roles to determine if
// he can edit this role
const allowEdit =
ous === undefined ? false : ous.some((value) => value.id === role.ou_id)
// Submit function for the save button
const submit: SubmitHandler<RoleFormData> = (data) => {
const payload: {
start_date?: string
end_date: string
contact_person_unit?: string
comments?: string
} = {
end_date: format(data.end_date as Date, 'yyyy-MM-dd'),
start_date: format(data.start_date as Date, 'yyyy-MM-dd'),
contact_person_unit: data.contact_person_unit,
comments: data.comments,
}
console.log('submitting', JSON.stringify(payload))
fetch(`/api/ui/v1/role/${id}`, submitJsonOpts('PATCH', payload))
.then((res) => {
if (!res.ok) {
return null
}
return res.text()
})
.then((result) => {
if (result !== null) {
setShowRoleChange(true)
setBadEndDate(false)
setShowRoleChangeFailed(false)
console.log('result', result)
} else {
setShowRoleChangeFailed(true)
setShowRoleChange(false)
setBadEndDate(false)
}
// Reload the guest so that the information on the overview page is updated
reloadGuests()
reloadGuest()
// A submit does not clear the dirty state, so resetting values in the form
// to the values just submitted to clear the dirty-flag
reset(data)
})
.catch((error) => {
setShowRoleChangeFailed(true)
console.log('error', error)
})
}
const onSubmit = handleSubmit(submit)
const [showEndRoleConfirmationDialog, setShowEndRoleConfirmationDialog] =
useState(false)
// Find the role info relevant for this page
const getRoleInfo = () => {
const roleInfo = guest.roles.filter((ro) => ro.id.toString() === id)[0]
if (roleInfo) {
setRole(roleInfo)
// Set values of date fields to current dates if role exists
setValue('end_date', roleInfo.end_date)
// The start date can be undefined for existing roles that have been imported
if (roleInfo.start_date !== undefined) {
setValue('start_date', roleInfo.start_date)
}
}
}
useEffect(() => {
getRoleInfo()
}, [guest])
return (
<Page>
<SponsorInfoButtons
to={`/sponsor/guest/${pid}`}
name={`${guest.first} ${guest.last}`}
/>
{allowEdit && (
<>
<Typography sx={{ marginBottom: '1rem' }} variant="h2">
{t('sponsor.roleInfoHead')}
</Typography>
<Typography sx={{ marginBottom: '1rem' }} variant="body1">
{t('sponsor.roleInfoText')}
</Typography>
</>
)}
{showRoleChange && (
<Alert severity="success" sx={{ marginBottom: '1rem' }}>
{t('guestInfo.roleChanged')}
</Alert>
)}
{showRoleChangeFailed && (
<Alert severity="error" sx={{ marginBottom: '1rem' }}>
{t('error.changeRoleFailed')}
</Alert>
)}
{badEndDate && (
<Alert
sx={{ fontSize: '1rem', marginTop: '1rem', marginBottom: '1rem' }}
severity="error"
>
{t('error.badEndDate')}
</Alert>
)}
<form onSubmit={onSubmit}>
<TableContainer>
<Table sx={{ minWidth: 650 }} aria-label="simple table">
<TableHead sx={{ backgroundColor: 'none' }}>
<TableRow>
<TableHeadCell align="left">
{t('sponsor.details')}
</TableHeadCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell align="left" sx={{ fontWeight: 'bold' }}>
{t('common:role')}
</TableCell>
<TableCell>{getRoleName(role)}</TableCell>
</TableRow>
<TableRow>
<TableCell align="left" sx={{ fontWeight: 'bold' }}>
{t('common:period')}
</TableCell>
<TableCell align="left">
<Controller
name="start_date"
control={control}
defaultValue={role.start_date}
render={({ field: { onChange, value } }) => (
<DatePicker
mask="____-__-__"
label={t('input.roleStartDate')}
value={value}
maxDate={todayPlusMaxDays}
inputFormat="yyyy-MM-dd"
onChange={onChange}
renderInput={(params) => <TextField {...params} />}
disabled={!allowEdit}
/>
)}
/>
</TableCell>
<TableCell align="left">
<Controller
name="end_date"
control={control}
defaultValue={role.end_date}
render={({ field: { onChange, value } }) => (
<DatePicker
mask="____-__-__"
label={t('input.roleEndDate')}
maxDate={todayPlusMaxDays}
value={value}
inputFormat="yyyy-MM-dd"
onChange={onChange}
renderInput={(params) => <TextField {...params} />}
disabled={!allowEdit}
/>
)}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell align="left" sx={{ fontWeight: 'bold' }}>
{t('common:ou')}
</TableCell>
<TableCell align="left">{getRoleOuName(role)}</TableCell>
<TableCell align="left" />
</TableRow>
<TableRow>
<TableCell align="left" sx={{ fontWeight: 'bold' }}>
{t('common:host')}
</TableCell>
<TableCell align="left">{role.sponsor_name}</TableCell>
<TableCell align="left" />
</TableRow>
{allowEdit && displayContactAtUnit && (
<TableRow>
<TableCell align="left" sx={{ fontWeight: 'bold' }}>
{t('sponsor.contactPerson')}
</TableCell>
<TableCell>
<TextField
id="contact_person"
defaultValue={role.contact_person_unit}
label={`${t('input.contactPersonUnit')}`}
{...register(`contact_person_unit`)}
/>
</TableCell>
</TableRow>
)}
{allowEdit && displayComment && (
<TableRow>
<TableCell align="left" sx={{ fontWeight: 'bold' }}>
{t('input.comment')}
</TableCell>
<TableCell>
<TextField
id="comment"
label={`${t('input.comment')}`}
multiline
rows={2}
defaultValue={role.comments}
{...register(`comments`)}
/>
</TableCell>
</TableRow>
)}
{!allowEdit && displayContactAtUnit && (
<TableRow>
<TableCell align="left" sx={{ fontWeight: 'bold' }}>
{t('sponsor.contactPerson')}
</TableCell>
<TableCell align="left">{role.contact_person_unit}</TableCell>
<TableCell align="left" />
</TableRow>
)}
{!allowEdit && displayComment && (
<TableRow>
<TableCell align="left" sx={{ fontWeight: 'bold' }}>
{t('input.comment')}
</TableCell>
<TableCell align="left">{role.comments}</TableCell>
<TableCell align="left" />
</TableRow>
)}
</TableBody>
</Table>
</TableContainer>
<Button
variant="contained"
color="success"
type="submit"
disabled={!isDirty || !isValid || !allowEdit}
>
{t('button.save')}
</Button>{' '}
{/* If the role has already expired the role end button is disabled */}
<Button
aria-label={t('sponsor.endNow')}
color="primary"
disabled={role.end_date < today || !allowEdit}
onClick={() => setShowEndRoleConfirmationDialog(true)}
>
{t('sponsor.endNow')}
</Button>
{typeof id === 'string' ? (
<ConfirmDialog
title={t('endRoleDialog.title')}
open={showEndRoleConfirmationDialog}
setOpen={setShowEndRoleConfirmationDialog}
onConfirm={endPeriod(id)}
>
{t('endRoleDialog.text')}
</ConfirmDialog>
) : (
<></>
)}
</form>
</Page>
)
}