all repos — caroster @ 8f7930deb0475683392d3660112a7b737f2b025a

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