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