diff options
-rw-r--r-- | modern/src/App.js | 2 | ||||
-rw-r--r-- | modern/src/MainToolbar.js | 28 | ||||
-rw-r--r-- | modern/src/SocketController.js | 1 | ||||
-rw-r--r-- | modern/src/admin/UsersPage.js | 66 | ||||
-rw-r--r-- | modern/src/common/formatter.js | 9 | ||||
-rw-r--r-- | web/l10n/en.json | 2 |
6 files changed, 105 insertions, 3 deletions
diff --git a/modern/src/App.js b/modern/src/App.js index f45c64de..0f2a69b7 100644 --- a/modern/src/App.js +++ b/modern/src/App.js @@ -4,6 +4,7 @@ import CssBaseline from '@material-ui/core/CssBaseline'; import MainPage from './MainPage'; import LoginPage from './LoginPage'; import RouteReportPage from './reports/RouteReportPage'; +import UsersPage from './admin/UsersPage'; import DevicePage from './DevicePage'; import SocketController from './SocketController'; @@ -17,6 +18,7 @@ const App = () => { <Route exact path='/login' component={LoginPage} /> <Route exact path='/device/:id?' component={DevicePage} /> <Route exact path='/reports/route' component={RouteReportPage} /> + <Route exact path='/admin/users' component={UsersPage} /> </Switch> </> ); diff --git a/modern/src/MainToolbar.js b/modern/src/MainToolbar.js index e627f52c..338e961b 100644 --- a/modern/src/MainToolbar.js +++ b/modern/src/MainToolbar.js @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import { useHistory } from 'react-router-dom'; import { makeStyles } from '@material-ui/core/styles'; -import { useDispatch } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import { sessionActions } from './store'; import AppBar from '@material-ui/core/AppBar'; import Toolbar from '@material-ui/core/Toolbar'; @@ -19,6 +19,7 @@ import ListItemText from '@material-ui/core/ListItemText'; import DashboardIcon from '@material-ui/icons/Dashboard'; import BarChartIcon from '@material-ui/icons/BarChart'; import SettingsIcon from '@material-ui/icons/Settings'; +import PeopleIcon from '@material-ui/icons/People'; import t from './common/localization'; const useStyles = makeStyles(theme => ({ @@ -42,6 +43,7 @@ const MainToolbar = () => { const [drawer, setDrawer] = useState(false); const classes = useStyles(); const history = useHistory(); + const adminEnabled = useSelector(state => state.session.user && state.session.user.administrator); const openDrawer = () => { setDrawer(true) } const closeDrawer = () => { setDrawer(false) } @@ -155,6 +157,30 @@ const MainToolbar = () => { <ListItemText primary={t('sharedNotifications')} /> </ListItem> </List> + {adminEnabled && ( + <> + <Divider /> + <List + subheader={ + <ListSubheader> + {t('userAdmin')} + </ListSubheader> + }> + <ListItem button onClick={() => { history.push('/admin/users') }}> + <ListItemIcon> + <PeopleIcon /> + </ListItemIcon> + <ListItemText primary={t('settingsUsers')} /> + </ListItem> + <ListItem button disabled> + <ListItemIcon> + <BarChartIcon /> + </ListItemIcon> + <ListItemText primary={t('statisticsTitle')} /> + </ListItem> + </List> + </> + )} </div> </Drawer> </> diff --git a/modern/src/SocketController.js b/modern/src/SocketController.js index 787527cc..3d9748bd 100644 --- a/modern/src/SocketController.js +++ b/modern/src/SocketController.js @@ -1,4 +1,3 @@ -import { useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { connect } from 'react-redux'; import { positionsActions, devicesActions, sessionActions } from './store'; diff --git a/modern/src/admin/UsersPage.js b/modern/src/admin/UsersPage.js new file mode 100644 index 00000000..15368c75 --- /dev/null +++ b/modern/src/admin/UsersPage.js @@ -0,0 +1,66 @@ +import React, { useState } from 'react'; +import MainToobar from '../MainToolbar'; +import { useHistory } from 'react-router-dom'; +import { TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles } from '@material-ui/core'; +import t from '../common/localization'; +import formatter from '../common/formatter'; +import { useEffectAsync } from '../reactHelper'; + +const useStyles = makeStyles(theme => ({ + root: { + height: '100%', + display: 'flex', + flexDirection: 'column', + }, + content: { + flex: 1, + overflow: 'auto', + padding: theme.spacing(2), + }, + form: { + padding: theme.spacing(1, 2, 2), + }, +})); + +const UsersPage = () => { + const history = useHistory(); + const classes = useStyles(); + const [data, setData] = useState([]); + + useEffectAsync(async () => { + const response = await fetch('/api/users'); + if (response.ok) { + setData(await response.json()); + } + }, []); + + return ( + <div className={classes.root}> + <MainToobar history={history} /> + <TableContainer> + <Table> + <TableHead> + <TableRow> + <TableCell>{t('sharedName')}</TableCell> + <TableCell>{t('userEmail')}</TableCell> + <TableCell>{t('userAdmin')}</TableCell> + <TableCell>{t('sharedDisabled')}</TableCell> + </TableRow> + </TableHead> + <TableBody> + {data.map((item) => ( + <TableRow key={item.id}> + <TableCell>{formatter(item, 'name')}</TableCell> + <TableCell>{formatter(item, 'email')}</TableCell> + <TableCell>{formatter(item, 'administrator')}</TableCell> + <TableCell>{formatter(item, 'disabled')}</TableCell> + </TableRow> + ))} + </TableBody> + </Table> + </TableContainer> + </div> + ); +} + +export default UsersPage; diff --git a/modern/src/common/formatter.js b/modern/src/common/formatter.js index 9a61b178..8ad87e70 100644 --- a/modern/src/common/formatter.js +++ b/modern/src/common/formatter.js @@ -1,4 +1,5 @@ import moment from 'moment'; +import t from '../common/localization'; const formatValue = (key, value) => { switch (key) { @@ -13,7 +14,13 @@ const formatValue = (key, value) => { case 'batteryLevel': return value + '%'; default: - return value; + if (typeof value === 'number') { + return Number(value.toFixed(1)); + } else if (typeof value === 'boolean') { + return value ? t('sharedYes') : t('sharedNo'); + } else { + return value; + } } } diff --git a/web/l10n/en.json b/web/l10n/en.json index 627edece..27043437 100644 --- a/web/l10n/en.json +++ b/web/l10n/en.json @@ -8,6 +8,8 @@ "sharedEdit": "Edit", "sharedRemove": "Remove", "sharedRemoveConfirm": "Remove item?", + "sharedYes": "Yes", + "sharedNo": "No", "sharedKm": "km", "sharedMi": "mi", "sharedNmi": "nmi", |