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