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