aboutsummaryrefslogtreecommitdiff
path: root/modern/src/settings
diff options
context:
space:
mode:
Diffstat (limited to 'modern/src/settings')
-rw-r--r--modern/src/settings/ComputedAttributesPage.js35
-rw-r--r--modern/src/settings/DriversPage.js27
-rw-r--r--modern/src/settings/GroupsPage.js27
-rw-r--r--modern/src/settings/MaintenancesPage.js27
-rw-r--r--modern/src/settings/NotificationsPage.js33
-rw-r--r--modern/src/settings/OptionsLayout/index.js106
-rw-r--r--modern/src/settings/OptionsLayout/useRoutes.js86
7 files changed, 282 insertions, 59 deletions
diff --git a/modern/src/settings/ComputedAttributesPage.js b/modern/src/settings/ComputedAttributesPage.js
index 1a6feab..d747598 100644
--- a/modern/src/settings/ComputedAttributesPage.js
+++ b/modern/src/settings/ComputedAttributesPage.js
@@ -1,24 +1,26 @@
import React, { useState } from 'react';
-import MainToolbar from '../MainToolbar';
import { TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton } from '@material-ui/core';
import MoreVertIcon from '@material-ui/icons/MoreVert';
import { useSelector } from 'react-redux';
import t from '../common/localization';
import { useEffectAsync } from '../reactHelper';
import EditCollectionView from '../EditCollectionView';
+import OptionsLayout from './OptionsLayout';
const useStyles = makeStyles(theme => ({
columnAction: {
width: theme.spacing(1),
- padding: theme.spacing(0, 1),
- },
+ padding: theme.spacing(0, 1)
+ }
}));
const ComputedAttributeView = ({ updateTimestamp, onMenuClick }) => {
const classes = useStyles();
const [items, setItems] = useState([]);
- const adminEnabled = useSelector(state => state.session.user && state.session.user.administrator);
+ const adminEnabled = useSelector(
+ state => state.session.user && state.session.user.administrator
+ );
useEffectAsync(async () => {
const response = await fetch('/api/attributes/computed');
@@ -40,15 +42,17 @@ const ComputedAttributeView = ({ updateTimestamp, onMenuClick }) => {
</TableRow>
</TableHead>
<TableBody>
- {items.map((item) => (
+ {items.map(item => (
<TableRow key={item.id}>
- {adminEnabled &&
+ {adminEnabled && (
<TableCell className={classes.columnAction} padding="none">
- <IconButton onClick={(event) => onMenuClick(event.currentTarget, item.id)}>
+ <IconButton
+ onClick={event => onMenuClick(event.currentTarget, item.id)}
+ >
<MoreVertIcon />
</IconButton>
</TableCell>
- }
+ )}
<TableCell>{item.description}</TableCell>
<TableCell>{item.attribute}</TableCell>
<TableCell>{item.expression}</TableCell>
@@ -59,15 +63,18 @@ const ComputedAttributeView = ({ updateTimestamp, onMenuClick }) => {
</Table>
</TableContainer>
);
-}
+};
const ComputedAttributesPage = () => {
return (
- <>
- <MainToolbar />
- <EditCollectionView content={ComputedAttributeView} editPath="/settings/attribute" endpoint="attributes/computed" />
- </>
+ <OptionsLayout>
+ <EditCollectionView
+ content={ComputedAttributeView}
+ editPath="/settings/attribute"
+ endpoint="attributes/computed"
+ />
+ </OptionsLayout>
);
-}
+};
export default ComputedAttributesPage;
diff --git a/modern/src/settings/DriversPage.js b/modern/src/settings/DriversPage.js
index 957e225..d5427b2 100644
--- a/modern/src/settings/DriversPage.js
+++ b/modern/src/settings/DriversPage.js
@@ -1,16 +1,16 @@
import React, { useState } from 'react';
-import MainToolbar from '../MainToolbar';
import { TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton } from '@material-ui/core';
import MoreVertIcon from '@material-ui/icons/MoreVert';
import t from '../common/localization';
import { useEffectAsync } from '../reactHelper';
import EditCollectionView from '../EditCollectionView';
+import OptionsLayout from './OptionsLayout';
const useStyles = makeStyles(theme => ({
columnAction: {
width: theme.spacing(1),
- padding: theme.spacing(0, 1),
- },
+ padding: theme.spacing(0, 1)
+ }
}));
const DriversView = ({ updateTimestamp, onMenuClick }) => {
@@ -36,10 +36,12 @@ const DriversView = ({ updateTimestamp, onMenuClick }) => {
</TableRow>
</TableHead>
<TableBody>
- {items.map((item) => (
+ {items.map(item => (
<TableRow key={item.id}>
<TableCell className={classes.columnAction} padding="none">
- <IconButton onClick={(event) => onMenuClick(event.currentTarget, item.id)}>
+ <IconButton
+ onClick={event => onMenuClick(event.currentTarget, item.id)}
+ >
<MoreVertIcon />
</IconButton>
</TableCell>
@@ -51,15 +53,18 @@ const DriversView = ({ updateTimestamp, onMenuClick }) => {
</Table>
</TableContainer>
);
-}
+};
const DriversPage = () => {
return (
- <>
- <MainToolbar />
- <EditCollectionView content={DriversView} editPath="/settings/driver" endpoint="drivers" />
- </>
+ <OptionsLayout>
+ <EditCollectionView
+ content={DriversView}
+ editPath="/settings/driver"
+ endpoint="drivers"
+ />
+ </OptionsLayout>
);
-}
+};
export default DriversPage;
diff --git a/modern/src/settings/GroupsPage.js b/modern/src/settings/GroupsPage.js
index e274062..2fc65c1 100644
--- a/modern/src/settings/GroupsPage.js
+++ b/modern/src/settings/GroupsPage.js
@@ -1,16 +1,16 @@
import React, { useState } from 'react';
-import MainToolbar from '../MainToolbar';
import { TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton } from '@material-ui/core';
import MoreVertIcon from '@material-ui/icons/MoreVert';
import t from '../common/localization';
import { useEffectAsync } from '../reactHelper';
import EditCollectionView from '../EditCollectionView';
+import OptionsLayout from './OptionsLayout';
const useStyles = makeStyles(theme => ({
columnAction: {
width: theme.spacing(1),
- padding: theme.spacing(0, 1),
- },
+ padding: theme.spacing(0, 1)
+ }
}));
const GroupsView = ({ updateTimestamp, onMenuClick }) => {
@@ -35,10 +35,12 @@ const GroupsView = ({ updateTimestamp, onMenuClick }) => {
</TableRow>
</TableHead>
<TableBody>
- {items.map((item) => (
+ {items.map(item => (
<TableRow key={item.id}>
<TableCell className={classes.columnAction} padding="none">
- <IconButton onClick={(event) => onMenuClick(event.currentTarget, item.id)}>
+ <IconButton
+ onClick={event => onMenuClick(event.currentTarget, item.id)}
+ >
<MoreVertIcon />
</IconButton>
</TableCell>
@@ -49,15 +51,18 @@ const GroupsView = ({ updateTimestamp, onMenuClick }) => {
</Table>
</TableContainer>
);
-}
+};
const GroupsPage = () => {
return (
- <>
- <MainToolbar />
- <EditCollectionView content={GroupsView} editPath="/settings/group" endpoint="groups" />
- </>
+ <OptionsLayout>
+ <EditCollectionView
+ content={GroupsView}
+ editPath="/settings/group"
+ endpoint="groups"
+ />
+ </OptionsLayout>
);
-}
+};
export default GroupsPage;
diff --git a/modern/src/settings/MaintenancesPage.js b/modern/src/settings/MaintenancesPage.js
index 7ba4bd2..d713eaa 100644
--- a/modern/src/settings/MaintenancesPage.js
+++ b/modern/src/settings/MaintenancesPage.js
@@ -1,5 +1,4 @@
import React, { useState } from 'react';
-import MainToolbar from '../MainToolbar';
import { TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton } from '@material-ui/core';
import MoreVertIcon from '@material-ui/icons/MoreVert';
import t from '../common/localization';
@@ -9,12 +8,13 @@ import EditCollectionView from '../EditCollectionView';
import positionAttributes from '../attributes/positionAttributes';
import { formatDistance, formatSpeed } from '../common/formatter';
import { useAttributePreference } from '../common/preferences';
+import OptionsLayout from './OptionsLayout';
const useStyles = makeStyles(theme => ({
columnAction: {
width: theme.spacing(1),
- padding: theme.spacing(0, 1),
- },
+ padding: theme.spacing(0, 1)
+ }
}));
const MaintenancesView = ({ updateTimestamp, onMenuClick }) => {
@@ -45,7 +45,7 @@ const MaintenancesView = ({ updateTimestamp, onMenuClick }) => {
}
return value;
- }
+ };
return (
<TableContainer>
@@ -63,7 +63,9 @@ const MaintenancesView = ({ updateTimestamp, onMenuClick }) => {
{items.map(item => (
<TableRow key={item.id}>
<TableCell className={classes.columnAction} padding="none">
- <IconButton onClick={event => onMenuClick(event.currentTarget, item.id)}>
+ <IconButton
+ onClick={event => onMenuClick(event.currentTarget, item.id)}
+ >
<MoreVertIcon />
</IconButton>
</TableCell>
@@ -77,15 +79,18 @@ const MaintenancesView = ({ updateTimestamp, onMenuClick }) => {
</Table>
</TableContainer>
);
-}
+};
const MaintenacesPage = () => {
return (
- <>
- <MainToolbar />
- <EditCollectionView content={MaintenancesView} editPath="/settings/maintenance" endpoint="maintenance" />
- </>
+ <OptionsLayout>
+ <EditCollectionView
+ content={MaintenancesView}
+ editPath="/settings/maintenance"
+ endpoint="maintenance"
+ />
+ </OptionsLayout>
);
-}
+};
export default MaintenacesPage;
diff --git a/modern/src/settings/NotificationsPage.js b/modern/src/settings/NotificationsPage.js
index 15da0de..5707f89 100644
--- a/modern/src/settings/NotificationsPage.js
+++ b/modern/src/settings/NotificationsPage.js
@@ -1,5 +1,4 @@
import React, { useState } from 'react';
-import MainToolbar from '../MainToolbar';
import { TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton } from '@material-ui/core';
import MoreVertIcon from '@material-ui/icons/MoreVert';
import t from '../common/localization';
@@ -7,12 +6,13 @@ import { useEffectAsync } from '../reactHelper';
import EditCollectionView from '../EditCollectionView';
import { prefixString } from '../common/stringUtils';
import { formatBoolean } from '../common/formatter';
+import OptionsLayout from './OptionsLayout';
const useStyles = makeStyles(theme => ({
columnAction: {
width: theme.spacing(1),
- padding: theme.spacing(0, 1),
- },
+ padding: theme.spacing(0, 1)
+ }
}));
const NotificationsView = ({ updateTimestamp, onMenuClick }) => {
@@ -54,29 +54,38 @@ const NotificationsView = ({ updateTimestamp, onMenuClick }) => {
{items.map(item => (
<TableRow key={item.id}>
<TableCell className={classes.columnAction} padding="none">
- <IconButton onClick={(event) => onMenuClick(event.currentTarget, item.id)}>
+ <IconButton
+ onClick={event => onMenuClick(event.currentTarget, item.id)}
+ >
<MoreVertIcon />
</IconButton>
</TableCell>
<TableCell>{t(prefixString('event', item.type))}</TableCell>
<TableCell>{formatBoolean(item.always)}</TableCell>
- <TableCell>{formatList('alarm', item.attributes.alarms)}</TableCell>
- <TableCell>{formatList('notificator', item.notificators)}</TableCell>
+ <TableCell>
+ {formatList('alarm', item.attributes.alarms)}
+ </TableCell>
+ <TableCell>
+ {formatList('notificator', item.notificators)}
+ </TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
-}
+};
const NotificationsPage = () => {
return (
- <>
- <MainToolbar />
- <EditCollectionView content={NotificationsView} editPath="/settings/notification" endpoint="notifications" />
- </>
+ <OptionsLayout>
+ <EditCollectionView
+ content={NotificationsView}
+ editPath="/settings/notification"
+ endpoint="notifications"
+ />
+ </OptionsLayout>
);
-}
+};
export default NotificationsPage;
diff --git a/modern/src/settings/OptionsLayout/index.js b/modern/src/settings/OptionsLayout/index.js
new file mode 100644
index 0000000..61a94cf
--- /dev/null
+++ b/modern/src/settings/OptionsLayout/index.js
@@ -0,0 +1,106 @@
+import React, { useState, useEffect } from 'react';
+import { useLocation } from 'react-router-dom';
+import {
+ Typography,
+ Divider,
+ Drawer,
+ makeStyles,
+ IconButton,
+ Hidden
+} from '@material-ui/core';
+
+import ArrowBackIcon from '@material-ui/icons/ArrowBack';
+
+import SideNav from '../../components/SideNav';
+import NavBar from '../../components/NavBar';
+import t from '../../common/localization';
+import useRoutes from './useRoutes';
+
+const useStyles = makeStyles(theme => ({
+ root: {
+ display: 'flex',
+ height: '100%'
+ },
+ drawerContainer: {
+ width: theme.dimensions.drawerWidthDesktop
+ },
+ drawer: {
+ width: theme.dimensions.drawerWidthDesktop,
+ [theme.breakpoints.down('md')]: {
+ width: theme.dimensions.drawerWidthTablet
+ }
+ },
+ content: {
+ flex: 1,
+ padding: theme.spacing(5, 3, 3, 3),
+ [theme.breakpoints.down('md')]: {
+ paddingTop: theme.spacing(10)
+ }
+ },
+ drawerHeader: {
+ ...theme.mixins.toolbar,
+ display: 'flex',
+ alignItems: 'center',
+ padding: theme.spacing(0, 1)
+ },
+ toolbar: {
+ [theme.breakpoints.down('md')]: {
+ ...theme.mixins.toolbar
+ }
+ }
+}));
+
+const OptionsLayout = ({ children }) => {
+ const classes = useStyles();
+ const location = useLocation();
+ const [openDrawer, setOpenDrawer] = useState(false);
+ const [optionTitle, setOptionTitle] = useState();
+ const routes = useRoutes();
+
+ useEffect(() => {
+ const activeRoute = routes.find(
+ route => route.href && location.pathname.match(route.match || route.href)
+ );
+ setOptionTitle(activeRoute?.name);
+ }, [location, routes]);
+
+ const title = `Options / ${optionTitle}`;
+
+ return (
+ <div className={classes.root}>
+ <Hidden lgUp>
+ <NavBar setOpenDrawer={setOpenDrawer} title={title} />
+ <Drawer
+ variant="temporary"
+ open={openDrawer}
+ onClose={() => setOpenDrawer(!openDrawer)}
+ classes={{ paper: classes.drawer }}
+ >
+ <SideNav routes={routes} />
+ </Drawer>
+ </Hidden>
+
+ <Hidden mdDown>
+ <Drawer
+ variant="permanent"
+ classes={{ root: classes.drawerContainer, paper: classes.drawer }}
+ >
+ <div className={classes.drawerHeader}>
+ <IconButton component="a" href="/">
+ <ArrowBackIcon />
+ </IconButton>
+ <Typography variant="h6" color="inherit" noWrap>
+ {t('settingsTitle')}
+ </Typography>
+ </div>
+ <Divider />
+ <SideNav routes={routes} />
+ </Drawer>
+ </Hidden>
+
+ <div className={classes.content}>{children}</div>
+ </div>
+ );
+};
+
+export default OptionsLayout;
diff --git a/modern/src/settings/OptionsLayout/useRoutes.js b/modern/src/settings/OptionsLayout/useRoutes.js
new file mode 100644
index 0000000..901719f
--- /dev/null
+++ b/modern/src/settings/OptionsLayout/useRoutes.js
@@ -0,0 +1,86 @@
+import React, { useMemo } from 'react';
+import { useSelector } from 'react-redux';
+import CreateIcon from '@material-ui/icons/Create';
+import NotificationsIcon from '@material-ui/icons/Notifications';
+import FolderIcon from '@material-ui/icons/Folder';
+import PersonIcon from '@material-ui/icons/Person';
+import StorageIcon from '@material-ui/icons/Storage';
+import BuildIcon from '@material-ui/icons/Build';
+import PeopleIcon from '@material-ui/icons/People';
+import BarChartIcon from '@material-ui/icons/BarChart';
+import { getIsAdmin, getUserId } from '../../selectors';
+import t from '../../common/localization';
+
+const accountRoute = {
+ name: t('settingsUser'),
+ icon: <PersonIcon />
+};
+
+const adminRoutes = [
+ { subheader: t('userAdmin') },
+ {
+ name: t('settingsServer'),
+ href: '/admin/server',
+ icon: <StorageIcon />
+ },
+ {
+ name: t('settingsUsers'),
+ href: '/admin/users',
+ icon: <PeopleIcon />
+ },
+ {
+ name: t('statisticsTitle'),
+ href: '/admin/statistics',
+ icon: <BarChartIcon />
+ }
+];
+
+const mainRoutes = [
+ accountRoute,
+ {
+ match: 'geofence',
+ name: t('sharedGeofences'),
+ href: '/geofences',
+ icon: <CreateIcon />
+ },
+ {
+ match: 'notification',
+ name: t('sharedNotifications'),
+ href: '/settings/notifications',
+ icon: <NotificationsIcon />
+ },
+ {
+ match: 'group',
+ name: t('settingsGroups'),
+ href: '/settings/groups',
+ icon: <FolderIcon />
+ },
+ {
+ match: 'driver',
+ name: t('sharedDrivers'),
+ href: '/settings/drivers',
+ icon: <PersonIcon />
+ },
+ {
+ match: 'attribute',
+ name: t('sharedComputedAttributes'),
+ href: '/settings/attributes',
+ icon: <StorageIcon />
+ },
+ {
+ match: 'maintenance',
+ name: t('sharedMaintenance'),
+ href: '/settings/maintenances',
+ icon: <BuildIcon />
+ }
+];
+
+export default () => {
+ const isAdmin = useSelector(getIsAdmin);
+ const userId = useSelector(getUserId);
+ accountRoute.href = `/user/${userId}`;
+
+ return useMemo(() => [...mainRoutes, ...(isAdmin ? adminRoutes : [])], [
+ isAdmin
+ ]);
+};