frontend/containers/TravelColumns/index.tsx (view raw)
1import {useState} from 'react';
2import {useTranslation} from 'react-i18next';
3import {useTheme} from '@mui/material/styles';
4import Container from '@mui/material/Container';
5import Masonry from '@mui/lab/Masonry';
6import Box from '@mui/material/Box';
7import useEventStore from '../../stores/useEventStore';
8import useToastStore from '../../stores/useToastStore';
9import useProfile from '../../hooks/useProfile';
10import useAddToEvents from '../../hooks/useAddToEvents';
11import usePassengersActions from '../../hooks/usePassengersActions';
12import Travel from '../Travel';
13import NoCar from './NoCar';
14import {Travel as TravelData, TravelEntity} from '../../generated/graphql';
15import {AddPassengerToTravel} from '../NewPassengerDialog';
16
17type TravelType = TravelData & {id: string};
18
19interface Props {
20 toggle: () => void;
21}
22
23const TravelColumns = (props: Props) => {
24 const theme = useTheme();
25 const event = useEventStore(s => s.event);
26 const travels = event?.travels?.data || [];
27 const {t} = useTranslation();
28 const addToast = useToastStore(s => s.addToast);
29 const {addToEvent} = useAddToEvents();
30 const {profile, userId} = useProfile();
31
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 <Box
56 sx={{
57 paddingLeft: theme.spacing(1),
58 paddingRight: theme.spacing(1),
59 [theme.breakpoints.down('md')]: {
60 paddingLeft: theme.spacing(),
61 paddingRight: theme.spacing(),
62 },
63 display: 'flex',
64 flexDirection: 'column',
65 }}
66 >
67 <Box
68 sx={{
69 height: '56px',
70 overflow: 'auto',
71 '& overflow': '-moz-scrollbars-none',
72 '-ms-overflow-style': 'none',
73 '&::-webkit-scrollbar': {
74 height: '0 !important',
75 },
76 '& .slick-dots': {
77 position: 'static',
78 '& li': {
79 display: 'block',
80 '& button:before': {
81 fontSize: '12px',
82 },
83 },
84 },
85 '& .slick-dots li:first-child button:before, & .slick-dots li:last-child button:before':
86 {
87 color: theme.palette.primary.main,
88 },
89 }}
90 id="slider-dots"
91 />
92 {(travels?.length === 0 && (
93 <NoCar
94 image
95 eventName={event?.name}
96 title={t('event.no_travel.title')}
97 />
98 )) || (
99 <Masonry columns={{xl: 4, lg: 3, md: 2, sm: 2, xs: 1}} spacing={0}>
100 {sortedTravels?.map(({id, attributes}) => {
101 const travel = {id, ...attributes};
102 return (
103 <Container
104 key={travel.id}
105 maxWidth="sm"
106 sx={{
107 padding: theme.spacing(1),
108 marginBottom: theme.spacing(10),
109 outline: 'none',
110 '& > *': {
111 cursor: 'default',
112 },
113
114 [theme.breakpoints.down('md')]: {
115 marginBottom: `calc(${theme.spacing(10)} + 56px)`,
116 },
117 }}
118 >
119 <Travel
120 travel={travel}
121 {...props}
122 getAddPassengerFunction={(addSelf: boolean) => () =>
123 addSelf
124 ? addSelfToTravel(travel)
125 : toggleNewPassengerToTravel({travel})}
126 />
127 </Container>
128 );
129 })}
130 <Container
131 maxWidth="sm"
132 sx={{
133 padding: theme.spacing(1),
134 marginBottom: theme.spacing(10),
135 outline: 'none',
136 '& > *': {
137 cursor: 'default',
138 },
139
140 [theme.breakpoints.down('md')]: {
141 marginBottom: `calc(${theme.spacing(10)} + 56px)`,
142 },
143 }}
144 >
145 <NoCar
146 eventName={event?.name}
147 title={t('event.no_other_travel.title')}
148 />
149 </Container>
150 </Masonry>
151 )}
152 {!!newPassengerTravelContext && (
153 <AddPassengerToTravel
154 open={!!newPassengerTravelContext}
155 toggle={() => toggleNewPassengerToTravel(null)}
156 travel={newPassengerTravelContext.travel}
157 />
158 )}
159 </Box>
160 );
161};
162
163const sortTravels = (
164 {attributes: a}: TravelEntity,
165 {attributes: b}: TravelEntity
166) => {
167 if (!b) return 1;
168 const dateA = new Date(a.departure).getTime();
169 const dateB = new Date(b.departure).getTime();
170 if (dateA === dateB)
171 return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
172 else return dateA - dateB;
173};
174
175export default TravelColumns;