all repos — caroster @ a60257e204f1cc253e9d375f87bc6d7ea661c1d8

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

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 useToastStore from '../../stores/useToastStore';
 13import useEventStore from '../../stores/useEventStore';
 14import RemoveDialog from '../RemoveDialog';
 15import {
 16  useUpdateEventMutation,
 17  useDeleteTravelMutation,
 18} from '../../generated/graphql';
 19import useActions from './useActions';
 20
 21const HeaderEditing = ({travel, toggleEditing}) => {
 22  const classes = useStyles();
 23  const {t} = useTranslation();
 24  const event = useEventStore(s => s.event);
 25  const addToast = useToastStore(s => s.addToast);
 26  const actions = useActions({travel});
 27  const [updateEvent] = useUpdateEventMutation();
 28  const [deleteTravel] = useDeleteTravelMutation({
 29    refetchQueries: ['eventByUUID'],
 30  });
 31  const [removing, toggleRemoving] = useReducer(i => !i, false);
 32  const dateMoment = useMemo(() => {
 33    if (!travel?.departure) return moment();
 34    else return moment(travel.departure);
 35  }, [travel?.departure]);
 36
 37  // States
 38  const [name, setName] = useState(travel?.vehicle?.name ?? '');
 39  const [seats, setSeats] = useState(travel?.vehicle?.seats ?? 4);
 40  const [meeting, setMeeting] = useState(travel?.meeting ?? '');
 41  const [date, setDate] = useState(dateMoment);
 42  const [time, setTime] = useState(dateMoment);
 43  const [phone, setPhone] = useState(travel?.vehicle?.phone_number ?? '');
 44  const [details, setDetails] = useState(travel?.details ?? '');
 45
 46  // Click on ESQ closes the form
 47  const escFunction = useCallback(
 48    evt => {
 49      if (evt.keyCode === 27) toggleEditing();
 50    },
 51    [toggleEditing]
 52  );
 53
 54  useEffect(() => {
 55    document.addEventListener('keydown', escFunction, false);
 56    return () => {
 57      document.removeEventListener('keydown', escFunction, false);
 58    };
 59  }, [escFunction]);
 60
 61  const onSave = async event => {
 62    if (event.preventDefault) event.preventDefault();
 63    const update = {
 64      vehicle: {
 65        name,
 66        seats,
 67        phone_number: phone,
 68      },
 69      travel: {meeting, date, time, details},
 70    };
 71    await actions.updateTravel(update);
 72    toggleEditing();
 73  };
 74
 75  const onRemove = async () => {
 76    await actions.removeTravel();
 77    toggleEditing();
 78  };
 79
 80  return (
 81    <div className={classes.header}>
 82      <form onSubmit={onSave}>
 83        <IconButton
 84          size="small"
 85          color="primary"
 86          type="submit"
 87          className={classes.edit}
 88        >
 89          <Icon>done</Icon>
 90        </IconButton>
 91        <DatePicker
 92          label={t('travel.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="NewTravelDate"
101        />
102        <TimePicker
103          label={t('travel.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="NewTravelTime"
112        />
113        <TextField
114          label={t('travel.creation.name')}
115          fullWidth
116          helperText=" "
117          value={name}
118          onChange={e => setName(e.target.value)}
119          name="name"
120          id="EditTravelName"
121        />
122        <TextField
123          label={t('travel.creation.phone')}
124          fullWidth
125          helperText=" "
126          value={phone}
127          onChange={e => setPhone(e.target.value)}
128          name="phone"
129          id="EditTravelPhone"
130        />
131        <TextField
132          label={t('travel.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="EditTravelMeeting"
142        />
143        <TextField
144          label={t('travel.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="EditTravelDetails"
154        />
155        <div className={classes.slider}>
156          <Typography variant="caption">
157            {t('travel.creation.seats')}
158          </Typography>
159          <Slider
160            value={seats}
161            onChange={(e, value) => setSeats(value)}
162            step={1}
163            marks={[1, 2, 3, 4, 5, 6, 7, 8].map(value => ({
164              value,
165              label: value,
166            }))}
167            min={1}
168            max={8}
169            valueLabelDisplay="auto"
170            id="EditTravelSeats"
171          />
172        </div>
173      </form>
174      <div className={classes.actions}>
175        <Button
176          variant="outlined"
177          color="primary"
178          onClick={onSave}
179          id="TravelSave"
180        >
181          {t('generic.save')}
182        </Button>
183        <Button
184          variant="outlined"
185          color="primary"
186          onClick={toggleRemoving}
187          id="TravelRemove"
188        >
189          {t('generic.remove')}
190        </Button>
191      </div>
192      <RemoveDialog
193        text={t('travel.actions.remove_alert')}
194        open={removing}
195        onClose={toggleRemoving}
196        onRemove={onRemove}
197      />
198    </div>
199  );
200};
201
202const useStyles = makeStyles(theme => ({
203  header: {
204    padding: theme.spacing(2),
205  },
206  edit: {
207    position: 'absolute',
208    top: 0,
209    right: 0,
210    margin: theme.spacing(1),
211    zIndex: theme.zIndex.speedDial,
212  },
213  section: {
214    marginTop: theme.spacing(2),
215  },
216  slider: {
217    marginTop: theme.spacing(2),
218  },
219  actions: {
220    display: 'flex',
221    flexDirection: 'column',
222    justifyContent: 'center',
223    margin: theme.spacing(2, 0),
224    '& > *:first-child': {
225      marginBottom: theme.spacing(2),
226    },
227  },
228}));
229
230export default HeaderEditing;