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