all repos — caroster @ 7c4ac0f6b287186311022f3893657bf173dcd540

[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 Typography from '@mui/material/Typography';
  3import Button from '@mui/material/Button';
  4import TextField from '@mui/material/TextField';
  5import Slider from '@mui/material/Slider';
  6import moment, {Moment} from 'moment';
  7import {useTheme} from '@mui/material/styles';
  8import {DatePicker} from '@mui/x-date-pickers/DatePicker';
  9import {TimePicker} from '@mui/x-date-pickers/TimePicker';
 10import {useTranslation} from 'react-i18next';
 11import RemoveDialog from '../RemoveDialog';
 12import useActions from './useActions';
 13import Box from '@mui/material/Box';
 14import PlaceInput from '../PlaceInput';
 15import useEventStore from '../../stores/useEventStore';
 16
 17const HeaderEditing = ({travel, toggleEditing}) => {
 18  const {t} = useTranslation();
 19  const theme = useTheme();
 20  const actions = useActions({travel});
 21  const isCarosterPlus = useEventStore(s =>
 22    s.event.enabled_modules?.includes('caroster-plus')
 23  );
 24  const [removing, toggleRemoving] = useReducer(i => !i, false);
 25  const dateMoment = useMemo(
 26    () => (travel?.departure ? moment(travel.departure) : null),
 27    [travel?.departure]
 28  );
 29
 30  // States
 31  const [name, setName] = useState(travel?.vehicleName ?? '');
 32  const [seats, setSeats] = useState(travel?.seats ?? 4);
 33  const [meeting, setMeeting] = useState(travel?.meeting ?? '');
 34  const [meeting_latitude, setMeetingLatitude] = useState(
 35    travel?.meeting_latitude
 36  );
 37  const [meeting_longitude, setMeetingLongitude] = useState(
 38    travel?.meeting_longitude
 39  );
 40  const [date, setDate] = useState(dateMoment);
 41  const [time, setTime] = useState(dateMoment);
 42  const [phone, setPhone] = useState(travel?.phone_number ?? '');
 43  const [details, setDetails] = useState(travel?.details ?? '');
 44
 45  // Click on ESQ closes the form
 46  const escFunction = useCallback(
 47    evt => {
 48      if (evt.keyCode === 27) toggleEditing();
 49    },
 50    [toggleEditing]
 51  );
 52
 53  useEffect(() => {
 54    document.addEventListener('keydown', escFunction, false);
 55    return () => {
 56      document.removeEventListener('keydown', escFunction, false);
 57    };
 58  }, [escFunction]);
 59
 60  const onSave = async event => {
 61    if (event.preventDefault) event.preventDefault();
 62    const travelUpdate = {
 63      meeting,
 64      meeting_latitude,
 65      meeting_longitude,
 66      details,
 67      seats,
 68      phone_number: phone,
 69      vehicleName: name,
 70      departure: formatDate(date, time),
 71    };
 72    await actions.updateTravel(travelUpdate);
 73    toggleEditing();
 74  };
 75
 76  const onRemove = async () => {
 77    await actions.removeTravel(
 78      isCarosterPlus
 79        ? t`travel.actions.removed.caroster_plus`
 80        : t`travel.actions.removed`
 81    );
 82    toggleEditing();
 83  };
 84
 85  return (
 86    <Box sx={{padding: 2}}>
 87      <form onSubmit={onSave}>
 88        <DatePicker
 89          slotProps={{
 90            textField: {
 91              sx: {width: '100%', pb: 2},
 92            },
 93          }}
 94          format="DD/MM/YYYY"
 95          label={t('travel.creation.date')}
 96          value={date}
 97          onChange={setDate}
 98          autoFocus
 99        />
100        <TimePicker
101          label={t('travel.creation.time')}
102          slotProps={{
103            textField: {
104              sx: {width: '100%', pb: 2},
105            },
106          }}
107          value={time}
108          onChange={setTime}
109          ampm={false}
110          minutesStep={5}
111        />
112        <TextField
113          label={t('travel.creation.name')}
114          fullWidth
115          sx={{pb: 2}}
116          value={name}
117          onChange={e => setName(e.target.value)}
118          name="name"
119          id="EditTravelName"
120        />
121        <TextField
122          label={t('travel.creation.phone')}
123          fullWidth
124          sx={{pb: 2}}
125          value={phone}
126          onChange={e => setPhone(e.target.value)}
127          name="phone"
128          id="EditTravelPhone"
129        />
130        <PlaceInput
131          label={t('travel.creation.meeting')}
132          textFieldProps={{sx: {pb: 2}}}
133          place={meeting}
134          latitude={meeting_latitude}
135          longitude={meeting_longitude}
136          onSelect={({place, latitude, longitude}) => {
137            setMeeting(place);
138            setMeetingLatitude(latitude);
139            setMeetingLongitude(longitude);
140          }}
141        />
142        <TextField
143          label={t('travel.creation.notes')}
144          fullWidth
145          sx={{pb: 2}}
146          multiline
147          maxRows={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        <Box sx={{marginTop: theme.spacing(2)}}>
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        </Box>
173      </form>
174      <Box
175        sx={{
176          display: 'flex',
177          flexDirection: 'column',
178          justifyContent: 'center',
179          margin: theme.spacing(2, 0),
180          '& > *:first-child': {
181            marginBottom: theme.spacing(2),
182          },
183        }}
184      >
185        <Button
186          variant="contained"
187          color="primary"
188          onClick={onSave}
189          id="TravelSave"
190        >
191          {t('generic.save')}
192        </Button>
193        <Button
194          variant="outlined"
195          color="primary"
196          onClick={toggleRemoving}
197          id="TravelRemove"
198        >
199          {t('generic.remove')}
200        </Button>
201      </Box>
202      <RemoveDialog
203        text={
204          isCarosterPlus
205            ? t`travel.actions.remove_alert.caroster_plus`
206            : t`travel.actions.remove_alert`
207        }
208        open={removing}
209        onClose={toggleRemoving}
210        onRemove={onRemove}
211      />
212    </Box>
213  );
214};
215
216const formatDate = (date: Moment, time: Moment) => {
217  return moment(
218    `${moment(date).format('YYYY-MM-DD')} ${moment(time).format('HH:mm')}`,
219    'YYYY-MM-DD HH:mm'
220  ).toISOString();
221};
222
223export default HeaderEditing;