aboutsummaryrefslogtreecommitdiff
path: root/src/common/components/BottomMenu.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/components/BottomMenu.jsx')
-rw-r--r--src/common/components/BottomMenu.jsx135
1 files changed, 135 insertions, 0 deletions
diff --git a/src/common/components/BottomMenu.jsx b/src/common/components/BottomMenu.jsx
new file mode 100644
index 00000000..07fa2e11
--- /dev/null
+++ b/src/common/components/BottomMenu.jsx
@@ -0,0 +1,135 @@
+import React, { useState } from 'react';
+import { useDispatch, useSelector } from 'react-redux';
+import { useNavigate, useLocation } from 'react-router-dom';
+import {
+ Paper, BottomNavigation, BottomNavigationAction, Menu, MenuItem, Typography, Badge,
+} from '@mui/material';
+
+import DescriptionIcon from '@mui/icons-material/Description';
+import SettingsIcon from '@mui/icons-material/Settings';
+import MapIcon from '@mui/icons-material/Map';
+import PersonIcon from '@mui/icons-material/Person';
+import ExitToAppIcon from '@mui/icons-material/ExitToApp';
+
+import { sessionActions } from '../../store';
+import { useTranslation } from './LocalizationProvider';
+import { useRestriction } from '../util/permissions';
+import { nativePostMessage } from './NativeInterface';
+
+const BottomMenu = () => {
+ const navigate = useNavigate();
+ const location = useLocation();
+ const dispatch = useDispatch();
+ const t = useTranslation();
+
+ const readonly = useRestriction('readonly');
+ const disableReports = useRestriction('disableReports');
+ const user = useSelector((state) => state.session.user);
+ const socket = useSelector((state) => state.session.socket);
+
+ const [anchorEl, setAnchorEl] = useState(null);
+
+ const currentSelection = () => {
+ if (location.pathname === `/settings/user/${user.id}`) {
+ return 'account';
+ } if (location.pathname.startsWith('/settings')) {
+ return 'settings';
+ } if (location.pathname.startsWith('/reports')) {
+ return 'reports';
+ } if (location.pathname === '/') {
+ return 'map';
+ }
+ return null;
+ };
+
+ const handleAccount = () => {
+ setAnchorEl(null);
+ navigate(`/settings/user/${user.id}`);
+ };
+
+ const handleLogout = async () => {
+ setAnchorEl(null);
+
+ const notificationToken = window.localStorage.getItem('notificationToken');
+ if (notificationToken && !user.readonly) {
+ window.localStorage.removeItem('notificationToken');
+ const tokens = user.attributes.notificationTokens?.split(',') || [];
+ if (tokens.includes(notificationToken)) {
+ const updatedUser = {
+ ...user,
+ attributes: {
+ ...user.attributes,
+ notificationTokens: tokens.length > 1 ? tokens.filter((it) => it !== notificationToken).join(',') : undefined,
+ },
+ };
+ await fetch(`/api/users/${user.id}`, {
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(updatedUser),
+ });
+ }
+ }
+
+ await fetch('/api/session', { method: 'DELETE' });
+ nativePostMessage('logout');
+ navigate('/login');
+ dispatch(sessionActions.updateUser(null));
+ };
+
+ const handleSelection = (event, value) => {
+ switch (value) {
+ case 'map':
+ navigate('/');
+ break;
+ case 'reports':
+ navigate('/reports/combined');
+ break;
+ case 'settings':
+ navigate('/settings/preferences');
+ break;
+ case 'account':
+ setAnchorEl(event.currentTarget);
+ break;
+ case 'logout':
+ handleLogout();
+ break;
+ default:
+ break;
+ }
+ };
+
+ return (
+ <Paper square elevation={3}>
+ <BottomNavigation value={currentSelection()} onChange={handleSelection} showLabels>
+ <BottomNavigationAction
+ label={t('mapTitle')}
+ icon={(
+ <Badge color="error" variant="dot" overlap="circular" invisible={socket !== false}>
+ <MapIcon />
+ </Badge>
+ )}
+ value="map"
+ />
+ {!disableReports && (
+ <BottomNavigationAction label={t('reportTitle')} icon={<DescriptionIcon />} value="reports" />
+ )}
+ <BottomNavigationAction label={t('settingsTitle')} icon={<SettingsIcon />} value="settings" />
+ {readonly ? (
+ <BottomNavigationAction label={t('loginLogout')} icon={<ExitToAppIcon />} value="logout" />
+ ) : (
+ <BottomNavigationAction label={t('settingsUser')} icon={<PersonIcon />} value="account" />
+ )}
+ </BottomNavigation>
+ <Menu anchorEl={anchorEl} open={Boolean(anchorEl)} onClose={() => setAnchorEl(null)}>
+ <MenuItem onClick={handleAccount}>
+ <Typography color="textPrimary">{t('settingsUser')}</Typography>
+ </MenuItem>
+ <MenuItem onClick={handleLogout}>
+ <Typography color="error">{t('loginLogout')}</Typography>
+ </MenuItem>
+ </Menu>
+ </Paper>
+ );
+};
+
+export default BottomMenu;