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