all repos — caroster @ c938f6d09213822e418659e119ad87b40ee923e4

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

frontend/containers/Travel/HeaderEditing.tsx (view raw)

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