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 appLink = user ? '/dashboard' : settings?.['about_link'] || '';
113
114 const UserIcon = user ? (
115 <Avatar className={classes.avatar}>
116 {`${user.username[0]}`.toUpperCase()}
117 </Avatar>
118 ) : (
119 <Icon>more_vert</Icon>
120 );
121
122 return (
123 <AppBar
124 className={classes.appbar}
125 position="static"
126 color="primary"
127 id={(isEditing && 'EditEvent') || (detailsOpen && 'Details') || 'Menu'}
128 >
129 <Toolbar>
130 <div className={classes.name}>
131 <Link href={appLink}>
132 <img
133 className={classes.logo}
134 src="/assets/Logo_in_beta.svg"
135 alt="Logo"
136 />
137 </Link>
138 <Tooltip title={event.name}>
139 <Typography
140 variant="h6"
141 noWrap
142 id="MenuHeaderTitle"
143 className={classes.title}
144 >
145 {event.name}
146 </Typography>
147 </Tooltip>
148
149 {detailsOpen && (
150 <IconButton
151 className="tour_event_edit"
152 color="inherit"
153 edge="end"
154 id="HeaderAction"
155 onClick={isEditing ? onSave : () => setIsEditing(true)}
156 >
157 <Icon>{isEditing ? 'done' : 'edit'}</Icon>
158 </IconButton>
159 )}
160 </div>
161 {detailsOpen ? (
162 <IconButton
163 color="inherit"
164 edge="end"
165 id="CloseDetailsBtn"
166 onClick={() => {
167 setIsEditing(false);
168 toggleDetails();
169 }}
170 >
171 <Icon>close</Icon>
172 </IconButton>
173 ) : (
174 <>
175 <IconButton
176 className={classes.shareIcon}
177 color="inherit"
178 edge="end"
179 id="ShareBtn"
180 onClick={toggleDetails}
181 >
182 <Icon>share</Icon>
183 </IconButton>
184 <IconButton
185 className={clsx(classes.iconButtons, 'tour_event_infos')}
186 color="inherit"
187 edge="end"
188 id="ShareBtn"
189 onClick={toggleDetails}
190 >
191 <Icon>information_outline</Icon>
192 </IconButton>
193 <IconButton
194 color="inherit"
195 edge="end"
196 id="MenuMoreInfo"
197 onClick={e => setAnchorEl(e.currentTarget)}
198 >
199 {UserIcon}
200 </IconButton>
201 </>
202 )}
203 {!detailsOpen && (
204 <GenericMenu
205 anchorEl={anchorEl}
206 setAnchorEl={setAnchorEl}
207 actions={[
208 ...userInfos,
209 ...[
210 {
211 label: detailsOpen
212 ? t('event.actions.hide_details')
213 : t('event.actions.show_details'),
214 onClick: e => {
215 setAnchorEl(null);
216 toggleDetails();
217 },
218 id: 'DetailsTab',
219 },
220 ],
221 ...menuActions,
222 ]}
223 />
224 )}
225 </Toolbar>
226 {detailsOpen && (
227 <EventDetails toggleDetails={toggleDetails} onShare={onShare} />
228 )}
229 </AppBar>
230 );
231};
232
233const onTourChange = (toggleDetails: Function) => {
234 const {prev, step, isCreator} = useTourStore.getState();
235 const fromTo = (step1: number, step2: number) =>
236 prev === step1 && step === step2;
237
238 if (isCreator) {
239 if (fromTo(3, 2) || fromTo(2, 3) || fromTo(4, 5)) toggleDetails();
240 } else if (fromTo(2, 3) || fromTo(3, 2) || fromTo(3, 4)) toggleDetails();
241};
242
243const useStyles = makeStyles(theme => ({
244 appbar: ({detailsOpen}) => ({
245 overflow: 'hidden',
246 height: detailsOpen ? '100vh' : theme.mixins.toolbar.minHeight,
247 overflowY: detailsOpen ? 'scroll' : 'hidden',
248 transition: 'height 0.3s ease',
249 zIndex: theme.zIndex.appBar,
250 position: 'fixed',
251 top: 0,
252 }),
253 logo: {
254 marginRight: theme.spacing(2),
255 width: 64,
256 height: 32,
257 cursor: 'pointer',
258 },
259 name: {
260 flexGrow: 1,
261 display: 'flex',
262 alignItems: 'center',
263 },
264 title: {
265 maxWidth: `calc(100vw - ${theme.spacing(30)}px)`,
266 },
267 iconButtons: {
268 margin: theme.spacing(0),
269 },
270 avatar: {
271 width: theme.spacing(3),
272 height: theme.spacing(3),
273 fontSize: 16,
274 },
275 shareIcon: {
276 marginRight: 0,
277 },
278}));
279
280export default EventBar;