frontend/containers/TravelColumns/index.tsx (view raw)
1import {useEffect, useRef} from 'react';
2import {makeStyles} from '@material-ui/core/styles';
3import Container from '@material-ui/core/Container';
4import Slider from 'react-slick';
5import {Travel as TravelType} from '../../generated/graphql';
6import useEventStore from '../../stores/useEventStore';
7import useTourStore from '../../stores/useTourStore';
8import WaitingList from '../WaitingList';
9import Travel from '../Travel';
10import AddTravel from './AddTravel';
11import sliderSettings from './_SliderSettings';
12
13interface Props {
14 toggleNewTravel: () => void;
15}
16
17const TravelColumns = (props: Props) => {
18 const event = useEventStore(s => s.event);
19 const {travels = []} = event || {};
20 const slider = useRef(null);
21 const tourStep = useTourStore(s => s.step);
22 const classes = useStyles();
23
24 // On tour step changes : component update
25 useEffect(() => {
26 onTourChange(slider.current);
27 }, [tourStep]);
28
29 return (
30 <div className={classes.container}>
31 <div className={classes.dots} id="slider-dots" />
32 <div className={classes.slider}>
33 <Slider ref={slider} {...sliderSettings}>
34 <Container maxWidth="sm" className={classes.slide}>
35 <WaitingList />
36 </Container>
37 {travels
38 ?.slice()
39 .sort(sortTravels)
40 .map(travel => (
41 <Container
42 key={travel.id}
43 maxWidth="sm"
44 className={classes.slide}
45 >
46 <Travel travel={travel} {...props} />
47 </Container>
48 ))}
49 <Container maxWidth="sm" className={classes.slide}>
50 <AddTravel {...props} />
51 </Container>
52 </Slider>
53 </div>
54 </div>
55 );
56};
57
58const onTourChange = slider => {
59 const {prev, step, isCreator} = useTourStore.getState();
60 const fromTo = (step1: number, step2: number) =>
61 prev === step1 && step === step2;
62
63 if (isCreator) {
64 if (fromTo(2, 3) || fromTo(4, 3)) slider?.slickGoTo(0, true);
65 } else if (fromTo(0, 1)) slider?.slickGoTo(0, true);
66};
67
68const sortTravels = (a: TravelType, b: TravelType) => {
69 if (!b) return 1;
70 const dateA = new Date(a.departure).getTime();
71 const dateB = new Date(b.departure).getTime();
72 if (dateA === dateB)
73 return new Date(a.created_at).getTime() - new Date(b.created_at).getTime();
74 else return dateA - dateB;
75};
76
77const useStyles = makeStyles(theme => ({
78 container: {
79 minHeight: '100vh',
80 paddingTop: theme.mixins.toolbar.minHeight,
81 paddingLeft: theme.spacing(6),
82 paddingRight: theme.spacing(6),
83 [theme.breakpoints.down('sm')]: {
84 paddingLeft: theme.spacing(),
85 paddingRight: theme.spacing(),
86 },
87 display: 'flex',
88 flexDirection: 'column',
89 overflowX: 'hidden',
90 overflowY: 'auto',
91 },
92 dots: {
93 height: 32,
94 overflow: 'auto',
95 '& overflow': '-moz-scrollbars-none',
96 '-ms-overflow-style': 'none',
97 '&::-webkit-scrollbar': {
98 height: '0 !important',
99 },
100 '& .slick-dots': {
101 position: 'static',
102 '& li': {
103 display: 'block',
104 },
105 },
106 '& .slick-dots li:first-child button:before, & .slick-dots li:last-child button:before': {
107 color: theme.palette.primary.main,
108 },
109 },
110 slider: {
111 flexGrow: 1,
112 height: 1,
113 '& .slick-slider': {
114 height: '100%',
115 '& .slick-list': {
116 overflow: 'visible',
117 },
118 cursor: 'grab',
119 },
120 },
121 slide: {
122 padding: theme.spacing(1),
123 marginBottom: theme.spacing(12),
124 outline: 'none',
125 '& > *': {
126 cursor: 'default',
127 },
128 },
129}));
130
131export default TravelColumns;