all repos — caroster @ 392f026c797ca85247bf71cdef9b86c274532e60

[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  const tripHasValidCoordinates =
 42    travel.attributes.meeting_latitude && travel.attributes.meeting_longitude;
 43
 44  return (
 45    <Box
 46      p={2}
 47      onClick={() => {
 48        setFocusOnTravel(travel);
 49        const mapElement = document?.getElementById('map');
 50        mapElement?.scrollIntoView({behavior: 'smooth'});
 51      }}
 52    >
 53      {canEditTravel(travel) && (
 54        <IconButton
 55          size="small"
 56          color="primary"
 57          sx={{
 58            position: 'absolute',
 59            top: theme.spacing(1),
 60            right: 0,
 61            margin: theme.spacing(1),
 62          }}
 63          onClick={e => {
 64            e.stopPropagation();
 65            toggleEditing();
 66          }}
 67          id="EditTravelBtn"
 68        >
 69          <TuneIcon />
 70        </IconButton>
 71      )}
 72      {!!travel.attributes.departureDate && (
 73        <Typography
 74          variant="overline"
 75          sx={{color: 'GrayText', textTransform: 'capitalize'}}
 76          id="TravelDeparture"
 77        >
 78          {moment(travel.attributes.departureDate).format('dddd LL')}{' '}
 79          {travel.attributes.departureTime}
 80        </Typography>
 81      )}
 82      <Typography variant="subtitle1">
 83        {travel.attributes.vehicleName}
 84        {isUserTripCreator && (
 85          <Typography component="span">
 86            <Chip sx={{mx: 1}} label={t`generic.me`} variant="outlined" />
 87          </Typography>
 88        )}
 89      </Typography>
 90
 91      {!!travel.attributes.phone_number && (
 92        <Box sx={{marginTop: 2}}>
 93          <Typography variant="overline" sx={{color: 'GrayText'}}>
 94            {t('travel.fields.phone')}
 95          </Typography>
 96          <Typography variant="body1" id="TravelPhone">
 97            {travel.attributes.phone_number}
 98          </Typography>
 99        </Box>
100      )}
101      {!!travel.attributes.meeting && (
102        <Box sx={{marginTop: 2}}>
103          <Typography variant="overline" sx={{color: 'GrayText'}}>
104            {t('travel.fields.meeting_point')}
105          </Typography>
106          <Typography variant="body1">
107            <Link
108              component="a"
109              target="_blank"
110              rel="noopener noreferrer"
111              href={getMapsLink(travel.attributes.meeting)}
112            >
113              {travel.attributes.meeting}
114            </Link>
115          </Typography>
116          {MAPBOX_CONFIGURED && !tripHasValidCoordinates && (
117            <Typography
118              variant="overline"
119              color="warning.main"
120            >{t`placeInput.noCoordinates`}</Typography>
121          )}
122        </Box>
123      )}
124      {!!travel.attributes.details && (
125        <Box sx={{marginTop: 2}}>
126          <Typography variant="overline" sx={{color: 'GrayText'}}>
127            {t('travel.fields.details')}
128          </Typography>
129
130          <Typography
131            variant="body1"
132            sx={{whiteSpace: 'pre-line'}}
133            onClick={e => e.stopPropagation()}
134          >
135            <Linkify options={{render: DetailsLink}}>
136              {travel.attributes.details}
137            </Linkify>
138          </Typography>
139        </Box>
140      )}
141      <LinearProgress
142        sx={{
143          width: 1,
144          mt: 2,
145          mb: 1,
146          backgroundColor: 'LightGray',
147          '& .MuiLinearProgress-bar': {
148            backgroundColor: 'Gray',
149          },
150        }}
151        value={(passengersCount / travel?.attributes.seats) * 100}
152        variant="determinate"
153      />
154      <Box display="flex" justifyContent="space-between" sx={{width: 1}}>
155        <Typography variant="body1" sx={{color: 'GrayText'}}>
156          {t('passenger.assign.seats', {count: availableSeats})}
157        </Typography>
158      </Box>
159    </Box>
160  );
161};
162
163export default Header;