all repos — caroster @ e05034e4ae972de5a8df40528d270d038c4343e6

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

frontend/containers/WaitingList/TravelDialog.tsx (view raw)

  1import moment from 'moment';
  2import { styled } from '@mui/material/styles';
  3import Link from '@mui/material/Link';
  4import Typography from '@mui/material/Typography';
  5import Button from '@mui/material/Button';
  6import Slide from '@mui/material/Slide';
  7import Dialog from '@mui/material/Dialog';
  8import AppBar from '@mui/material/AppBar';
  9import Toolbar from '@mui/material/Toolbar';
 10import ListItem from '@mui/material/ListItem';
 11import List from '@mui/material/List';
 12import IconButton from '@mui/material/IconButton';
 13import Icon from '@mui/material/Icon';
 14import Box from '@mui/material/Box';
 15import {useTranslation} from 'react-i18next';
 16import {forwardRef} from 'react';
 17import getMapsLink from '../../lib/getMapsLink';
 18import ShareEvent from '../ShareEvent';
 19import {Passenger, TravelEntity, Travel} from '../../generated/graphql';
 20
 21const PREFIX = 'TravelDialog';
 22
 23const classes = {
 24  offset: `${PREFIX}-offset`,
 25  rtlBox: `${PREFIX}-rtlBox`,
 26  info: `${PREFIX}-info`,
 27  listItem: `${PREFIX}-listItem`,
 28  date: `${PREFIX}-date`,
 29  button: `${PREFIX}-button`,
 30  noTravel: `${PREFIX}-noTravel`,
 31  noTravelImage: `${PREFIX}-noTravelImage`,
 32  share: `${PREFIX}-share`
 33};
 34
 35const StyledSlide = styled(Slide)((
 36  {
 37    theme
 38  }
 39) => ({
 40  [`& .${classes.offset}`]: {
 41    paddingTop: theme.spacing(7),
 42  },
 43
 44  [`& .${classes.rtlBox}`]: {
 45    display: 'flex',
 46    padding: 0,
 47    margin: 0,
 48    direction: 'rtl',
 49    [theme.breakpoints.down('md')]: {
 50      display: 'block',
 51      paddingBottom: theme.spacing(1),
 52    },
 53  },
 54
 55  [`& .${classes.info}`]: {
 56    padding: theme.spacing(0, 4, 0, 0),
 57    width: '350px',
 58    [theme.breakpoints.down('md')]: {
 59      padding: theme.spacing(0.5, 1),
 60      width: '100%',
 61      textAlign: 'left',
 62    },
 63  },
 64
 65  [`& .${classes.listItem}`]: {
 66    display: 'flex',
 67    justifyContent: 'left',
 68    [theme.breakpoints.down('md')]: {
 69      display: 'block',
 70      textAlign: 'center',
 71    },
 72  },
 73
 74  [`& .${classes.date}`]: {
 75    textTransform: 'capitalize',
 76    padding: theme.spacing(0, 0, 0.5, 0),
 77  },
 78
 79  [`& .${classes.button}`]: {
 80    padding: theme.spacing(1, 15),
 81    margin: theme.spacing(1),
 82  },
 83
 84  [`& .${classes.noTravel}`]: {
 85    margin: '120px auto 0 auto',
 86    width: '330px',
 87    maxWidth: '100%',
 88    textAlign: 'center',
 89  },
 90
 91  [`& .${classes.noTravelImage}`]: {
 92    width: 'calc(100% - 2px)',
 93    [theme.breakpoints.down('md')]: {
 94      width: 'calc(50% - 2px)',
 95    },
 96  },
 97
 98  [`& .${classes.share}`]: {
 99    marginTop: theme.spacing(2),
100    backgroundColor: '#fff',
101  }
102}));
103
104interface Props {
105  eventName: string;
106  travels: Array<TravelEntity>;
107  passenger: Passenger;
108  open: boolean;
109  onClose: () => void;
110  onSelect: (travel: Travel & {id: string}) => void;
111}
112
113const TravelDialog = ({
114  eventName,
115  travels,
116  passenger,
117  open,
118  onClose,
119  onSelect,
120}: Props) => {
121
122  const {t} = useTranslation();
123
124  const availableTravels = travels?.filter(
125    ({attributes}) =>
126      attributes.passengers &&
127      attributes?.seats > attributes.passengers.data.length
128  );
129
130  return (
131    <Dialog
132      fullScreen
133      open={open}
134      onClose={onClose}
135      TransitionComponent={Transition}
136    >
137      <AppBar>
138        <Toolbar>
139          <IconButton onClick={onClose} color="inherit" size="large">
140            <Icon>arrow_back_ios</Icon>
141          </IconButton>
142          <Typography variant="h5">
143            {t('passenger.creation.available_cars')}
144          </Typography>
145        </Toolbar>
146      </AppBar>
147      {(availableTravels.length === 0 && (
148        <Box className={classes.noTravel}>
149          <Typography variant="h5">
150            {t('passenger.creation.no_travel.title')}
151          </Typography>
152          <img className={classes.noTravelImage} src="/assets/car.png" />
153          <Typography>
154            {t('passenger.creation.no_travel.desc', {name: passenger?.name})}
155          </Typography>
156          <ShareEvent
157            className={classes.share}
158            title={`Caroster ${eventName}`}
159            url={`${typeof window !== 'undefined' ? window.location.href : ''}`}
160          />
161        </Box>
162      )) || (
163        <div className={classes.offset}>
164          <List disablePadding>
165            {availableTravels.map(({id, attributes}, i) => {
166              const travel = {id, ...attributes};
167              const passengersCount = travel?.passengers?.data.length || 0;
168              const counter = `${passengersCount} / ${travel?.seats || 0}`;
169              return (
170                <ListItem key={i} divider className={classes.listItem}>
171                  <Box className={classes.rtlBox}>
172                    <Box className={classes.info}>
173                      <Typography variant="subtitle1" className={classes.date}>
174                        {t('passenger.creation.departure')}
175                        {moment(travel.departure).format('LLLL')}
176                      </Typography>
177                      <Link
178                        target="_blank"
179                        rel="noreferrer"
180                        href={getMapsLink(travel.meeting)}
181                        onClick={e => e.preventDefault}
182                      >
183                        {travel.meeting}
184                      </Link>
185                    </Box>
186                    <Box className={classes.info}>
187                      <Typography variant="h6">{travel.vehicleName}</Typography>
188                      <Typography variant="body2">
189                        {t('passenger.creation.seats', {seats: counter})}
190                      </Typography>
191                    </Box>
192                  </Box>
193                  <Button
194                    color="primary"
195                    variant="contained"
196                    onClick={() => onSelect(travel)}
197                    className={classes.button}
198                  >
199                    {t('passenger.creation.assign')}
200                  </Button>
201                </ListItem>
202              );
203            })}
204          </List>
205        </div>
206      )}
207    </Dialog>
208  );
209};
210
211const Transition = forwardRef(function Transition(props, ref) {
212  return <StyledSlide direction="up" ref={ref} {...props} />;
213});
214
215export default TravelDialog;