all repos — caroster @ b8dc99b3be7b7cfaa1158efeb1bcd7938ec44758

[Octree] Group carpool to your event https://caroster.io

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