diff options
23 files changed, 242 insertions, 228 deletions
diff --git a/modern/package.json b/modern/package.json index b1422f44..89b0a6f9 100644 --- a/modern/package.json +++ b/modern/package.json @@ -18,8 +18,8 @@ "moment": "^2.29.3", "react": "^17.0.2", "react-dom": "^17.0.2", - "react-redux": "^7.2.4", - "react-router-dom": "^5.2.0", + "react-redux": "^8.0.2", + "react-router-dom": "^6.3.0", "react-scripts": "^3.4.4", "react-virtualized-auto-sizer": "^1.0.5", "react-window": "^1.8.6", diff --git a/modern/src/App.js b/modern/src/App.js index fee94e5b..84459cd5 100644 --- a/modern/src/App.js +++ b/modern/src/App.js @@ -1,56 +1,9 @@ -import React, { useState } from 'react'; -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 React from 'react'; +import { Outlet } from 'react-router-dom'; +import { useSelector } from 'react-redux'; import { makeStyles, LinearProgress, useMediaQuery } from '@material-ui/core'; -import MainPage from './main/MainPage'; -import RouteReportPage from './reports/RouteReportPage'; -import ServerPage from './settings/ServerPage'; -import UsersPage from './settings/UsersPage'; -import DevicePage from './settings/DevicePage'; -import UserPage from './settings/UserPage'; -import SocketController from './SocketController'; -import NotificationsPage from './settings/NotificationsPage'; -import NotificationPage from './settings/NotificationPage'; -import GroupsPage from './settings/GroupsPage'; -import GroupPage from './settings/GroupPage'; -import PositionPage from './other/PositionPage'; -import EventReportPage from './reports/EventReportPage'; -import ReplayPage from './other/ReplayPage'; -import TripReportPage from './reports/TripReportPage'; -import StopReportPage from './reports/StopReportPage'; -import SummaryReportPage from './reports/SummaryReportPage'; -import ChartReportPage from './reports/ChartReportPage'; -import DriversPage from './settings/DriversPage'; -import DriverPage from './settings/DriverPage'; -import CalendarsPage from './settings/CalendarsPage'; -import CalendarPage from './settings/CalendarPage'; -import ComputedAttributesPage from './settings/ComputedAttributesPage'; -import ComputedAttributePage from './settings/ComputedAttributePage'; -import MaintenancesPage from './settings/MaintenancesPage'; -import MaintenancePage from './settings/MaintenancePage'; -import CommandsPage from './settings/CommandsPage'; -import CommandPage from './settings/CommandPage'; -import StatisticsPage from './reports/StatisticsPage'; -import CachingController from './CachingController'; - -import LoginPage from './login/LoginPage'; -import RegisterPage from './login/RegisterPage'; -import ResetPasswordPage from './login/ResetPasswordPage'; - import theme from './common/theme'; -import GeofencesPage from './other/GeofencesPage'; -import GeofencePage from './settings/GeofencePage'; -import useQuery from './common/util/useQuery'; -import { useEffectAsync } from './reactHelper'; -import { devicesActions } from './store'; -import EventPage from './other/EventPage'; -import PreferencesPage from './settings/PreferencesPage'; import BottomMenu from './common/components/BottomMenu'; -import AccumulatorsPage from './settings/AccumulatorsPage'; -import CommandSendPage from './settings/CommandSendPage'; -import ErrorHandler from './common/components/ErrorHandler'; const useStyles = makeStyles(() => ({ page: { @@ -63,107 +16,27 @@ const useStyles = makeStyles(() => ({ })); const App = () => { - const history = useHistory(); - const dispatch = useDispatch(); const classes = useStyles(); const desktop = useMediaQuery(theme.breakpoints.up('md')); const initialized = useSelector((state) => !!state.session.server && !!state.session.user); - const [redirectsHandled, setRedirectsHandled] = useState(false); - - const query = useQuery(); - - useEffectAsync(async () => { - if (query.get('token')) { - const token = query.get('token'); - await fetch(`/api/session?token=${encodeURIComponent(token)}`); - history.push('/'); - } else if (query.get('deviceId')) { - const deviceId = query.get('deviceId'); - const response = await fetch(`/api/devices?uniqueId=${deviceId}`); - if (response.ok) { - const items = await response.json(); - if (items.length > 0) { - dispatch(devicesActions.select(items[0].id)); - } - } else { - throw Error(await response.text()); - } - history.push('/'); - } else if (query.get('eventId')) { - const eventId = parseInt(query.get('eventId'), 10); - history.push(`/event/${eventId}`); - } else { - setRedirectsHandled(true); - } - }, [query]); - - return (!redirectsHandled ? (<LinearProgress />) : ( - <ThemeProvider theme={theme}> - <CssBaseline /> - <SocketController /> - <CachingController /> - <Switch> - <Route exact path="/login" component={LoginPage} /> - <Route exact path="/register" component={RegisterPage} /> - <Route exact path="/reset-password" component={ResetPasswordPage} /> - <Route> - {!initialized ? (<LinearProgress />) : ( - <> - <div className={classes.page}> - <Switch> - <Route exact path="/" component={MainPage} /> - - <Route exact path="/position/:id?" component={PositionPage} /> - <Route exact path="/event/:id?" component={EventPage} /> - <Route exact path="/replay" component={ReplayPage} /> - <Route exact path="/geofences" component={GeofencesPage} /> - - <Route exact path="/settings/accumulators/:deviceId?" component={AccumulatorsPage} /> - <Route exact path="/settings/calendars" component={CalendarsPage} /> - <Route exact path="/settings/calendar/:id?" component={CalendarPage} /> - <Route exact path="/settings/commands" component={CommandsPage} /> - <Route exact path="/settings/command/:id?" component={CommandPage} /> - <Route exact path="/settings/command-send/:deviceId?" component={CommandSendPage} /> - <Route exact path="/settings/attributes" component={ComputedAttributesPage} /> - <Route exact path="/settings/attribute/:id?" component={ComputedAttributePage} /> - <Route exact path="/settings/device/:id?" component={DevicePage} /> - <Route exact path="/settings/drivers" component={DriversPage} /> - <Route exact path="/settings/driver/:id?" component={DriverPage} /> - <Route exact path="/settings/geofence/:id?" component={GeofencePage} /> - <Route exact path="/settings/groups" component={GroupsPage} /> - <Route exact path="/settings/group/:id?" component={GroupPage} /> - <Route exact path="/settings/maintenances" component={MaintenancesPage} /> - <Route exact path="/settings/maintenance/:id?" component={MaintenancePage} /> - <Route exact path="/settings/notifications" component={NotificationsPage} /> - <Route exact path="/settings/notification/:id?" component={NotificationPage} /> - <Route exact path="/settings/preferences" component={PreferencesPage} /> - <Route exact path="/settings/server" component={ServerPage} /> - <Route exact path="/settings/users" component={UsersPage} /> - <Route exact path="/settings/user/:id?" component={UserPage} /> - <Route exact path="/reports/chart" component={ChartReportPage} /> - <Route exact path="/reports/event" component={EventReportPage} /> - <Route exact path="/reports/route" component={RouteReportPage} /> - <Route exact path="/reports/statistics" component={StatisticsPage} /> - <Route exact path="/reports/stop" component={StopReportPage} /> - <Route exact path="/reports/summary" component={SummaryReportPage} /> - <Route exact path="/reports/trip" component={TripReportPage} /> - </Switch> - </div> - {!desktop && ( - <div className={classes.menu}> - <BottomMenu /> - </div> - )} - </> - )} - </Route> - </Switch> - <ErrorHandler /> - </ThemeProvider> - )); + if (!initialized) { + return (<LinearProgress />); + } + return ( + <> + <div className={classes.page}> + <Outlet /> + </div> + {!desktop && ( + <div className={classes.menu}> + <BottomMenu /> + </div> + )} + </> + ); }; export default App; diff --git a/modern/src/Navigation.js b/modern/src/Navigation.js new file mode 100644 index 00000000..a538029b --- /dev/null +++ b/modern/src/Navigation.js @@ -0,0 +1,131 @@ +import React, { useState } from 'react'; +import { Route, Routes, useNavigate } from 'react-router-dom'; +import { useDispatch } from 'react-redux'; +import { LinearProgress } from '@material-ui/core'; +import MainPage from './main/MainPage'; +import RouteReportPage from './reports/RouteReportPage'; +import ServerPage from './settings/ServerPage'; +import UsersPage from './settings/UsersPage'; +import DevicePage from './settings/DevicePage'; +import UserPage from './settings/UserPage'; +import NotificationsPage from './settings/NotificationsPage'; +import NotificationPage from './settings/NotificationPage'; +import GroupsPage from './settings/GroupsPage'; +import GroupPage from './settings/GroupPage'; +import PositionPage from './other/PositionPage'; +import EventReportPage from './reports/EventReportPage'; +import ReplayPage from './other/ReplayPage'; +import TripReportPage from './reports/TripReportPage'; +import StopReportPage from './reports/StopReportPage'; +import SummaryReportPage from './reports/SummaryReportPage'; +import ChartReportPage from './reports/ChartReportPage'; +import DriversPage from './settings/DriversPage'; +import DriverPage from './settings/DriverPage'; +import CalendarsPage from './settings/CalendarsPage'; +import CalendarPage from './settings/CalendarPage'; +import ComputedAttributesPage from './settings/ComputedAttributesPage'; +import ComputedAttributePage from './settings/ComputedAttributePage'; +import MaintenancesPage from './settings/MaintenancesPage'; +import MaintenancePage from './settings/MaintenancePage'; +import CommandsPage from './settings/CommandsPage'; +import CommandPage from './settings/CommandPage'; +import StatisticsPage from './reports/StatisticsPage'; +import LoginPage from './login/LoginPage'; +import RegisterPage from './login/RegisterPage'; +import ResetPasswordPage from './login/ResetPasswordPage'; +import GeofencesPage from './other/GeofencesPage'; +import GeofencePage from './settings/GeofencePage'; +import useQuery from './common/util/useQuery'; +import { useEffectAsync } from './reactHelper'; +import { devicesActions } from './store'; +import EventPage from './other/EventPage'; +import PreferencesPage from './settings/PreferencesPage'; +import AccumulatorsPage from './settings/AccumulatorsPage'; +import CommandSendPage from './settings/CommandSendPage'; +import App from './App'; + +const Navigation = () => { + const navigate = useNavigate(); + const dispatch = useDispatch(); + + const [redirectsHandled, setRedirectsHandled] = useState(false); + + const query = useQuery(); + + useEffectAsync(async () => { + if (query.get('token')) { + const token = query.get('token'); + await fetch(`/api/session?token=${encodeURIComponent(token)}`); + navigate('/'); + } else if (query.get('deviceId')) { + const deviceId = query.get('deviceId'); + const response = await fetch(`/api/devices?uniqueId=${deviceId}`); + if (response.ok) { + const items = await response.json(); + if (items.length > 0) { + dispatch(devicesActions.select(items[0].id)); + } + } else { + throw Error(await response.text()); + } + navigate('/'); + } else if (query.get('eventId')) { + const eventId = parseInt(query.get('eventId'), 10); + navigate(`/event/${eventId}`); + } else { + setRedirectsHandled(true); + } + }, [query]); + + if (!redirectsHandled) { + return (<LinearProgress />); + } + return ( + <Routes> + <Route path="/login" element={<LoginPage />} /> + <Route path="/register" element={<RegisterPage />} /> + <Route path="/reset-password" element={<ResetPasswordPage />} /> + <Route path="/" element={<App />}> + <Route index element={<MainPage />} /> + + <Route path="/position/:id?" element={<PositionPage />} /> + <Route path="/event/:id?" element={<EventPage />} /> + <Route path="/replay" element={<ReplayPage />} /> + <Route path="/geofences" element={<GeofencesPage />} /> + + <Route path="/settings/accumulators/:deviceId?" element={<AccumulatorsPage />} /> + <Route path="/settings/calendars" element={<CalendarsPage />} /> + <Route path="/settings/calendar/:id?" element={<CalendarPage />} /> + <Route path="/settings/commands" element={<CommandsPage />} /> + <Route path="/settings/command/:id?" element={<CommandPage />} /> + <Route path="/settings/command-send/:deviceId?" element={<CommandSendPage />} /> + <Route path="/settings/attributes" element={<ComputedAttributesPage />} /> + <Route path="/settings/attribute/:id?" element={<ComputedAttributePage />} /> + <Route path="/settings/device/:id?" element={<DevicePage />} /> + <Route path="/settings/drivers" element={<DriversPage />} /> + <Route path="/settings/driver/:id?" element={<DriverPage />} /> + <Route path="/settings/geofence/:id?" element={<GeofencePage />} /> + <Route path="/settings/groups" element={<GroupsPage />} /> + <Route path="/settings/group/:id?" element={<GroupPage />} /> + <Route path="/settings/maintenances" element={<MaintenancesPage />} /> + <Route path="/settings/maintenance/:id?" element={<MaintenancePage />} /> + <Route path="/settings/notifications" element={<NotificationsPage />} /> + <Route path="/settings/notification/:id?" element={<NotificationPage />} /> + <Route path="/settings/preferences" element={<PreferencesPage />} /> + <Route path="/settings/server" element={<ServerPage />} /> + <Route path="/settings/users" element={<UsersPage />} /> + <Route path="/settings/user/:id?" element={<UserPage />} /> + + <Route path="/reports/chart" element={<ChartReportPage />} /> + <Route path="/reports/event" element={<EventReportPage />} /> + <Route path="/reports/route" element={<RouteReportPage />} /> + <Route path="/reports/statistics" element={<StatisticsPage />} /> + <Route path="/reports/stop" element={<StopReportPage />} /> + <Route path="/reports/summary" element={<SummaryReportPage />} /> + <Route path="/reports/trip" element={<TripReportPage />} /> + </Route> + </Routes> + ); +}; + +export default Navigation; diff --git a/modern/src/SocketController.js b/modern/src/SocketController.js index 9826d4b1..f776ebc7 100644 --- a/modern/src/SocketController.js +++ b/modern/src/SocketController.js @@ -1,7 +1,7 @@ import React, { useEffect, useRef, useState } from 'react'; import { useDispatch, useSelector, connect } from 'react-redux'; import { Snackbar } from '@material-ui/core'; -import { useHistory } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import { positionsActions, devicesActions, sessionActions } from './store'; import { useEffectAsync } from './reactHelper'; @@ -11,7 +11,7 @@ import { snackBarDurationLongMs } from './common/util/duration'; const SocketController = () => { const dispatch = useDispatch(); - const history = useHistory(); + const navigate = useNavigate(); const t = useTranslation(); const authenticated = useSelector((state) => !!state.session.user); @@ -74,7 +74,7 @@ const SocketController = () => { if (response.ok) { dispatch(sessionActions.updateUser(await response.json())); } else { - history.push('/login'); + navigate('/login'); } return null; }, [authenticated]); diff --git a/modern/src/common/components/BottomMenu.js b/modern/src/common/components/BottomMenu.js index 30960396..7db4dff8 100644 --- a/modern/src/common/components/BottomMenu.js +++ b/modern/src/common/components/BottomMenu.js @@ -1,6 +1,6 @@ import React, { useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { useHistory, useLocation } from 'react-router-dom'; +import { useNavigate, useLocation } from 'react-router-dom'; import { Paper, BottomNavigation, BottomNavigationAction, Menu, MenuItem, Typography, } from '@material-ui/core'; @@ -16,7 +16,7 @@ import { useTranslation } from './LocalizationProvider'; import { useReadonly } from '../util/permissions'; const BottomMenu = () => { - const history = useHistory(); + const navigate = useNavigate(); const location = useLocation(); const dispatch = useDispatch(); const t = useTranslation(); @@ -41,26 +41,26 @@ const BottomMenu = () => { const handleAccount = () => { setAnchorEl(null); - history.push(`/settings/user/${userId}`); + navigate(`/settings/user/${userId}`); }; const handleLogout = async () => { setAnchorEl(null); await fetch('/api/session', { method: 'DELETE' }); - history.push('/login'); + navigate('/login'); dispatch(sessionActions.updateUser(null)); }; const handleSelection = (event, value) => { switch (value) { case 0: - history.push('/'); + navigate('/'); break; case 1: - history.push('/reports/route'); + navigate('/reports/route'); break; case 2: - history.push('/settings/preferences'); + navigate('/settings/preferences'); break; case 3: if (readonly) { diff --git a/modern/src/common/components/PageLayout.js b/modern/src/common/components/PageLayout.js index a1f117c4..d92b71c3 100644 --- a/modern/src/common/components/PageLayout.js +++ b/modern/src/common/components/PageLayout.js @@ -4,7 +4,7 @@ import { } from '@material-ui/core'; import ArrowBackIcon from '@material-ui/icons/ArrowBack'; import MenuIcon from '@material-ui/icons/Menu'; -import { useHistory } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import { useTranslation } from './LocalizationProvider'; const useStyles = makeStyles((theme) => ({ @@ -56,7 +56,7 @@ const PageTitle = ({ breadcrumbs }) => { const PageLayout = ({ menu, breadcrumbs, children }) => { const classes = useStyles(); - const history = useHistory(); + const navigate = useNavigate(); const [openDrawer, setOpenDrawer] = useState(false); @@ -71,7 +71,7 @@ const PageLayout = ({ menu, breadcrumbs, children }) => { > <div className={classes.toolbar}> <Toolbar> - <IconButton color="inherit" edge="start" onClick={() => history.push('/')}> + <IconButton color="inherit" edge="start" onClick={() => navigate('/')}> <ArrowBackIcon /> </IconButton> <PageTitle breadcrumbs={breadcrumbs} /> diff --git a/modern/src/index.js b/modern/src/index.js index 43462d35..07ac7e3f 100644 --- a/modern/src/index.js +++ b/modern/src/index.js @@ -3,21 +3,31 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { BrowserRouter } from 'react-router-dom'; import { Provider } from 'react-redux'; - -import App from './App'; +import { CssBaseline, ThemeProvider } from '@material-ui/core'; import * as serviceWorker from './serviceWorker'; import store from './store'; import { LocalizationProvider } from './common/components/LocalizationProvider'; +import ErrorHandler from './common/components/ErrorHandler'; +import CachingController from './CachingController'; +import SocketController from './SocketController'; +import theme from './common/theme'; +import Navigation from './Navigation'; -const base = window.location.href.indexOf('modern') >= 0 ? '/modern' : null; +const base = window.location.href.indexOf('modern') >= 0 ? '/modern' : '/'; ReactDOM.render( ( <Provider store={store}> <LocalizationProvider> - <BrowserRouter basename={base}> - <App /> - </BrowserRouter> + <ThemeProvider theme={theme}> + <CssBaseline /> + <BrowserRouter basename={base}> + <SocketController /> + <CachingController /> + <Navigation /> + </BrowserRouter> + <ErrorHandler /> + </ThemeProvider> </LocalizationProvider> </Provider> ), document.getElementById('root'), diff --git a/modern/src/login/LoginPage.js b/modern/src/login/LoginPage.js index 5b690cdc..2a911b84 100644 --- a/modern/src/login/LoginPage.js +++ b/modern/src/login/LoginPage.js @@ -6,7 +6,7 @@ import CloseIcon from '@material-ui/icons/Close'; import CachedIcon from '@material-ui/icons/Cached'; import { useTheme } from '@material-ui/core/styles'; import { useDispatch, useSelector } from 'react-redux'; -import { useHistory } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import { sessionActions } from '../store'; import { useLocalization, useTranslation } from '../common/components/LocalizationProvider'; import LoginLayout from './LoginLayout'; @@ -30,7 +30,7 @@ const useStyles = makeStyles((theme) => ({ const LoginPage = () => { const classes = useStyles(); const dispatch = useDispatch(); - const history = useHistory(); + const navigate = useNavigate(); const theme = useTheme(); const t = useTranslation(); @@ -58,7 +58,7 @@ const LoginPage = () => { if (response.ok) { const user = await response.json(); dispatch(sessionActions.updateUser(user)); - history.push('/'); + navigate('/'); } else { throw Error(await response.text()); } @@ -136,7 +136,7 @@ const LoginPage = () => { </Grid> <Grid item container spacing={2}> <Grid item> - <Button onClick={() => history.push('/register')} disabled={!registrationEnabled} color="secondary"> + <Button onClick={() => navigate('/register')} disabled={!registrationEnabled} color="secondary"> {t('loginRegister')} </Button> </Grid> @@ -152,7 +152,7 @@ const LoginPage = () => { {emailEnabled && ( <Grid item container justifyContent="flex-end"> <Grid item> - <Link onClick={() => history.push('/reset-password')} className={classes.resetPassword} underline="none">{t('loginReset')}</Link> + <Link onClick={() => navigate('/reset-password')} className={classes.resetPassword} underline="none">{t('loginReset')}</Link> </Grid> </Grid> )} diff --git a/modern/src/login/RegisterPage.js b/modern/src/login/RegisterPage.js index 78728b58..5fa061bb 100644 --- a/modern/src/login/RegisterPage.js +++ b/modern/src/login/RegisterPage.js @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import { Grid, Button, TextField, Typography, Link, makeStyles, Snackbar, } from '@material-ui/core'; -import { useHistory } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import ArrowBackIcon from '@material-ui/icons/ArrowBack'; import LoginLayout from './LoginLayout'; import { useTranslation } from '../common/components/LocalizationProvider'; @@ -26,7 +26,7 @@ const useStyles = makeStyles((theme) => ({ const RegisterPage = () => { const classes = useStyles(); - const history = useHistory(); + const navigate = useNavigate(); const t = useTranslation(); const [name, setName] = useState(''); @@ -51,7 +51,7 @@ const RegisterPage = () => { <LoginLayout> <Snackbar open={snackbarOpen} - onClose={() => history.push('/login')} + onClose={() => navigate('/login')} autoHideDuration={snackBarDurationShortMs} message={t('loginCreated')} /> @@ -59,7 +59,7 @@ const RegisterPage = () => { <Grid container item> <Grid item> <Typography className={classes.link} color="primary"> - <Link onClick={() => history.push('/login')}> + <Link onClick={() => navigate('/login')}> <ArrowBackIcon /> </Link> </Typography> diff --git a/modern/src/login/ResetPasswordPage.js b/modern/src/login/ResetPasswordPage.js index 93e154e3..acdf13ab 100644 --- a/modern/src/login/ResetPasswordPage.js +++ b/modern/src/login/ResetPasswordPage.js @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import { Grid, Button, TextField, Typography, Link, makeStyles, Snackbar, } from '@material-ui/core'; -import { useHistory } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import ArrowBackIcon from '@material-ui/icons/ArrowBack'; import LoginLayout from './LoginLayout'; import { useTranslation } from '../common/components/LocalizationProvider'; @@ -27,7 +27,7 @@ const useStyles = makeStyles((theme) => ({ const ResetPasswordPage = () => { const classes = useStyles(); - const history = useHistory(); + const navigate = useNavigate(); const t = useTranslation(); const query = useQuery(); @@ -62,7 +62,7 @@ const ResetPasswordPage = () => { <LoginLayout> <Snackbar open={snackbarOpen} - onClose={() => history.push('/login')} + onClose={() => navigate('/login')} autoHideDuration={snackBarDurationShortMs} message={!token ? t('loginResetSuccess') : t('loginUpdateSuccess')} /> @@ -70,7 +70,7 @@ const ResetPasswordPage = () => { <Grid container item> <Grid item> <Typography className={classes.link} color="primary"> - <Link onClick={() => history.push('/login')}> + <Link onClick={() => navigate('/login')}> <ArrowBackIcon /> </Link> </Typography> diff --git a/modern/src/main/MainPage.js b/modern/src/main/MainPage.js index 61c10d81..346919e2 100644 --- a/modern/src/main/MainPage.js +++ b/modern/src/main/MainPage.js @@ -1,5 +1,5 @@ import React, { useState, useEffect } from 'react'; -import { useHistory } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import { makeStyles, Paper, Toolbar, TextField, IconButton, Button, } from '@material-ui/core'; @@ -115,7 +115,7 @@ const useStyles = makeStyles((theme) => ({ const MainPage = () => { const classes = useStyles(); - const history = useHistory(); + const navigate = useNavigate(); const dispatch = useDispatch(); const theme = useTheme(); const t = useTranslation(); @@ -178,7 +178,7 @@ const MainPage = () => { placeholder={t('sharedSearchDevices')} variant="filled" /> - <IconButton onClick={() => history.push('/settings/device')} disabled={deviceReadonly}> + <IconButton onClick={() => navigate('/settings/device')} disabled={deviceReadonly}> <AddIcon /> </IconButton> {desktop && ( diff --git a/modern/src/main/StatusCard.js b/modern/src/main/StatusCard.js index d23bc8c3..92db8047 100644 --- a/modern/src/main/StatusCard.js +++ b/modern/src/main/StatusCard.js @@ -1,6 +1,6 @@ import React, { useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { useHistory } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import { makeStyles, Card, CardContent, Typography, CardActions, CardHeader, IconButton, Avatar, Table, TableBody, TableRow, TableCell, TableContainer, } from '@material-ui/core'; @@ -65,7 +65,7 @@ const StatusRow = ({ name, content }) => { const StatusCard = ({ deviceId, onClose }) => { const classes = useStyles(); - const history = useHistory(); + const navigate = useNavigate(); const dispatch = useDispatch(); const t = useTranslation(); @@ -134,16 +134,16 @@ const StatusCard = ({ deviceId, onClose }) => { </CardContent> )} <CardActions classes={{ root: classes.actions }} disableSpacing> - <IconButton onClick={() => history.push(`/position/${position.id}`)} disabled={!position} color="secondary"> + <IconButton onClick={() => navigate(`/position/${position.id}`)} disabled={!position} color="secondary"> <PostAddIcon /> </IconButton> - <IconButton onClick={() => history.push('/replay')} disabled={!position}> + <IconButton onClick={() => navigate('/replay')} disabled={!position}> <ReplayIcon /> </IconButton> - <IconButton onClick={() => history.push(`/settings/command-send/${deviceId}`)} disabled={readonly}> + <IconButton onClick={() => navigate(`/settings/command-send/${deviceId}`)} disabled={readonly}> <PublishIcon /> </IconButton> - <IconButton onClick={() => history.push(`/settings/device/${deviceId}`)} disabled={deviceReadonly}> + <IconButton onClick={() => navigate(`/settings/device/${deviceId}`)} disabled={deviceReadonly}> <EditIcon /> </IconButton> <IconButton onClick={() => setRemoving(true)} disabled={deviceReadonly} className={classes.negative}> diff --git a/modern/src/map/MapGeofenceEdit.js b/modern/src/map/MapGeofenceEdit.js index c64eb736..0b5062d8 100644 --- a/modern/src/map/MapGeofenceEdit.js +++ b/modern/src/map/MapGeofenceEdit.js @@ -5,7 +5,7 @@ import theme from '@mapbox/mapbox-gl-draw/src/lib/theme'; import { useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { useHistory } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import { map } from './core/Map'; import { geofenceToFeature, geometryToArea } from './core/mapUtil'; import { errorsActions, geofencesActions } from '../store'; @@ -36,7 +36,7 @@ const draw = new MapboxDraw({ const MapGeofenceEdit = () => { const dispatch = useDispatch(); - const history = useHistory(); + const navigate = useNavigate(); const geofences = useSelector((state) => state.geofences.items); @@ -69,7 +69,7 @@ const MapGeofenceEdit = () => { }); if (response.ok) { const item = await response.json(); - history.push(`/settings/geofence/${item.id}`); + navigate(`/settings/geofence/${item.id}`); } else { throw Error(await response.text()); } @@ -80,7 +80,7 @@ const MapGeofenceEdit = () => { map.on('draw.create', listener); return () => map.off('draw.create', listener); - }, [dispatch, history]); + }, [dispatch, navigate]); useEffect(() => { const listener = async (event) => { diff --git a/modern/src/other/EventPage.js b/modern/src/other/EventPage.js index c688e62a..9f5f7c84 100644 --- a/modern/src/other/EventPage.js +++ b/modern/src/other/EventPage.js @@ -4,7 +4,7 @@ import { makeStyles, Typography, AppBar, Toolbar, IconButton, } from '@material-ui/core'; import ArrowBackIcon from '@material-ui/icons/ArrowBack'; -import { useHistory, useParams } from 'react-router-dom'; +import { useNavigate, useParams } from 'react-router-dom'; import { useEffectAsync } from '../reactHelper'; import { useTranslation } from '../common/components/LocalizationProvider'; import Map from '../map/core/Map'; @@ -23,7 +23,7 @@ const useStyles = makeStyles(() => ({ const EventPage = () => { const classes = useStyles(); - const history = useHistory(); + const navigate = useNavigate(); const t = useTranslation(); const { id } = useParams(); @@ -60,7 +60,7 @@ const EventPage = () => { <div className={classes.root}> <AppBar color="inherit" position="static"> <Toolbar> - <IconButton color="inherit" edge="start" onClick={() => history.push('/')}> + <IconButton color="inherit" edge="start" onClick={() => navigate('/')}> <ArrowBackIcon /> </IconButton> <Typography variant="h6">{t('positionEvent')}</Typography> diff --git a/modern/src/other/GeofencesPage.js b/modern/src/other/GeofencesPage.js index 98833cc7..80e23cba 100644 --- a/modern/src/other/GeofencesPage.js +++ b/modern/src/other/GeofencesPage.js @@ -5,7 +5,7 @@ import { import { useTheme } from '@material-ui/core/styles'; import Drawer from '@material-ui/core/Drawer'; import ArrowBackIcon from '@material-ui/icons/ArrowBack'; -import { useHistory } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import Map from '../map/core/Map'; import MapCurrentLocation from '../map/MapCurrentLocation'; import MapGeofenceEdit from '../map/MapGeofenceEdit'; @@ -51,7 +51,7 @@ const useStyles = makeStyles((theme) => ({ const GeofencesPage = () => { const theme = useTheme(); const classes = useStyles(); - const history = useHistory(); + const navigate = useNavigate(); const t = useTranslation(); const isPhone = useMediaQuery(theme.breakpoints.down('xs')); @@ -65,7 +65,7 @@ const GeofencesPage = () => { classes={{ paper: classes.drawerPaper }} > <div className={classes.drawerHeader}> - <IconButton onClick={() => history.goBack()}> + <IconButton onClick={() => navigate(-1)}> <ArrowBackIcon /> </IconButton> <Typography variant="h6" color="inherit" noWrap> diff --git a/modern/src/other/PositionPage.js b/modern/src/other/PositionPage.js index 76bb560f..8188f669 100644 --- a/modern/src/other/PositionPage.js +++ b/modern/src/other/PositionPage.js @@ -5,7 +5,7 @@ import { makeStyles, Typography, Container, Paper, AppBar, Toolbar, IconButton, Table, TableHead, TableRow, TableCell, TableBody, } from '@material-ui/core'; import ArrowBackIcon from '@material-ui/icons/ArrowBack'; -import { useHistory, useParams } from 'react-router-dom'; +import { useNavigate, useParams } from 'react-router-dom'; import { useEffectAsync } from '../reactHelper'; import { prefixString } from '../common/util/stringUtils'; import { useTranslation } from '../common/components/LocalizationProvider'; @@ -26,7 +26,7 @@ const useStyles = makeStyles((theme) => ({ const PositionPage = () => { const classes = useStyles(); - const history = useHistory(); + const navigate = useNavigate(); const t = useTranslation(); const { id } = useParams(); @@ -63,7 +63,7 @@ const PositionPage = () => { <div className={classes.root}> <AppBar position="sticky" color="inherit"> <Toolbar> - <IconButton color="inherit" edge="start" onClick={() => history.goBack()}> + <IconButton color="inherit" edge="start" onClick={() => navigate(-1)}> <ArrowBackIcon /> </IconButton> <Typography variant="h6"> diff --git a/modern/src/other/ReplayPage.js b/modern/src/other/ReplayPage.js index 5e759d7e..c95240be 100644 --- a/modern/src/other/ReplayPage.js +++ b/modern/src/other/ReplayPage.js @@ -10,7 +10,7 @@ import PlayArrowIcon from '@material-ui/icons/PlayArrow'; import PauseIcon from '@material-ui/icons/Pause'; import FastForwardIcon from '@material-ui/icons/FastForward'; import FastRewindIcon from '@material-ui/icons/FastRewind'; -import { useHistory } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import { useSelector } from 'react-redux'; import Map from '../map/core/Map'; import MapReplayPath from '../map/MapReplayPath'; @@ -78,7 +78,7 @@ const TimeLabel = ({ children, open, value }) => ( const ReplayPage = () => { const t = useTranslation(); const classes = useStyles(); - const history = useHistory(); + const navigate = useNavigate(); const timerRef = useRef(); const defaultDeviceId = useSelector((state) => state.devices.selectedId); @@ -100,8 +100,8 @@ const ReplayPage = () => { }); const onClick = useCallback((positionId) => { - history.push(`/position/${positionId}`); - }, [history]); + navigate(`/position/${positionId}`); + }, [navigate]); useEffect(() => { if (playing && positions.length > 0) { @@ -146,7 +146,7 @@ const ReplayPage = () => { <div className={classes.sidebar}> <Paper elevation={3} square> <Toolbar> - <IconButton onClick={() => history.push('/')}> + <IconButton onClick={() => navigate('/')}> <ArrowBackIcon /> </IconButton> <Typography variant="h6" className={classes.title}>{t('reportReplay')}</Typography> diff --git a/modern/src/settings/AccumulatorsPage.js b/modern/src/settings/AccumulatorsPage.js index b22fe02e..8ca9d277 100644 --- a/modern/src/settings/AccumulatorsPage.js +++ b/modern/src/settings/AccumulatorsPage.js @@ -1,6 +1,6 @@ import React, { useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; -import { useHistory, useParams } from 'react-router-dom'; +import { useNavigate, useParams } from 'react-router-dom'; import { Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, Container, TextField, FormControl, Button, } from '@material-ui/core'; @@ -27,7 +27,7 @@ const useStyles = makeStyles((theme) => ({ })); const AccumulatorsPage = () => { - const history = useHistory(); + const navigate = useNavigate(); const classes = useStyles(); const t = useTranslation(); @@ -54,7 +54,7 @@ const AccumulatorsPage = () => { }); if (response.ok) { - history.goBack(); + navigate(-1); } else { throw Error(await response.text()); } @@ -95,7 +95,7 @@ const AccumulatorsPage = () => { type="button" color="primary" variant="outlined" - onClick={() => history.goBack()} + onClick={() => navigate(-1)} > {t('sharedCancel')} </Button> diff --git a/modern/src/settings/CommandSendPage.js b/modern/src/settings/CommandSendPage.js index cc0dae63..98415a5e 100644 --- a/modern/src/settings/CommandSendPage.js +++ b/modern/src/settings/CommandSendPage.js @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { useHistory, useParams } from 'react-router-dom'; +import { useNavigate, useParams } from 'react-router-dom'; import { Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, Container, Button, FormControl, } from '@material-ui/core'; @@ -28,7 +28,7 @@ const useStyles = makeStyles((theme) => ({ })); const CommandSendPage = () => { - const history = useHistory(); + const navigate = useNavigate(); const classes = useStyles(); const t = useTranslation(); @@ -59,7 +59,7 @@ const CommandSendPage = () => { }); if (response.ok) { - history.goBack(); + navigate(-1); } else { throw Error(await response.text()); } @@ -98,7 +98,7 @@ const CommandSendPage = () => { type="button" color="primary" variant="outlined" - onClick={() => history.goBack()} + onClick={() => navigate(-1)} > {t('sharedCancel')} </Button> diff --git a/modern/src/settings/ServerPage.js b/modern/src/settings/ServerPage.js index b745cb96..53feb8ba 100644 --- a/modern/src/settings/ServerPage.js +++ b/modern/src/settings/ServerPage.js @@ -5,7 +5,7 @@ import { Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, Button, FormControl, Container, Checkbox, FormControlLabel, InputLabel, Select, MenuItem, } from '@material-ui/core'; import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; -import { useHistory } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import { useDispatch, useSelector } from 'react-redux'; import { sessionActions } from '../store'; import EditAttributesView from './components/EditAttributesView'; @@ -35,7 +35,7 @@ const useStyles = makeStyles((theme) => ({ const ServerPage = () => { const classes = useStyles(); - const history = useHistory(); + const navigate = useNavigate(); const dispatch = useDispatch(); const t = useTranslation(); @@ -54,7 +54,7 @@ const ServerPage = () => { if (response.ok) { dispatch(sessionActions.updateServer(await response.json())); - history.goBack(); + navigate(-1); } else { throw Error(await response.text()); } @@ -229,7 +229,7 @@ const ServerPage = () => { )} <FormControl fullWidth margin="normal"> <div className={classes.buttons}> - <Button type="button" color="primary" variant="outlined" onClick={() => history.goBack()}> + <Button type="button" color="primary" variant="outlined" onClick={() => navigate(-1)}> {t('sharedCancel')} </Button> <Button type="button" color="primary" variant="contained" onClick={handleSave}> diff --git a/modern/src/settings/components/CollectionActions.js b/modern/src/settings/components/CollectionActions.js index 98226269..3fef1203 100644 --- a/modern/src/settings/components/CollectionActions.js +++ b/modern/src/settings/components/CollectionActions.js @@ -1,21 +1,21 @@ import React, { useState } from 'react'; import { IconButton, Menu, MenuItem } from '@material-ui/core'; import MoreVertIcon from '@material-ui/icons/MoreVert'; -import { useHistory } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import RemoveDialog from '../../common/components/RemoveDialog'; import { useTranslation } from '../../common/components/LocalizationProvider'; const CollectionActions = ({ itemId, editPath, endpoint, setTimestamp, }) => { - const history = useHistory(); + const navigate = useNavigate(); const t = useTranslation(); const [menuAnchorEl, setMenuAnchorEl] = useState(null); const [removing, setRemoving] = useState(false); const handleEdit = () => { - history.push(`${editPath}/${itemId}`); + navigate(`${editPath}/${itemId}`); setMenuAnchorEl(null); }; diff --git a/modern/src/settings/components/CollectionFab.js b/modern/src/settings/components/CollectionFab.js index f52bed38..36435cd9 100644 --- a/modern/src/settings/components/CollectionFab.js +++ b/modern/src/settings/components/CollectionFab.js @@ -1,7 +1,7 @@ import React from 'react'; import { Fab, makeStyles } from '@material-ui/core'; import AddIcon from '@material-ui/icons/Add'; -import { useHistory } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import { useReadonly } from '../../common/util/permissions'; import dimensions from '../../common/theme/dimensions'; @@ -18,13 +18,13 @@ const useStyles = makeStyles((theme) => ({ const CollectionFab = ({ editPath, disabled }) => { const classes = useStyles(); - const history = useHistory(); + const navigate = useNavigate(); const readonly = useReadonly(); if (!readonly && !disabled) { return ( - <Fab size="medium" color="primary" className={classes.fab} onClick={() => history.push(editPath)}> + <Fab size="medium" color="primary" className={classes.fab} onClick={() => navigate(editPath)}> <AddIcon /> </Fab> ); diff --git a/modern/src/settings/components/EditItemView.js b/modern/src/settings/components/EditItemView.js index 28598e77..d0a3dde5 100644 --- a/modern/src/settings/components/EditItemView.js +++ b/modern/src/settings/components/EditItemView.js @@ -1,5 +1,5 @@ import React from 'react'; -import { useHistory, useParams } from 'react-router-dom'; +import { useNavigate, useParams } from 'react-router-dom'; import { makeStyles } from '@material-ui/core/styles'; import Container from '@material-ui/core/Container'; import Button from '@material-ui/core/Button'; @@ -25,7 +25,7 @@ const useStyles = makeStyles((theme) => ({ const EditItemView = ({ children, endpoint, item, setItem, defaultItem, validate, onItemSaved, menu, breadcrumbs, }) => { - const history = useHistory(); + const navigate = useNavigate(); const classes = useStyles(); const t = useTranslation(); @@ -60,7 +60,7 @@ const EditItemView = ({ if (onItemSaved) { onItemSaved(await response.json()); } - history.goBack(); + navigate(-1); } else { throw Error(await response.text()); } @@ -76,7 +76,7 @@ const EditItemView = ({ type="button" color="primary" variant="outlined" - onClick={() => history.goBack()} + onClick={() => navigate(-1)} > {t('sharedCancel')} </Button> |