app/src/containers/Car/HeaderEditing.js (view raw)
1import React, {useState, useReducer, useCallback, useEffect} from 'react';
2import Typography from '@material-ui/core/Typography';
3import IconButton from '@material-ui/core/IconButton';
4import Icon from '@material-ui/core/Icon';
5import Button from '@material-ui/core/Button';
6import moment from 'moment';
7import {makeStyles} from '@material-ui/core/styles';
8import {DateTimePicker} from '@material-ui/pickers';
9import {useTranslation} from 'react-i18next';
10import TextField from '@material-ui/core/TextField';
11import Slider from '@material-ui/core/Slider';
12import {useStrapi} from 'strapi-react-context';
13import {useToast} from '../../contexts/Toast';
14import {useEvent} from '../../contexts/Event';
15import RemoveDialog from '../RemoveDialog';
16
17const HeaderEditing = ({car, toggleEditing}) => {
18 const classes = useStyles();
19 const {t} = useTranslation();
20 const strapi = useStrapi();
21 const {event} = useEvent();
22 const {addToast} = useToast();
23 const [removing, toggleRemoving] = useReducer(i => !i, false);
24
25 // States
26 const [name, setName] = useState(car?.name ?? '');
27 const [seats, setSeats] = useState(car?.seats ?? 4);
28 const [meeting, setMeeting] = useState(car?.meeting ?? '');
29 const [date, setDate] = useState(
30 car?.departure ? moment(car.departure) : moment()
31 );
32 const [phone, setPhone] = useState(car ? car['phone_number'] : '');
33 const [details, setDetails] = useState(car?.details ?? '');
34
35 // Click on ESQ should close the form
36 const escFunction = useCallback(
37 evt => {
38 if (evt.keyCode === 27) toggleEditing();
39 },
40 [toggleEditing]
41 );
42
43 useEffect(() => {
44 document.addEventListener('keydown', escFunction, false);
45 return () => {
46 document.removeEventListener('keydown', escFunction, false);
47 };
48 }, [escFunction]);
49
50 const onSave = async evt => {
51 if (evt.preventDefault) evt.preventDefault();
52 try {
53 // If new seats count is under current passengers count, put excedent in event waiting list
54 if (!!car.passengers && car.passengers.length > seats) {
55 const lostPassengers = car.passengers.slice(seats);
56 if (lostPassengers.length > 0)
57 await strapi.services.events.update(event.id, {
58 waiting_list: [...(event.waiting_list ?? []), ...lostPassengers],
59 });
60 }
61 // Update car
62 await strapi.services.cars.update(car.id, {
63 name,
64 seats,
65 meeting,
66 departure: date.toISOString(),
67 phone_number: phone,
68 details,
69 passengers: car.passengers ? car.passengers.slice(0, seats) : [],
70 });
71 toggleEditing();
72 } catch (error) {
73 console.error(error);
74 addToast('car.errors.cant_update');
75 }
76 return false;
77 };
78
79 const onRemove = async () => {
80 try {
81 // Put passengers in event waiting list (if any)
82 if (Array.isArray(car?.passengers) && car.passengers.length > 0)
83 await strapi.services.events.update(event.id, {
84 waiting_list: [...(event.waiting_list ?? []), ...car.passengers],
85 });
86 // Remove car
87 await strapi.services.cars.remove(car.id);
88 addToast(t('car.actions.removed'));
89 toggleEditing();
90 } catch (error) {
91 console.error(error);
92 addToast('car.errors.cant_remove');
93 }
94 };
95
96 return (
97 <div className={classes.header}>
98 <form onSubmit={onSave}>
99 <IconButton
100 size="small"
101 color="primary"
102 type="submit"
103 className={classes.editBtn}
104 >
105 <Icon>done</Icon>
106 </IconButton>
107 <DateTimePicker
108 label={t('car.creation.date')}
109 value={date}
110 onChange={setDate}
111 className={classes.textField}
112 fullWidth
113 format="LLLL"
114 disablePast
115 minDateMessage={t('car.creation.date_min')}
116 id="EditCarDateTime"
117 name="date"
118 cancelLabel={t('generic.cancel')}
119 />
120 <TextField
121 className={classes.textField}
122 label={t('car.creation.name')}
123 fullWidth
124 autoFocus
125 margin="dense"
126 value={name}
127 onChange={e => setName(e.target.value)}
128 id="EditCarName"
129 name="name"
130 />
131 <TextField
132 className={classes.textField}
133 label={t('car.creation.phone')}
134 fullWidth
135 autoFocus
136 margin="dense"
137 value={phone}
138 onChange={e => setPhone(e.target.value)}
139 id="EditCarPhone"
140 name="phone"
141 />
142 <TextField
143 className={classes.textField}
144 label={t('car.creation.meeting')}
145 fullWidth
146 margin="dense"
147 multiline
148 rows={2}
149 value={meeting}
150 onChange={e => setMeeting(e.target.value)}
151 id="EditCarMeeting"
152 name="meeting"
153 />
154 <TextField
155 className={classes.textField}
156 label={t('car.creation.notes')}
157 fullWidth
158 margin="dense"
159 inputProps={{maxLength: 250}}
160 helperText={`${details.length}/250`}
161 multiline
162 rows={2}
163 value={details}
164 onChange={e => setDetails(e.target.value)}
165 id="EditCarDetails"
166 name="details"
167 />
168 <div className={classes.slider}>
169 <Typography variant="caption">{t('car.creation.seats')}</Typography>
170 <Slider
171 value={seats}
172 onChange={(e, value) => setSeats(value)}
173 step={1}
174 marks={[1, 2, 3, 4, 5, 6, 7, 8].map(value => ({
175 value,
176 label: value,
177 }))}
178 min={1}
179 max={8}
180 valueLabelDisplay="auto"
181 id="EditCarSeats"
182 />
183 </div>
184 </form>
185 <div className={classes.actions}>
186 <Button
187 variant="outlined"
188 color="primary"
189 onClick={onSave}
190 id="CarSave"
191 >
192 {t('generic.save')}
193 </Button>
194 <Button
195 variant="outlined"
196 color="primary"
197 onClick={toggleRemoving}
198 id="CarRemove"
199 >
200 {t('generic.remove')}
201 </Button>
202 </div>
203 <RemoveDialog
204 text={t('car.actions.remove_alert')}
205 open={removing}
206 onClose={toggleRemoving}
207 onRemove={onRemove}
208 />
209 </div>
210 );
211};
212
213const useStyles = makeStyles(theme => ({
214 header: {padding: theme.spacing(2)},
215 editBtn: {
216 position: 'absolute',
217 top: 0,
218 right: 0,
219 margin: theme.spacing(1),
220 zIndex: theme.zIndex.speedDial,
221 },
222 section: {
223 marginTop: theme.spacing(2),
224 },
225 slider: {
226 marginTop: theme.spacing(2),
227 },
228 actions: {
229 display: 'flex',
230 flexDirection: 'column',
231 justifyContent: 'center',
232 margin: theme.spacing(2, 0),
233 '& > *:first-child': {
234 marginBottom: theme.spacing(2),
235 },
236 },
237}));
238
239export default HeaderEditing;