frontend/containers/GenericToolbar/index.tsx (view raw)
1import {useState, useEffect} from 'react';
2import {useRouter} from 'next/router';
3import {makeStyles} from '@material-ui/core/styles';
4import AppBar from '@material-ui/core/AppBar';
5import Toolbar from '@material-ui/core/Toolbar';
6import Typography from '@material-ui/core/Typography';
7import IconButton from '@material-ui/core/IconButton';
8import Avatar from '@material-ui/core/Avatar';
9import Icon from '@material-ui/core/Icon';
10import useProfile from '../../hooks/useProfile';
11import GenericMenu from '../GenericMenu';
12import {ActionType} from '../GenericMenu/Action';
13import useBannerStore from '../../stores/useBannerStore';
14import Banner from '../../components/Banner';
15import useSettings from '../../hooks/useSettings';
16
17let persistedLastAnnouncementSeen = '';
18if (typeof localStorage !== 'undefined') {
19 persistedLastAnnouncementSeen = localStorage.getItem('lastAnnouncementSeen');
20}
21
22const GenericToolbar = ({
23 title,
24 actions = [],
25 goBack = null,
26}: {
27 title: string;
28 actions: Array<ActionType>;
29 goBack: () => void | null;
30}) => {
31 const router = useRouter();
32 const [anchorEl, setAnchorEl] = useState(null);
33 const bannerOffset = useBannerStore(s => s.offset);
34 const bannerHeight = useBannerStore(s => s.height);
35 const classes = useStyles({bannerOffset, bannerHeight});
36 const {user} = useProfile();
37 const settings = useSettings();
38 const announcement = settings?.announcement || '';
39 const [lastAnnouncementSeen, setLastAnnouncementSeen] = useState(
40 persistedLastAnnouncementSeen
41 );
42 const showAnnouncement =
43 announcement !== '' && announcement !== lastAnnouncementSeen;
44
45 const onBannerClear = () => {
46 if (typeof announcement != 'undefined') {
47 localStorage.setItem('lastAnnouncementSeen', String(announcement));
48 }
49 setLastAnnouncementSeen(announcement);
50 };
51
52 const userInfos = user
53 ? [{label: user.username, id: 'Email'}, {divider: true}]
54 : [];
55
56 useEffect(() => {
57 window.scrollTo(0, 0);
58 }, []);
59
60 return (
61 <AppBar
62 position="fixed"
63 color="primary"
64 className={classes.appbar}
65 id="Menu"
66 >
67 <Banner
68 message={announcement}
69 open={showAnnouncement}
70 onClear={onBannerClear}
71 />
72 <Toolbar>
73 {goBack && (
74 <IconButton
75 edge="start"
76 className={classes.goBack}
77 onClick={() =>
78 router.basePath.split('/').length > 2
79 ? router.back()
80 : router.push('/dashboard')
81 }
82 >
83 <Icon>arrow_back</Icon>
84 </IconButton>
85 )}
86 <div className={classes.name}>
87 <Typography variant="h6" noWrap id="MenuHeaderTitle">
88 {title}
89 </Typography>
90 </div>
91 {actions.length > 0 && (
92 <>
93 <IconButton
94 color="inherit"
95 edge="end"
96 id="MenuMoreInfo"
97 onClick={e => setAnchorEl(e.currentTarget)}
98 >
99 {user ? (
100 <Avatar className={classes.avatar}>
101 {`${user.username[0]}`.toUpperCase()}
102 </Avatar>
103 ) : (
104 <Icon>more_vert</Icon>
105 )}
106 </IconButton>
107
108 <GenericMenu
109 anchorEl={anchorEl}
110 setAnchorEl={setAnchorEl}
111 actions={[...userInfos, ...actions, {divider: true}]}
112 />
113 </>
114 )}
115 </Toolbar>
116 </AppBar>
117 );
118};
119
120const useStyles = makeStyles(theme => ({
121 appbar: ({bannerHeight, bannerOffset}) => ({
122 minHeight: theme.mixins.toolbar.minHeight,
123 transition: 'height 0.3s ease',
124 zIndex: theme.zIndex.appBar,
125 display: 'block',
126 marginTop: bannerOffset - bannerHeight,
127 }),
128 name: {
129 flexGrow: 1,
130 display: 'flex',
131 alignItems: 'center',
132 },
133 avatar: {
134 width: theme.spacing(3),
135 height: theme.spacing(3),
136 fontSize: 16,
137 },
138 goBack: {
139 color: theme.palette.common.white,
140 },
141}));
142
143export default GenericToolbar;