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;