frontend/containers/Travel/HeaderEditing.tsx (view raw)
1import {useState, useReducer, useCallback, useEffect, useMemo} from 'react';
2import {makeStyles} from '@material-ui/core/styles';
3import Typography from '@material-ui/core/Typography';
4import IconButton from '@material-ui/core/IconButton';
5import Icon from '@material-ui/core/Icon';
6import Button from '@material-ui/core/Button';
7import TextField from '@material-ui/core/TextField';
8import Slider from '@material-ui/core/Slider';
9import {DatePicker, TimePicker} from '@material-ui/pickers';
10import moment from 'moment';
11import {useTranslation} from 'react-i18next';
12import RemoveDialog from '../RemoveDialog';
13import useActions from './useActions';
14
15const HeaderEditing = ({travel, toggleEditing}) => {
16 const classes = useStyles();
17 const {t} = useTranslation();
18 const actions = useActions({travel});
19 const [removing, toggleRemoving] = useReducer(i => !i, false);
20 const dateMoment = useMemo(
21 () => (travel?.departure ? moment(travel.departure) : moment()),
22 [travel?.departure]
23 );
24
25 // States
26 const [name, setName] = useState(travel?.vehicle?.name ?? '');
27 const [seats, setSeats] = useState(travel?.vehicle?.seats ?? 4);
28 const [meeting, setMeeting] = useState(travel?.meeting ?? '');
29 const [date, setDate] = useState(dateMoment);
30 const [time, setTime] = useState(dateMoment);
31 const [phone, setPhone] = useState(travel?.vehicle?.phone_number ?? '');
32 const [details, setDetails] = useState(travel?.details ?? '');
33
34 // Click on ESQ closes the form
35 const escFunction = useCallback(
36 evt => {
37 if (evt.keyCode === 27) toggleEditing();
38 },
39 [toggleEditing]
40 );
41
42 useEffect(() => {
43 document.addEventListener('keydown', escFunction, false);
44 return () => {
45 document.removeEventListener('keydown', escFunction, false);
46 };
47 }, [escFunction]);
48
49 const onSave = async event => {
50 if (event.preventDefault) event.preventDefault();
51 const update = {
52 vehicle: {
53 name,
54 seats,
55 phone_number: phone,
56 },
57 travel: {meeting, date, time, details},
58 };
59 await actions.updateTravel(update);
60 toggleEditing();
61 };
62
63 const onRemove = async () => {
64 await actions.removeTravel();
65 toggleEditing();
66 };
67
68 return (
69 <div className={classes.header}>
70 <form onSubmit={onSave}>
71 <IconButton
72 size="small"
73 color="primary"
74 type="submit"
75 className={classes.edit}
76 >
77 <Icon>done</Icon>
78 </IconButton>
79 <DatePicker
80 label={t('travel.creation.date')}
81 fullWidth
82 helperText=" "
83 value={date}
84 onChange={setDate}
85 format="DD/MM/YYYY"
86 cancelLabel={t('generic.cancel')}
87 autoFocus
88 id="NewTravelDate"
89 />
90 <TimePicker
91 label={t('travel.creation.time')}
92 fullWidth
93 helperText=" "
94 value={time}
95 onChange={setTime}
96 cancelLabel={t('generic.cancel')}
97 ampm={false}
98 minutesStep={5}
99 id="NewTravelTime"
100 />
101 <TextField
102 label={t('travel.creation.name')}
103 fullWidth
104 helperText=" "
105 value={name}
106 onChange={e => setName(e.target.value)}
107 name="name"
108 id="EditTravelName"
109 />
110 <TextField
111 label={t('travel.creation.phone')}
112 fullWidth
113 helperText=" "
114 value={phone}
115 onChange={e => setPhone(e.target.value)}
116 name="phone"
117 id="EditTravelPhone"
118 />
119 <TextField
120 label={t('travel.creation.meeting')}
121 fullWidth
122 multiline
123 rowsMax={4}
124 inputProps={{maxLength: 250}}
125 helperText={`${meeting.length}/250`}
126 value={meeting}
127 onChange={e => setMeeting(e.target.value)}
128 name="meeting"
129 id="EditTravelMeeting"
130 />
131 <TextField
132 label={t('travel.creation.notes')}
133 fullWidth
134 multiline
135 rowsMax={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 <div className={classes.slider}>
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 </div>
161 </form>
162 <div className={classes.actions}>
163 <Button
164 variant="outlined"
165 color="primary"
166 onClick={onSave}
167 id="TravelSave"
168 >
169 {t('generic.save')}
170 </Button>
171 <Button
172 variant="outlined"
173 color="primary"
174 onClick={toggleRemoving}
175 id="TravelRemove"
176 >
177 {t('generic.remove')}
178 </Button>
179 </div>
180 <RemoveDialog
181 text={t('travel.actions.remove_alert')}
182 open={removing}
183 onClose={toggleRemoving}
184 onRemove={onRemove}
185 />
186 </div>
187 );
188};
189
190const useStyles = makeStyles(theme => ({
191 header: {
192 padding: theme.spacing(2),
193 },
194 edit: {
195 position: 'absolute',
196 top: 0,
197 right: 0,
198 margin: theme.spacing(1),
199 zIndex: theme.zIndex.speedDial,
200 },
201 section: {
202 marginTop: theme.spacing(2),
203 },
204 slider: {
205 marginTop: theme.spacing(2),
206 },
207 actions: {
208 display: 'flex',
209 flexDirection: 'column',
210 justifyContent: 'center',
211 margin: theme.spacing(2, 0),
212 '& > *:first-child': {
213 marginBottom: theme.spacing(2),
214 },
215 },
216}));
217
218export default HeaderEditing;