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 'next-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, canSeeTravelDetails},
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 && canSeeTravelDetails(travel) && (
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({
99 phone: travel.attributes.phone_number,
100 phoneCountry: travel.attributes.phoneCountry,
101 })}
102 </Typography>
103 </Box>
104 )}
105 {!!travel.attributes.meeting && (
106 <Box sx={{marginTop: 2}}>
107 <Typography variant="overline" sx={{color: 'GrayText'}}>
108 {t('travel.fields.meeting_point')}
109 </Typography>
110 <Typography variant="body1">
111 <Link
112 component="a"
113 target="_blank"
114 rel="noopener noreferrer"
115 href={getMapsLink(travel.attributes.meeting)}
116 >
117 {travel.attributes.meeting}
118 </Link>
119 </Typography>
120 {MAPBOX_CONFIGURED && !tripHasValidCoordinates && (
121 <Typography
122 variant="overline"
123 color="warning.main"
124 >{t`placeInput.noCoordinates`}</Typography>
125 )}
126 </Box>
127 )}
128 {!!travel.attributes.details && (
129 <Box sx={{marginTop: 2}}>
130 <Typography variant="overline" sx={{color: 'GrayText'}}>
131 {t('travel.fields.details')}
132 </Typography>
133
134 <Typography
135 variant="body1"
136 sx={{whiteSpace: 'pre-line'}}
137 onClick={e => e.stopPropagation()}
138 >
139 <Linkify options={{render: DetailsLink}}>
140 {travel.attributes.details}
141 </Linkify>
142 </Typography>
143 </Box>
144 )}
145 <LinearProgress
146 sx={{
147 width: 1,
148 mt: 2,
149 mb: 1,
150 backgroundColor: 'LightGray',
151 '& .MuiLinearProgress-bar': {
152 backgroundColor: 'Gray',
153 },
154 }}
155 value={(passengersCount / travel?.attributes.seats) * 100}
156 variant="determinate"
157 />
158 <Box display="flex" justifyContent="space-between" sx={{width: 1}}>
159 <Typography variant="body1" sx={{color: 'GrayText'}}>
160 {t('passenger.assign.seats', {count: availableSeats})}
161 </Typography>
162 </Box>
163 </Box>
164 );
165};
166
167export default Header;