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 {TravelEntity} from '../../generated/graphql';
13import usePermissions from '../../hooks/usePermissions';
14
15interface Props {
16 travel: TravelEntity;
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: {canEditTravel},
26 } = usePermissions();
27 const {setFocusOnTravel, focusedTravel} = useMapStore();
28
29 const passengersCount = travel?.attributes.passengers?.data.length || 0;
30 const availableSeats = travel?.attributes.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 {canEditTravel(travel) && (
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.attributes.departure && (
61 <Typography
62 variant="overline"
63 sx={{color: 'GrayText', textTransform: 'capitalize'}}
64 id="TravelDeparture"
65 >
66 {moment(travel.attributes.departure).format('LLLL')}
67 </Typography>
68 )}
69 <Typography variant="subtitle1">
70 {travel.attributes.vehicleName}
71 </Typography>
72 {!!travel.attributes.phone_number && (
73 <Box sx={{marginTop: 2}}>
74 <Typography variant="overline" sx={{color: 'GrayText'}}>
75 {t('travel.fields.phone')}
76 </Typography>
77 <Typography variant="body1" id="TravelPhone">
78 {travel.attributes.phone_number}
79 </Typography>
80 </Box>
81 )}
82 {!!travel.attributes.meeting && (
83 <Box sx={{marginTop: 2}}>
84 <Typography variant="overline" sx={{color: 'GrayText'}}>
85 {t('travel.fields.meeting_point')}
86 </Typography>
87 <Typography variant="body1">
88 <Link
89 component="a"
90 target="_blank"
91 rel="noopener noreferrer"
92 href={getMapsLink(travel.attributes.meeting)}
93 >
94 {travel.attributes.meeting}
95 </Link>
96 </Typography>
97 </Box>
98 )}
99 {!!travel.attributes.details && (
100 <Box sx={{marginTop: 2}}>
101 <Typography variant="overline" sx={{color: 'GrayText'}}>
102 {t('travel.fields.details')}
103 </Typography>
104 <Typography variant="body1">{travel.attributes.details}</Typography>
105 </Box>
106 )}
107 <LinearProgress
108 sx={{
109 width: 1,
110 mt: 2,
111 mb: 1,
112 backgroundColor: 'LightGray',
113 '& .MuiLinearProgress-bar': {
114 backgroundColor: 'Gray',
115 },
116 }}
117 value={(passengersCount / travel?.attributes.seats) * 100}
118 variant="determinate"
119 />
120 <Box display="flex" justifyContent="space-between" sx={{width: 1}}>
121 <Typography variant="body1" sx={{color: 'GrayText'}}>
122 {t('passenger.assign.seats', {count: availableSeats})}
123 </Typography>
124 </Box>
125 </Box>
126 );
127};
128
129export default Header;