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