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 type="submit" className={classes.editBtn}>
100 <Icon>done</Icon>
101 </IconButton>
102 <DateTimePicker
103 label={t('event.creation.date')}
104 value={date}
105 onChange={setDate}
106 className={classes.textField}
107 fullWidth
108 format="LLLL"
109 disablePast
110 id="EditCarDateTime"
111 name="date"
112 />
113 <TextField
114 className={classes.textField}
115 label={t('car.creation.name')}
116 fullWidth
117 autoFocus
118 margin="dense"
119 value={name}
120 onChange={e => setName(e.target.value)}
121 id="EditCarName"
122 name="name"
123 />
124 <TextField
125 className={classes.textField}
126 label={t('car.creation.phone')}
127 fullWidth
128 autoFocus
129 margin="dense"
130 value={phone}
131 onChange={e => setPhone(e.target.value)}
132 id="EditCarPhone"
133 name="phone"
134 />
135 <TextField
136 className={classes.textField}
137 label={t('car.creation.meeting')}
138 fullWidth
139 margin="dense"
140 multiline
141 rows={2}
142 value={meeting}
143 onChange={e => setMeeting(e.target.value)}
144 id="EditCarMeeting"
145 name="meeting"
146 />
147 <TextField
148 className={classes.textField}
149 label={t('car.creation.notes')}
150 fullWidth
151 margin="dense"
152 multiline
153 rows={2}
154 value={details}
155 onChange={e => setDetails(e.target.value)}
156 id="EditCarDetails"
157 name="details"
158 />
159 <div className={classes.slider}>
160 <Typography variant="caption">{t('car.creation.seats')}</Typography>
161 <Slider
162 value={seats}
163 onChange={(e, value) => setSeats(value)}
164 step={1}
165 marks={[1, 2, 3, 4, 5, 6, 7, 8].map(value => ({
166 value,
167 label: value,
168 }))}
169 min={1}
170 max={8}
171 valueLabelDisplay="auto"
172 id="EditCarSeats"
173 />
174 </div>
175 </form>
176 <div className={classes.actions}>
177 <Button
178 color="secondary"
179 variant="outlined"
180 onClick={toggleRemoving}
181 id="CarRemove"
182 >
183 {t('car.actions.remove')}
184 </Button>
185 </div>
186 <RemoveDialog
187 text={t('car.actions.remove_alert')}
188 open={removing}
189 onClose={toggleRemoving}
190 onRemove={onRemove}
191 />
192 </div>
193 );
194};
195
196const useStyles = makeStyles(theme => ({
197 header: {padding: theme.spacing(2)},
198 editBtn: {
199 position: 'absolute',
200 top: 0,
201 right: 0,
202 zIndex: theme.zIndex.speedDial,
203 },
204 section: {
205 marginTop: theme.spacing(2),
206 },
207 slider: {
208 marginTop: theme.spacing(2),
209 },
210 actions: {
211 display: 'flex',
212 justifyContent: 'center',
213 margin: theme.spacing(2, 0),
214 },
215}));
216
217export default HeaderEditing;