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