all repos — caroster @ a440f7c732fd067d2cfa68ac51df9e0369252402

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

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

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