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