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 PlaceInput from '../PlaceInput';
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 <PlaceInput
119 label={t('travel.creation.meeting')}
120 textFieldProps={{sx: {pb: 2}}}
121 place={meeting}
122 latitude={meeting_latitude}
123 longitude={meeting_longitude}
124 onSelect={({place, latitude, longitude}) => {
125 setMeeting(place);
126 setMeetingLatitude(latitude);
127 setMeetingLongitude(longitude);
128 }}
129 />
130 <TextField
131 label={t('travel.creation.notes')}
132 fullWidth
133 sx={{pb: 2}}
134 multiline
135 maxRows={4}
136 inputProps={{maxLength: 250}}
137 helperText={`${details.length}/250`}
138 value={details}
139 onChange={e => setDetails(e.target.value)}
140 name="details"
141 id="EditTravelDetails"
142 />
143 <Box sx={{marginTop: theme.spacing(2)}}>
144 <Typography variant="caption">
145 {t('travel.creation.seats')}
146 </Typography>
147 <Slider
148 value={seats}
149 onChange={(e, value) => setSeats(value)}
150 step={1}
151 marks={[1, 2, 3, 4, 5, 6, 7, 8].map(value => ({
152 value,
153 label: value,
154 }))}
155 min={1}
156 max={8}
157 valueLabelDisplay="auto"
158 id="EditTravelSeats"
159 />
160 </Box>
161 </form>
162 <Box
163 sx={{
164 display: 'flex',
165 flexDirection: 'column',
166 justifyContent: 'center',
167 margin: theme.spacing(2, 0),
168 '& > *:first-child': {
169 marginBottom: theme.spacing(2),
170 },
171 }}
172 >
173 <Button
174 variant="contained"
175 color="primary"
176 onClick={onSave}
177 id="TravelSave"
178 >
179 {t('generic.save')}
180 </Button>
181 <Button
182 variant="outlined"
183 color="primary"
184 onClick={toggleRemoving}
185 id="TravelRemove"
186 >
187 {t('generic.remove')}
188 </Button>
189 </Box>
190 <RemoveDialog
191 text={t('travel.actions.remove_alert')}
192 open={removing}
193 onClose={toggleRemoving}
194 onRemove={onRemove}
195 />
196 </Box>
197 );
198};
199
200const formatDate = (date: Moment, time: Moment) => {
201 return moment(
202 `${moment(date).format('YYYY-MM-DD')} ${moment(time).format('HH:mm')}`,
203 'YYYY-MM-DD HH:mm'
204 ).toISOString();
205};
206
207export default HeaderEditing;