all repos — caroster @ 8a4f9e069b406ad3b9c2405dbef767b2a5304477

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