all repos — caroster @ 671bf12812b5cb332d94dcd491e18b7264d4844e

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