all repos — caroster @ 8f8d1b858152fdaf4b7594c0f9ebc84e7518a035

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

frontend/containers/Travel/Header.tsx (view raw)

  1import moment from 'moment';
  2import Linkify from 'linkify-react';
  3import Typography from '@mui/material/Typography';
  4import IconButton from '@mui/material/IconButton';
  5import TuneIcon from '@mui/icons-material/Tune';
  6import Box from '@mui/material/Box';
  7import Link from '@mui/material/Link';
  8import LinearProgress from '@mui/material/LinearProgress';
  9import Chip from '@mui/material/Chip';
 10import {useTheme} from '@mui/material/styles';
 11import {useTranslation} from 'react-i18next';
 12import getMapsLink from '../../lib/getMapsLink';
 13import useMapStore from '../../stores/useMapStore';
 14import usePermissions from '../../hooks/usePermissions';
 15import useProfile from '../../hooks/useProfile';
 16import DetailsLink from './DetailsLink';
 17import {TravelEntity} from '../../generated/graphql';
 18
 19interface Props {
 20  travel: TravelEntity;
 21  toggleEditing: () => void;
 22}
 23
 24const MAPBOX_CONFIGURED = process.env['MAPBOX_CONFIGURED'] || false;
 25
 26const Header = (props: Props) => {
 27  const {travel, toggleEditing} = props;
 28  const theme = useTheme();
 29  const {t} = useTranslation();
 30  const {
 31    userPermissions: {canEditTravel},
 32  } = usePermissions();
 33  const {setFocusOnTravel} = useMapStore();
 34  const {userId} = useProfile();
 35  const isUserTripCreator =
 36    userId && userId === travel.attributes.user?.data?.id;
 37
 38  const passengersCount = travel?.attributes.passengers?.data.length || 0;
 39  const availableSeats = travel?.attributes.seats - passengersCount || 0;
 40
 41  return (
 42    <Box
 43      p={2}
 44      onClick={() => {
 45        setFocusOnTravel(travel);
 46        const mapElement = document?.getElementById('map');
 47        mapElement?.scrollIntoView({behavior: 'smooth'});
 48      }}
 49    >
 50      {canEditTravel(travel) && (
 51        <IconButton
 52          size="small"
 53          color="primary"
 54          sx={{
 55            position: 'absolute',
 56            top: theme.spacing(1),
 57            right: 0,
 58            margin: theme.spacing(1),
 59          }}
 60          onClick={e => {
 61            e.stopPropagation();
 62            toggleEditing();
 63          }}
 64          id="EditTravelBtn"
 65        >
 66          <TuneIcon />
 67        </IconButton>
 68      )}
 69      {!!travel.attributes.departureDate && (
 70        <Typography
 71          variant="overline"
 72          sx={{color: 'GrayText', textTransform: 'capitalize'}}
 73          id="TravelDeparture"
 74        >
 75          {moment(travel.attributes.departureDate).format('dddd LL')}{' '}
 76          {travel.attributes.departureTime}
 77        </Typography>
 78      )}
 79      <Typography variant="subtitle1">
 80        {travel.attributes.vehicleName}
 81        {isUserTripCreator && (
 82          <Typography component="span">
 83            <Chip sx={{mx: 1}} label={t`generic.me`} variant="outlined" />
 84          </Typography>
 85        )}
 86      </Typography>
 87
 88      {!!travel.attributes.phone_number && (
 89        <Box sx={{marginTop: 2}}>
 90          <Typography variant="overline" sx={{color: 'GrayText'}}>
 91            {t('travel.fields.phone')}
 92          </Typography>
 93          <Typography variant="body1" id="TravelPhone">
 94            {travel.attributes.phone_number}
 95          </Typography>
 96        </Box>
 97      )}
 98      {!!travel.attributes.meeting && (
 99        <Box sx={{marginTop: 2}}>
100          <Typography variant="overline" sx={{color: 'GrayText'}}>
101            {t('travel.fields.meeting_point')}
102          </Typography>
103          <Typography variant="body1">
104            <Link
105              component="a"
106              target="_blank"
107              rel="noopener noreferrer"
108              href={getMapsLink(travel.attributes.meeting)}
109            >
110              {travel.attributes.meeting}
111            </Link>
112          </Typography>
113          {MAPBOX_CONFIGURED && (
114            <Typography variant="overline" color="warning.main">{t`placeInput.noCoordinates`}</Typography>
115          )}
116        </Box>
117      )}
118      {!!travel.attributes.details && (
119        <Box sx={{marginTop: 2}}>
120          <Typography variant="overline" sx={{color: 'GrayText'}}>
121            {t('travel.fields.details')}
122          </Typography>
123
124          <Typography variant="body1" sx={{whiteSpace: 'pre-line'}} onClick={e => e.stopPropagation()}>
125            <Linkify options={{render: DetailsLink}}>
126              {travel.attributes.details}
127            </Linkify>
128          </Typography>
129        </Box>
130      )}
131      <LinearProgress
132        sx={{
133          width: 1,
134          mt: 2,
135          mb: 1,
136          backgroundColor: 'LightGray',
137          '& .MuiLinearProgress-bar': {
138            backgroundColor: 'Gray',
139          },
140        }}
141        value={(passengersCount / travel?.attributes.seats) * 100}
142        variant="determinate"
143      />
144      <Box display="flex" justifyContent="space-between" sx={{width: 1}}>
145        <Typography variant="body1" sx={{color: 'GrayText'}}>
146          {t('passenger.assign.seats', {count: availableSeats})}
147        </Typography>
148      </Box>
149    </Box>
150  );
151};
152
153export default Header;