app/src/containers/WaitingList/index.js (view raw)
1import React, {useReducer, useState, useMemo} from 'react';
2import Typography from '@material-ui/core/Typography';
3import IconButton from '@material-ui/core/IconButton';
4import Icon from '@material-ui/core/Icon';
5import Paper from '@material-ui/core/Paper';
6import Divider from '@material-ui/core/Divider';
7import {makeStyles} from '@material-ui/core/styles';
8import {Trans, useTranslation} from 'react-i18next';
9import {useStrapi} from 'strapi-react-context';
10import {useEvent} from '../../contexts/Event';
11import {useToast} from '../../contexts/Toast';
12import PassengersList from '../PassengersList';
13import RemoveDialog from '../RemoveDialog';
14import CarDialog from './CarDialog';
15
16const sortCars = (a, b) => {
17 const dateA = new Date(a.departure).getTime();
18 const dateB = new Date(b.departure).getTime();
19 if (dateA === dateB) return new Date(a.createdAt) - new Date(b.createdAt);
20 else return dateA - dateB;
21};
22
23const WaitingList = ({car}) => {
24 const classes = useStyles();
25 const {t} = useTranslation();
26 const {event} = useEvent();
27 const {addToast} = useToast();
28 const strapi = useStrapi();
29 const [isEditing, toggleEditing] = useReducer(i => !i, false);
30 const [removing, setRemoving] = useState(null);
31 const [adding, setAdding] = useState(null);
32 const passengers = event.waiting_list;
33
34 const cars = useMemo(
35 () =>
36 strapi.stores.cars
37 ?.filter(car => car?.event?.id === event?.id)
38 .sort(sortCars),
39 [strapi.stores.cars, event]
40 );
41
42 const availability = useMemo(() => {
43 if (!cars) return;
44 return cars.reduce((count, {seats, passengers = []}) => {
45 return count + seats - passengers.length;
46 }, 0);
47 }, [cars]);
48
49 const saveWaitingList = async (waitingList, i18nError) => {
50 try {
51 await strapi.services.events.update(event.id, {
52 waiting_list: waitingList,
53 });
54 } catch (error) {
55 console.error(error);
56 addToast(t(i18nError));
57 }
58 };
59
60 const addPassenger = async passenger => {
61 return saveWaitingList(
62 [...(event.waiting_list || []), passenger],
63 'passenger.errors.cant_add_passenger'
64 );
65 };
66
67 const removePassenger = index => {
68 return saveWaitingList(
69 passengers.filter((_, i) => i !== index),
70 'passenger.errors.cant_remove_passenger'
71 );
72 };
73
74 const selectCar = async car => {
75 try {
76 await strapi.services.cars.update(car.id, {
77 passengers: [...(car.passengers || []), passengers[adding]],
78 });
79 await strapi.services.events.update(event.id, {
80 waiting_list: event.waiting_list.filter((_, i) => i !== adding),
81 });
82 } catch (error) {
83 console.error(error);
84 addToast(t('passenger.errors.cant_select_car'));
85 }
86 setAdding(null);
87 };
88
89 const onPress = index => {
90 if (isEditing) setRemoving(index);
91 else setAdding(index);
92 };
93
94 return (
95 <>
96 <Paper className={classes.root}>
97 <div className={classes.header}>
98 <IconButton
99 size="small"
100 color="primary"
101 className={classes.editBtn}
102 onClick={toggleEditing}
103 >
104 {isEditing ? <Icon>check</Icon> : <Icon>edit</Icon>}
105 </IconButton>
106 <Typography variant="h5">{t('passenger.title')}</Typography>
107 <Typography variant="overline">
108 {t('passenger.availability.seats', {count: availability})}
109 </Typography>
110 </div>
111 <Divider />
112 <PassengersList
113 passengers={passengers}
114 addPassenger={addPassenger}
115 onPress={onPress}
116 icon={isEditing ? 'close' : 'chevron_right'}
117 disabled={!isEditing && availability <= 0}
118 />
119 </Paper>
120 <RemoveDialog
121 text={
122 <Trans
123 i18nKey="passenger.actions.remove_alert"
124 values={{name: passengers ? passengers[removing] : null}}
125 components={{italic: <i />, bold: <strong />}}
126 />
127 }
128 open={removing !== null}
129 onClose={() => setRemoving(null)}
130 onRemove={async () => removePassenger(removing)}
131 />
132 <CarDialog
133 cars={cars}
134 open={adding !== null}
135 onClose={() => setAdding(null)}
136 onSelect={selectCar}
137 />
138 </>
139 );
140};
141
142const useStyles = makeStyles(theme => ({
143 root: {
144 position: 'relative',
145 },
146 header: {
147 padding: theme.spacing(2),
148 },
149 editBtn: {
150 position: 'absolute',
151 top: 0,
152 right: 0,
153 margin: theme.spacing(1),
154 zIndex: theme.zIndex.speedDial,
155 },
156}));
157
158export default WaitingList;