From b124908d9f9f2a24963871cac982cc5b5e172ba5 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 20 Sep 2020 18:22:36 -0700 Subject: Implement simple users screen --- modern/src/App.js | 2 ++ modern/src/MainToolbar.js | 28 +++++++++++++++++- modern/src/SocketController.js | 1 - modern/src/admin/UsersPage.js | 66 ++++++++++++++++++++++++++++++++++++++++++ modern/src/common/formatter.js | 9 +++++- web/l10n/en.json | 2 ++ 6 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 modern/src/admin/UsersPage.js 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 = () => { + ); 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 = () => { + {adminEnabled && ( + <> + + + {t('userAdmin')} + + }> + { history.push('/admin/users') }}> + + + + + + + + + + + + + + )} 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 ( +
+ + + + + + {t('sharedName')} + {t('userEmail')} + {t('userAdmin')} + {t('sharedDisabled')} + + + + {data.map((item) => ( + + {formatter(item, 'name')} + {formatter(item, 'email')} + {formatter(item, 'administrator')} + {formatter(item, 'disabled')} + + ))} + +
+
+
+ ); +} + +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", -- cgit v1.2.3