frontend/containers/NewCarDialog/index.tsx (view raw)
1import {useState, forwardRef, useMemo} from 'react';
2import {makeStyles} from '@material-ui/core/styles';
3import Dialog from '@material-ui/core/Dialog';
4import DialogActions from '@material-ui/core/DialogActions';
5import DialogContent from '@material-ui/core/DialogContent';
6import DialogTitle from '@material-ui/core/DialogTitle';
7import Button from '@material-ui/core/Button';
8import Slide from '@material-ui/core/Slide';
9import TextField from '@material-ui/core/TextField';
10import Slider from '@material-ui/core/Slider';
11import Typography from '@material-ui/core/Typography';
12import {DatePicker, TimePicker} from '@material-ui/pickers';
13import moment from 'moment';
14import {useTranslation} from 'react-i18next';
15import useEventStore from '../../stores/useEventStore';
16import useToastsStore from '../../stores/useToastStore';
17import useAddToEvents from '../../hooks/useAddToEvents';
18import {useCreateCarMutation} from '../../generated/graphql';
19
20const NewCarDialog = ({open, toggle}) => {
21 const {t} = useTranslation();
22 const classes = useStyles();
23 const addToast = useToastsStore(s => s.addToast);
24 const {addToEvent} = useAddToEvents();
25 const event = useEventStore(s => s.event);
26 const [createCar] = useCreateCarMutation({refetchQueries: ['eventByUUID']});
27 const dateMoment = useMemo(() => {
28 if (!event?.date) return moment();
29 else return moment(event.date);
30 }, [event?.date]);
31
32 // States
33 const [name, setName] = useState('');
34 const [seats, setSeats] = useState(4);
35 const [meeting, setMeeting] = useState('');
36 const [date, setDate] = useState(dateMoment);
37 const [time, setTime] = useState(dateMoment);
38 const [phone, setPhone] = useState('');
39 const [details, setDetails] = useState('');
40 const canCreate = !!name && !!seats;
41
42 const onCreate = async e => {
43 if (e.preventDefault) e.preventDefault();
44 try {
45 const departure = moment(
46 `${moment(date).format('YYYY-MM-DD')} ${moment(time).format('HH:mm')}`,
47 'YYYY-MM-DD HH:mm'
48 ).toISOString();
49 await createCar({
50 variables: {
51 car: {
52 name,
53 seats,
54 meeting,
55 departure,
56 phone_number: phone,
57 details,
58 event: event.id,
59 },
60 },
61 });
62 addToEvent(event.id);
63 addToast(t('car.creation.created'));
64 toggle();
65
66 // Clear states
67 setName('');
68 setSeats(4);
69 setMeeting('');
70 setDate(moment());
71 setPhone('');
72 setDetails('');
73 } catch (error) {
74 console.error(error);
75 addToast(t('car.errors.cant_create'));
76 }
77 return false;
78 };
79
80 return (
81 <Dialog
82 fullWidth
83 maxWidth="sm"
84 open={open}
85 onClose={toggle}
86 TransitionComponent={Transition}
87 >
88 <form onSubmit={onCreate}>
89 <DialogTitle>{t('car.creation.title')}</DialogTitle>
90 <DialogContent>
91 <DatePicker
92 label={t('car.creation.date')}
93 fullWidth
94 helperText=" "
95 value={date}
96 onChange={setDate}
97 format="DD/MM/YYYY"
98 cancelLabel={t('generic.cancel')}
99 autoFocus
100 id="NewCarDateTime"
101 />
102 <TimePicker
103 label={t('car.creation.time')}
104 fullWidth
105 helperText=" "
106 value={time}
107 onChange={setTime}
108 cancelLabel={t('generic.cancel')}
109 ampm={false}
110 minutesStep={5}
111 id="NewCarTime"
112 />
113 <TextField
114 label={t('car.creation.name')}
115 fullWidth
116 helperText=" "
117 value={name}
118 onChange={e => setName(e.target.value)}
119 name="name"
120 id="NewCarName"
121 />
122 <TextField
123 label={t('car.creation.phone')}
124 fullWidth
125 helperText=" "
126 value={phone}
127 onChange={e => setPhone(e.target.value)}
128 name="phone"
129 id="NewCarPhone"
130 />
131 <TextField
132 label={t('car.creation.meeting')}
133 fullWidth
134 multiline
135 rowsMax={4}
136 inputProps={{maxLength: 250}}
137 helperText={`${meeting.length}/250`}
138 value={meeting}
139 onChange={e => setMeeting(e.target.value)}
140 name="meeting"
141 id="NewCarMeeting"
142 />
143 <TextField
144 label={t('car.creation.notes')}
145 fullWidth
146 multiline
147 rowsMax={4}
148 inputProps={{maxLength: 250}}
149 helperText={`${details.length}/250`}
150 value={details}
151 onChange={e => setDetails(e.target.value)}
152 name="details"
153 id="NewCarDetails"
154 />
155 <div className={classes.slider}>
156 <Typography variant="caption">{t('car.creation.seats')}</Typography>
157 <Slider
158 value={seats}
159 onChange={(e, value) => setSeats(value)}
160 step={1}
161 marks={MARKS}
162 min={1}
163 max={MARKS.length}
164 valueLabelDisplay="auto"
165 id="NewCarSeats"
166 />
167 </div>
168 </DialogContent>
169 <DialogActions>
170 <Button
171 color="primary"
172 id="NewCarCancel"
173 onClick={toggle}
174 tabIndex={-1}
175 >
176 {t('generic.cancel')}
177 </Button>
178 <Button
179 color="primary"
180 variant="contained"
181 type="submit"
182 disabled={!canCreate}
183 aria-disabled={!canCreate}
184 id="NewCarSubmit"
185 >
186 {t('generic.create')}
187 </Button>
188 </DialogActions>
189 </form>
190 </Dialog>
191 );
192};
193
194const Transition = forwardRef(function Transition(props, ref) {
195 return <Slide direction="up" ref={ref} {...props} />;
196});
197
198const MARKS = [1, 2, 3, 4, 5, 6, 7, 8].map(value => ({
199 value,
200 label: value,
201}));
202
203const useStyles = makeStyles(theme => ({
204 slider: {
205 marginTop: theme.spacing(2),
206 },
207}));
208
209export default NewCarDialog;