frontend/containers/EventBar/index.tsx (view raw)
1import {useEffect, useState, useReducer} from 'react';
2import {useRouter} from 'next/router';
3import Link from 'next/link';
4import {makeStyles} from '@material-ui/core/styles';
5import AppBar from '@material-ui/core/AppBar';
6import Toolbar from '@material-ui/core/Toolbar';
7import Typography from '@material-ui/core/Typography';
8import IconButton from '@material-ui/core/IconButton';
9import Tooltip from '@material-ui/core/Tooltip';
10import Avatar from '@material-ui/core/Avatar';
11import Icon from '@material-ui/core/Icon';
12import clsx from 'clsx';
13import {useTranslation} from 'react-i18next';
14import useAuthStore from '../../stores/useAuthStore';
15import useEventStore from '../../stores/useEventStore';
16import useTourStore from '../../stores/useTourStore';
17import useProfile from '../../hooks/useProfile';
18import useSettings from '../../hooks/useSettings';
19import GenericMenu from '../GenericMenu';
20import EventDetails from '../EventDetails';
21
22const EventBar = ({event, onAdd, onSave, onShare}) => {
23 const {t} = useTranslation();
24 const router = useRouter();
25 const [detailsOpen, toggleDetails] = useReducer(i => !i, false);
26 const classes = useStyles({detailsOpen});
27 const [anchorEl, setAnchorEl] = useState(null);
28 const isEditing = useEventStore(s => s.isEditing);
29 const setIsEditing = useEventStore(s => s.setIsEditing);
30 const token = useAuthStore(s => s.token);
31 const {user} = useProfile();
32 const settings = useSettings();
33 const setTour = useTourStore(s => s.setTour);
34 const tourStep = useTourStore(s => s.step);
35
36 useEffect(() => {
37 onTourChange(toggleDetails);
38 }, [tourStep]);
39
40 useEffect(() => {
41 if (!detailsOpen) setIsEditing(false);
42 }, [detailsOpen]); // eslint-disable-line react-hooks/exhaustive-deps
43
44 const signUp = () =>
45 router.push({
46 pathname: '/auth/register',
47 state: {event: event?.id},
48 });
49 const signIn = () => router.push('/auth/login');
50 const goToDashboard = () => router.push('/dashboard');
51 const goProfile = () => router.push('/profile');
52
53 const onTourRestart = () => setTour({showWelcome: true});
54
55 const noUserMenuActions = [
56 {
57 label: t('event.actions.add_to_my_events'),
58 onClick: () => {
59 onAdd(true);
60 },
61 id: 'AddToMyEventsTab',
62 },
63 {divider: true},
64 {
65 label: t('menu.login'),
66 onClick: signIn,
67 id: 'SignInTab',
68 },
69 {
70 label: t('menu.register'),
71 onClick: signUp,
72 id: 'SignUpTab',
73 },
74 {divider: true},
75 {
76 label: t('menu.tour'),
77 onClick: () => {
78 setAnchorEl(null);
79 onTourRestart();
80 },
81 id: 'TourTab',
82 },
83 ];
84
85 const loggedMenuActions = [
86 {
87 label: t('menu.dashboard'),
88 onClick: goToDashboard,
89 id: 'GoToDashboardTab',
90 },
91 {
92 label: t('menu.profile'),
93 onClick: goProfile,
94 id: 'ProfileTab',
95 },
96 {divider: true},
97 {
98 label: t('menu.tour'),
99 onClick: () => {
100 setAnchorEl(null);
101 onTourRestart();
102 },
103 id: 'TourTab',
104 },
105 ];
106
107 const menuActions = token ? loggedMenuActions : noUserMenuActions;
108 const userInfos = user
109 ? [{label: user.username, id: 'Email'}, {divider: true}]
110 : [];
111
112 const UserIcon = user ? (
113 <Avatar className={classes.avatar}>
114 {`${user.username[0]}`.toUpperCase()}
115 </Avatar>
116 ) : (
117 <Icon>more_vert</Icon>
118 );
119
120 return (
121 <AppBar
122 className={classes.appbar}
123 position="static"
124 color="primary"
125 id={(isEditing && 'EditEvent') || (detailsOpen && 'Details') || 'Menu'}
126 >
127 <Toolbar>
128 <div className={classes.name}>
129 <Link href={settings?.['about_link'] || ''}>
130 <img
131 className={classes.logo}
132 src="/assets/Logo_in_beta.svg"
133 alt="Logo"
134 />
135 </Link>
136 <Tooltip title={event.name}>
137 <Typography
138 variant="h6"
139 noWrap
140 id="MenuHeaderTitle"
141 className={classes.title}
142 >
143 {event.name}
144 </Typography>
145 </Tooltip>
146
147 {detailsOpen && (
148 <IconButton
149 className="tour_event_edit"
150 color="inherit"
151 edge="end"
152 id="HeaderAction"
153 onClick={isEditing ? onSave : () => setIsEditing(true)}
154 >
155 <Icon>{isEditing ? 'done' : 'edit'}</Icon>
156 </IconButton>
157 )}
158 </div>
159 {detailsOpen ? (
160 <IconButton
161 color="inherit"
162 edge="end"
163 id="CloseDetailsBtn"
164 onClick={() => {
165 setIsEditing(false);
166 toggleDetails();
167 }}
168 >
169 <Icon>close</Icon>
170 </IconButton>
171 ) : (
172 <>
173 <IconButton
174 className={classes.shareIcon}
175 color="inherit"
176 edge="end"
177 id="ShareBtn"
178 onClick={toggleDetails}
179 >
180 <Icon>share</Icon>
181 </IconButton>
182 <IconButton
183 className={clsx(classes.iconButtons, 'tour_event_infos')}
184 color="inherit"
185 edge="end"
186 id="ShareBtn"
187 onClick={toggleDetails}
188 >
189 <Icon>information_outline</Icon>
190 </IconButton>
191 <IconButton
192 color="inherit"
193 edge="end"
194 id="MenuMoreInfo"
195 onClick={e => setAnchorEl(e.currentTarget)}
196 >
197 {UserIcon}
198 </IconButton>
199 </>
200 )}
201 {!detailsOpen && (
202 <GenericMenu
203 anchorEl={anchorEl}
204 setAnchorEl={setAnchorEl}
205 actions={[
206 ...userInfos,
207 ...[
208 {
209 label: detailsOpen
210 ? t('event.actions.hide_details')
211 : t('event.actions.show_details'),
212 onClick: e => {
213 setAnchorEl(null);
214 toggleDetails();
215 },
216 id: 'DetailsTab',
217 },
218 ],
219 ...menuActions,
220 ]}
221 />
222 )}
223 </Toolbar>
224 {detailsOpen && (
225 <EventDetails toggleDetails={toggleDetails} onShare={onShare} />
226 )}
227 </AppBar>
228 );
229};
230
231const onTourChange = (toggleDetails: Function) => {
232 const {prev, step, isCreator} = useTourStore.getState();
233 const fromTo = (step1: number, step2: number) =>
234 prev === step1 && step === step2;
235
236 if (isCreator) {
237 if (fromTo(3, 2) || fromTo(2, 3) || fromTo(4, 5)) toggleDetails();
238 } else if (fromTo(2, 3) || fromTo(3, 2) || fromTo(3, 4)) toggleDetails();
239};
240
241const useStyles = makeStyles(theme => ({
242 appbar: ({detailsOpen}) => ({
243 overflow: 'hidden',
244 height: detailsOpen ? '100vh' : theme.mixins.toolbar.minHeight,
245 overflowY: detailsOpen ? 'scroll' : 'hidden',
246 transition: 'height 0.3s ease',
247 zIndex: theme.zIndex.appBar,
248 position: 'fixed',
249 top: 0,
250 }),
251 logo: {
252 marginRight: theme.spacing(2),
253 width: 64,
254 height: 32,
255 cursor: 'pointer',
256 },
257 name: {
258 flexGrow: 1,
259 display: 'flex',
260 alignItems: 'center',
261 },
262 title: {
263 maxWidth: `calc(100vw - ${theme.spacing(30)}px)`,
264 },
265 iconButtons: {
266 margin: theme.spacing(0),
267 },
268 avatar: {
269 width: theme.spacing(3),
270 height: theme.spacing(3),
271 fontSize: 16,
272 },
273 shareIcon: {
274 marginRight: 0,
275 },
276}));
277
278export default EventBar;