aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Tananaev <anton@traccar.org>2022-05-01 20:29:10 -0700
committerAnton Tananaev <anton@traccar.org>2022-05-01 20:29:10 -0700
commitd3bd766cbc81f51c9b13b82d0ca92ae819561ea8 (patch)
tree7f76d29ead2628b0d3c67ae8e0715b9666b30136
parentd01f563d3909582acbcfd4fe20fa271ee224aba3 (diff)
downloadtrackermap-web-d3bd766cbc81f51c9b13b82d0ca92ae819561ea8.tar.gz
trackermap-web-d3bd766cbc81f51c9b13b82d0ca92ae819561ea8.tar.bz2
trackermap-web-d3bd766cbc81f51c9b13b82d0ca92ae819561ea8.zip
Global mobile bottom menu
-rw-r--r--modern/src/App.js97
-rw-r--r--modern/src/MainPage.js19
-rw-r--r--modern/src/StartPage.js2
-rw-r--r--modern/src/components/BottomMenu.js51
4 files changed, 106 insertions, 63 deletions
diff --git a/modern/src/App.js b/modern/src/App.js
index 57e44621..a4b66ea1 100644
--- a/modern/src/App.js
+++ b/modern/src/App.js
@@ -3,7 +3,7 @@ import { ThemeProvider } from '@material-ui/core/styles';
import { Switch, Route, useHistory } from 'react-router-dom';
import CssBaseline from '@material-ui/core/CssBaseline';
import { useDispatch, useSelector } from 'react-redux';
-import { LinearProgress } from '@material-ui/core';
+import { makeStyles, LinearProgress, useMediaQuery } from '@material-ui/core';
import MainPage from './MainPage';
import RouteReportPage from './reports/RouteReportPage';
import ServerPage from './admin/ServerPage';
@@ -48,10 +48,28 @@ import { useEffectAsync } from './reactHelper';
import { devicesActions } from './store';
import EventPage from './EventPage';
import PreferencesPage from './settings/PreferencesPage';
+import BottomMenu from './components/BottomMenu';
+
+const useStyles = makeStyles((theme) => ({
+ root: {
+ display: 'flex',
+ flexDirection: 'column',
+ height: '100%',
+ },
+ page: {
+ flexGrow: 1,
+ },
+ menu: {
+ zIndex: 1,
+ },
+}));
const App = () => {
const history = useHistory();
const dispatch = useDispatch();
+ const classes = useStyles();
+
+ const desktop = useMediaQuery(theme.breakpoints.up('lg'));
const initialized = useSelector((state) => !!state.session.server && !!state.session.user);
const [redirectsHandled, setRedirectsHandled] = useState(false);
@@ -93,40 +111,49 @@ const App = () => {
<Route exact path="/reset-password" component={ResetPasswordForm} />
<Route>
{!initialized ? (<LinearProgress />) : (
- <Switch>
- <Route exact path="/" component={MainPage} />
- <Route exact path="/replay" component={ReplayPage} />
- <Route exact path="/position/:id?" component={PositionPage} />
- <Route exact path="/event/:id?" component={EventPage} />
- <Route exact path="/user/:id?" component={UserPage} />
- <Route exact path="/device/:id?" component={DevicePage} />
- <Route exact path="/geofence/:id?" component={GeofencePage} />
- <Route exact path="/geofences" component={GeofencesPage} />
- <Route exact path="/settings/preferences" component={PreferencesPage} />
- <Route exact path="/settings/notifications" component={NotificationsPage} />
- <Route exact path="/settings/notification/:id?" component={NotificationPage} />
- <Route exact path="/settings/groups" component={GroupsPage} />
- <Route exact path="/settings/group/:id?" component={GroupPage} />
- <Route exact path="/settings/drivers" component={DriversPage} />
- <Route exact path="/settings/driver/:id?" component={DriverPage} />
- <Route exact path="/settings/calendars" component={CalendarsPage} />
- <Route exact path="/settings/calendar/:id?" component={CalendarPage} />
- <Route exact path="/settings/attributes" component={ComputedAttributesPage} />
- <Route exact path="/settings/attribute/:id?" component={ComputedAttributePage} />
- <Route exact path="/settings/maintenances" component={MaintenancesPage} />
- <Route exact path="/settings/maintenance/:id?" component={MaintenancePage} />
- <Route exact path="/settings/commands" component={CommandsPage} />
- <Route exact path="/settings/command/:id?" component={CommandPage} />
- <Route exact path="/admin/server" component={ServerPage} />
- <Route exact path="/admin/users" component={UsersPage} />
- <Route exact path="/admin/statistics" component={StatisticsPage} />
- <Route exact path="/reports/route" component={RouteReportPage} />
- <Route exact path="/reports/event" component={EventReportPage} />
- <Route exact path="/reports/trip" component={TripReportPage} />
- <Route exact path="/reports/stop" component={StopReportPage} />
- <Route exact path="/reports/summary" component={SummaryReportPage} />
- <Route exact path="/reports/chart" component={ChartReportPage} />
- </Switch>
+ <div className={classes.root}>
+ <div className={classes.page}>
+ <Switch>
+ <Route exact path="/" component={MainPage} />
+ <Route exact path="/replay" component={ReplayPage} />
+ <Route exact path="/position/:id?" component={PositionPage} />
+ <Route exact path="/event/:id?" component={EventPage} />
+ <Route exact path="/user/:id?" component={UserPage} />
+ <Route exact path="/device/:id?" component={DevicePage} />
+ <Route exact path="/geofence/:id?" component={GeofencePage} />
+ <Route exact path="/geofences" component={GeofencesPage} />
+ <Route exact path="/settings/preferences" component={PreferencesPage} />
+ <Route exact path="/settings/notifications" component={NotificationsPage} />
+ <Route exact path="/settings/notification/:id?" component={NotificationPage} />
+ <Route exact path="/settings/groups" component={GroupsPage} />
+ <Route exact path="/settings/group/:id?" component={GroupPage} />
+ <Route exact path="/settings/drivers" component={DriversPage} />
+ <Route exact path="/settings/driver/:id?" component={DriverPage} />
+ <Route exact path="/settings/calendars" component={CalendarsPage} />
+ <Route exact path="/settings/calendar/:id?" component={CalendarPage} />
+ <Route exact path="/settings/attributes" component={ComputedAttributesPage} />
+ <Route exact path="/settings/attribute/:id?" component={ComputedAttributePage} />
+ <Route exact path="/settings/maintenances" component={MaintenancesPage} />
+ <Route exact path="/settings/maintenance/:id?" component={MaintenancePage} />
+ <Route exact path="/settings/commands" component={CommandsPage} />
+ <Route exact path="/settings/command/:id?" component={CommandPage} />
+ <Route exact path="/admin/server" component={ServerPage} />
+ <Route exact path="/admin/users" component={UsersPage} />
+ <Route exact path="/admin/statistics" component={StatisticsPage} />
+ <Route exact path="/reports/route" component={RouteReportPage} />
+ <Route exact path="/reports/event" component={EventReportPage} />
+ <Route exact path="/reports/trip" component={TripReportPage} />
+ <Route exact path="/reports/stop" component={StopReportPage} />
+ <Route exact path="/reports/summary" component={SummaryReportPage} />
+ <Route exact path="/reports/chart" component={ChartReportPage} />
+ </Switch>
+ </div>
+ {!desktop && (
+ <div className={classes.menu}>
+ <BottomMenu />
+ </div>
+ )}
+ </div>
)}
</Route>
</Switch>
diff --git a/modern/src/MainPage.js b/modern/src/MainPage.js
index 0f6db95a..75af9666 100644
--- a/modern/src/MainPage.js
+++ b/modern/src/MainPage.js
@@ -28,7 +28,7 @@ import { devicesActions } from './store';
const useStyles = makeStyles((theme) => ({
root: {
- height: '100vh',
+ height: '100%',
},
sidebar: {
display: 'flex',
@@ -53,9 +53,6 @@ const useStyles = makeStyles((theme) => ({
transform: 'translateX(-100vw)',
},
},
- paper: {
- zIndex: 1,
- },
toolbar: {
display: 'flex',
padding: theme.spacing(0, 1),
@@ -101,6 +98,12 @@ const useStyles = makeStyles((theme) => ({
backgroundColor: 'white',
},
},
+ bottomMenu: {
+ position: 'fixed',
+ left: theme.spacing(1.5),
+ bottom: theme.spacing(1.5),
+ width: theme.dimensions.drawerWidthDesktop,
+ },
}));
const MainPage = () => {
@@ -147,7 +150,7 @@ const MainPage = () => {
<div className={classes.sidebarToggleText}>{t('deviceTitle')}</div>
</Button>
<Paper square elevation={3} className={`${classes.sidebar} ${collapsed && classes.sidebarCollapsed}`}>
- <Paper className={classes.paper} square elevation={3}>
+ <Paper square elevation={3}>
<Toolbar className={classes.toolbar} disableGutters>
{isTablet && (
<IconButton onClick={handleClose}>
@@ -178,7 +181,11 @@ const MainPage = () => {
<DevicesList filter={searchKeyword} />
</div>
</Paper>
- <BottomMenu />
+ {!isPhone && !isTablet && (
+ <div className={classes.bottomMenu}>
+ <BottomMenu />
+ </div>
+ )}
{selectedDeviceId && (
<div className={classes.statusCard}>
<StatusCard
diff --git a/modern/src/StartPage.js b/modern/src/StartPage.js
index fcfaccca..1e672c2b 100644
--- a/modern/src/StartPage.js
+++ b/modern/src/StartPage.js
@@ -59,7 +59,7 @@ const StartPage = ({ children }) => {
<svg height="64" width="240">
<use xlinkHref="/logo.svg#img" />
</svg>
- )}
+ )}
</div>
<Paper className={classes.paper}>
<form className={classes.form}>
diff --git a/modern/src/components/BottomMenu.js b/modern/src/components/BottomMenu.js
index c43cfb96..672c969a 100644
--- a/modern/src/components/BottomMenu.js
+++ b/modern/src/components/BottomMenu.js
@@ -1,8 +1,8 @@
import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
-import { useHistory } from 'react-router-dom';
+import { useHistory, useLocation } from 'react-router-dom';
import {
- makeStyles, Paper, BottomNavigation, BottomNavigationAction, Menu, MenuItem, Typography,
+ Paper, BottomNavigation, BottomNavigationAction, Menu, MenuItem, Typography,
} from '@material-ui/core';
import DescriptionIcon from '@material-ui/icons/Description';
@@ -13,23 +13,9 @@ import PersonIcon from '@material-ui/icons/Person';
import { sessionActions } from '../store';
import { useTranslation } from '../LocalizationProvider';
-const useStyles = makeStyles((theme) => ({
- container: {
- bottom: theme.spacing(0),
- left: '0px',
- width: '100%',
- position: 'fixed',
- [theme.breakpoints.up('lg')]: {
- left: theme.spacing(1.5),
- bottom: theme.spacing(1.5),
- width: theme.dimensions.drawerWidthDesktop,
- },
- },
-}));
-
const BottomMenu = () => {
- const classes = useStyles();
const history = useHistory();
+ const location = useLocation();
const dispatch = useDispatch();
const t = useTranslation();
@@ -37,8 +23,25 @@ const BottomMenu = () => {
const [anchorEl, setAnchorEl] = useState(null);
- const handleSelection = async (event, value) => {
+ const currentSelection = () => {
+ if (location.pathname.startsWith('/user')) {
+ return 3;
+ } else if (location.pathname.startsWith('/settings')) {
+ return 2;
+ } else if (location.pathname.startsWith('/reports')) {
+ return 1;
+ } else if (location.pathname === '/') {
+ return 0;
+ } else {
+ return null;
+ }
+ }
+
+ const handleSelection = (event, value) => {
switch (value) {
+ case 0:
+ history.push('/');
+ break;
case 1:
history.push('/reports/route');
break;
@@ -53,22 +56,28 @@ const BottomMenu = () => {
}
};
+ const handleAccount = () => {
+ setAnchorEl(null);
+ history.push(`/user/${userId}`);
+ };
+
const handleLogout = async () => {
+ setAnchorEl(null);
await fetch('/api/session', { method: 'DELETE' });
history.push('/login');
dispatch(sessionActions.updateUser(null));
};
return (
- <Paper square elevation={3} className={classes.container}>
- <BottomNavigation value={0} onChange={handleSelection} showLabels>
+ <Paper square elevation={3}>
+ <BottomNavigation value={currentSelection()} onChange={handleSelection} showLabels>
<BottomNavigationAction label={t('mapTitle')} icon={<MapIcon />} />
<BottomNavigationAction label={t('reportTitle')} icon={<DescriptionIcon />} />
<BottomNavigationAction label={t('settingsTitle')} icon={<SettingsIcon />} />
<BottomNavigationAction label={t('settingsUser')} icon={<PersonIcon />} />
</BottomNavigation>
<Menu anchorEl={anchorEl} keepMounted open={Boolean(anchorEl)} onClose={() => setAnchorEl(null)}>
- <MenuItem onClick={() => history.push(`/user/${userId}`)}>
+ <MenuItem onClick={handleAccount}>
<Typography color="textPrimary">{t('settingsUser')}</Typography>
</MenuItem>
<MenuItem onClick={handleLogout}>