frontend/containers/Travel/HeaderEditing.tsx (view raw)
1import {useState, useReducer, useCallback, useEffect, useMemo} from 'react';
2import Typography from '@mui/material/Typography';
3import IconButton from '@mui/material/IconButton';
4import Icon from '@mui/material/Icon';
5import Button from '@mui/material/Button';
6import TextField from '@mui/material/TextField';
7import Slider from '@mui/material/Slider';
8import moment, {Moment} from 'moment';
9import {useTheme} from '@mui/material/styles';
10import {DatePicker} from '@mui/x-date-pickers/DatePicker';
11import {TimePicker} from '@mui/x-date-pickers/TimePicker';
12import {useTranslation} from 'react-i18next';
13import RemoveDialog from '../RemoveDialog';
14import useActions from './useActions';
15import Box from '@mui/material/Box';
16
17const HeaderEditing = ({travel, toggleEditing}) => {
18 const {t} = useTranslation();
19 const theme = useTheme();
20 const actions = useActions({travel});
21 const [removing, toggleRemoving] = useReducer(i => !i, false);
22 const dateMoment = useMemo(
23 () => (travel?.departure ? moment(travel.departure) : moment()),
24 [travel?.departure]
25 );
26
27 // States
28 const [name, setName] = useState(travel?.vehicleName ?? '');
29 const [seats, setSeats] = useState(travel?.seats ?? 4);
30 const [meeting, setMeeting] = useState(travel?.meeting ?? '');
31 const [date, setDate] = useState(dateMoment);
32 const [time, setTime] = useState(dateMoment);
33 const [phone, setPhone] = useState(travel?.phone_number ?? '');
34 const [details, setDetails] = useState(travel?.details ?? '');
35
36 // Click on ESQ closes the form
37 const escFunction = useCallback(
38 evt => {
39 if (evt.keyCode === 27) toggleEditing();
40 },
41 [toggleEditing]
42 );
43
44 useEffect(() => {
45 document.addEventListener('keydown', escFunction, false);
46 return () => {
47 document.removeEventListener('keydown', escFunction, false);
48 };
49 }, [escFunction]);
50
51 const onSave = async event => {
52 if (event.preventDefault) event.preventDefault();
53 const travelUpdate = {
54 meeting,
55 details,
56 seats,
57 phone_number: phone,
58 vehicleName: name,
59 departure: formatDate(date, time),
60 };
61 await actions.updateTravel(travelUpdate);
62 toggleEditing();
63 };
64
65 const onRemove = async () => {
66 await actions.removeTravel();
67 toggleEditing();
68 };
69
70 return (
71 <Box sx={{padding: theme.spacing(2)}}>
72 <form onSubmit={onSave}>
73 <IconButton
74 size="small"
75 color="primary"
76 type="submit"
77 sx={{
78 position: 'absolute',
79 top: 0,
80 right: 0,
81 margin: theme.spacing(1),
82 zIndex: theme.zIndex.speedDial,
83 }}
84 >
85 <Icon>done</Icon>
86 </IconButton>
87 <DatePicker
88 renderInput={props => (
89 <TextField
90 {...props}
91 fullWidth
92 helperText=" "
93 sx={{marginTop: theme.spacing(3)}}
94 />
95 )}
96 label={t('travel.creation.date')}
97 value={date}
98 onChange={setDate}
99 autoFocus
100 />
101 <TimePicker
102 label={t('travel.creation.time')}
103 renderInput={props => (
104 <TextField {...props} fullWidth helperText=" " />
105 )}
106 value={time}
107 onChange={setTime}
108 ampm={false}
109 minutesStep={5}
110 />
111 <TextField
112 label={t('travel.creation.name')}
113 fullWidth
114 helperText=" "
115 value={name}
116 onChange={e => setName(e.target.value)}
117 name="name"
118 id="EditTravelName"
119 />
120 <TextField
121 label={t('travel.creation.phone')}
122 fullWidth
123 helperText=" "
124 value={phone}
125 onChange={e => setPhone(e.target.value)}
126 name="phone"
127 id="EditTravelPhone"
128 />
129 <TextField
130 label={t('travel.creation.meeting')}
131 fullWidth
132 multiline
133 maxRows={4}
134 inputProps={{maxLength: 250}}
135 helperText={`${meeting.length}/250`}
136 value={meeting}
137 onChange={e => setMeeting(e.target.value)}
138 name="meeting"
139 id="EditTravelMeeting"
140 />
141 <TextField
142 label={t('travel.creation.notes')}
143 fullWidth
144 multiline
145 maxRows={4}
146 inputProps={{maxLength: 250}}
147 helperText={`${details.length}/250`}
148 value={details}
149 onChange={e => setDetails(e.target.value)}
150 name="details"
151 id="EditTravelDetails"
152 />
153 <Box sx={{marginTop: theme.spacing(2)}}>
154 <Typography variant="caption">
155 {t('travel.creation.seats')}
156 </Typography>
157 <Slider
158 value={seats}
159 onChange={(e, value) => setSeats(value)}
160 step={1}
161 marks={[1, 2, 3, 4, 5, 6, 7, 8].map(value => ({
162 value,
163 label: value,
164 }))}
165 min={1}
166 max={8}
167 valueLabelDisplay="auto"
168 id="EditTravelSeats"
169 />
170 </Box>
171 </form>
172 <Box
173 sx={{
174 display: 'flex',
175 flexDirection: 'column',
176 justifyContent: 'center',
177 margin: theme.spacing(2, 0),
178 '& > *:first-child': {
179 marginBottom: theme.spacing(2),
180 },
181 }}
182 >
183 <Button
184 variant="outlined"
185 color="primary"
186 onClick={onSave}
187 id="TravelSave"
188 >
189 {t('generic.save')}
190 </Button>
191 <Button
192 variant="outlined"
193 color="primary"
194 onClick={toggleRemoving}
195 id="TravelRemove"
196 >
197 {t('generic.remove')}
198 </Button>
199 </Box>
200 <RemoveDialog
201 text={t('travel.actions.remove_alert')}
202 open={removing}
203 onClose={toggleRemoving}
204 onRemove={onRemove}
205 />
206 </Box>
207 );
208};
209
210const formatDate = (date: Moment, time: Moment) => {
211 return moment(
212 `${moment(date).format('YYYY-MM-DD')} ${moment(time).format('HH:mm')}`,
213 'YYYY-MM-DD HH:mm'
214 ).toISOString();
215};
216
217export default HeaderEditing;