all repos — caroster @ 5b2bff1c4921d7880400037670dac9c88258965a

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

frontend/containers/TravelColumns/index.tsx (view raw)

  1import {useRef, useState} from 'react';
  2import {makeStyles} from '@material-ui/core/styles';
  3import Container from '@material-ui/core/Container';
  4import Slider from 'react-slick';
  5import {useTranslation} from 'react-i18next';
  6import {Travel as TravelData, TravelEntity} from '../../generated/graphql';
  7import useEventStore from '../../stores/useEventStore';
  8import useToastStore from '../../stores/useToastStore';
  9import useProfile from '../../hooks/useProfile';
 10import useAddToEvents from '../../hooks/useAddToEvents';
 11import {AddPassengerToTravel} from '../NewPassengerDialog';
 12import Travel from '../Travel';
 13import sliderSettings from './_SliderSettings';
 14import usePassengersActions from '../../hooks/usePassengersActions';
 15import NoCar from './NoCar';
 16
 17type TravelType = TravelData & {id: string};
 18
 19interface Props {
 20  toggle: () => void;
 21}
 22
 23const TravelColumns = (props: Props) => {
 24  const event = useEventStore(s => s.event);
 25  const travels = event?.travels?.data || [];
 26  const slider = useRef(null);
 27  const {t} = useTranslation();
 28  const addToast = useToastStore(s => s.addToast);
 29  const {addToEvent} = useAddToEvents();
 30  const {profile, userId} = useProfile();
 31  const classes = useStyles();
 32  const [newPassengerTravelContext, toggleNewPassengerToTravel] = useState<{
 33    travel: TravelType;
 34  } | null>(null);
 35  const {addPassenger} = usePassengersActions();
 36  const sortedTravels = travels?.slice().sort(sortTravels);
 37
 38  const addSelfToTravel = async (travel: TravelType) => {
 39    try {
 40      await addPassenger({
 41        user: userId,
 42        email: profile.email,
 43        name: profile.username,
 44        travel: travel.id,
 45        event: event.id,
 46      });
 47      addToEvent(event.id);
 48      addToast(t('passenger.success.added_self_to_car'));
 49    } catch (error) {
 50      console.error(error);
 51    }
 52  };
 53
 54  return (
 55    <div className={classes.container}>
 56      <div className={classes.dots} id="slider-dots" />
 57      {(travels?.length === 0 && (
 58        <NoCar
 59          image
 60          eventName={event?.name}
 61          title={t('event.no_travel.title')}
 62        />
 63      )) || (
 64        <Slider ref={slider} {...sliderSettings}>
 65          {sortedTravels?.map(({id, attributes}) => {
 66            const travel = {id, ...attributes};
 67            return (
 68              <Container
 69                key={travel.id}
 70                maxWidth="sm"
 71                className={classes.slide}
 72              >
 73                <Travel
 74                  travel={travel}
 75                  {...props}
 76                  getAddPassengerFunction={(addSelf: boolean) => () =>
 77                    addSelf
 78                      ? addSelfToTravel(travel)
 79                      : toggleNewPassengerToTravel({travel})}
 80                />
 81              </Container>
 82            );
 83          })}
 84          <Container maxWidth="sm" className={classes.slide}>
 85            <NoCar
 86              eventName={event?.name}
 87              title={t('event.no_other_travel.title')}
 88            />
 89          </Container>
 90        </Slider>
 91      )}
 92      {!!newPassengerTravelContext && (
 93        <AddPassengerToTravel
 94          open={!!newPassengerTravelContext}
 95          toggle={() => toggleNewPassengerToTravel(null)}
 96          travel={newPassengerTravelContext.travel}
 97        />
 98      )}
 99    </div>
100  );
101};
102
103const sortTravels = (
104  {attributes: a}: TravelEntity,
105  {attributes: b}: TravelEntity
106) => {
107  if (!b) return 1;
108  const dateA = new Date(a.departure).getTime();
109  const dateB = new Date(b.departure).getTime();
110  if (dateA === dateB)
111    return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
112  else return dateA - dateB;
113};
114
115const useStyles = makeStyles(theme => ({
116  container: {
117    paddingLeft: theme.spacing(6),
118    paddingRight: theme.spacing(6),
119    [theme.breakpoints.down('sm')]: {
120      paddingLeft: theme.spacing(),
121      paddingRight: theme.spacing(),
122    },
123    display: 'flex',
124    flexDirection: 'column',
125  },
126  dots: {
127    height: '56px',
128    overflow: 'auto',
129    '& overflow': '-moz-scrollbars-none',
130    '-ms-overflow-style': 'none',
131    '&::-webkit-scrollbar': {
132      height: '0 !important',
133    },
134    '& .slick-dots': {
135      position: 'static',
136      '& li': {
137        display: 'block',
138        '& button:before': {
139          fontSize: '12px',
140        },
141      },
142    },
143    '& .slick-dots li:first-child button:before, & .slick-dots li:last-child button:before':
144      {
145        color: theme.palette.primary.main,
146      },
147  },
148  slide: {
149    padding: theme.spacing(1),
150    marginBottom: theme.spacing(10),
151    outline: 'none',
152    '& > *': {
153      cursor: 'default',
154    },
155
156    [theme.breakpoints.down('sm')]: {
157      marginBottom: `${theme.spacing(10) + 56}px`,
158    },
159  },
160}));
161
162export default TravelColumns;