From 1b93de84e2bf6a6532bdb03e1ae75e47061a4dca Mon Sep 17 00:00:00 2001 From: Desmond Kyeremeh Date: Sun, 11 Jul 2021 22:14:39 +0000 Subject: Fixed linting --- modern/src/App.js | 68 ++++++++-------- modern/src/CachingController.js | 22 ++--- modern/src/DevicePage.js | 95 +++++++++++++--------- modern/src/DevicesList.js | 15 ++-- modern/src/EditCollectionView.js | 27 +++--- modern/src/EditItemView.js | 16 ++-- modern/src/GeofencePage.js | 22 +++-- modern/src/GeofencesList.js | 12 ++- modern/src/GeofencesPage.js | 27 +++--- modern/src/Logo.js | 47 +++++------ modern/src/MainPage.js | 11 +-- modern/src/MainToolbar.js | 16 ++-- modern/src/PositionPage.js | 29 +++---- modern/src/RegisterDialog.js | 61 +++++++------- modern/src/RemoveDialog.js | 9 +- modern/src/SocketController.js | 26 +++--- modern/src/StartPage.js | 19 +++-- modern/src/UserPage.js | 47 ++++++----- modern/src/admin/ServerPage.js | 77 ++++++++---------- modern/src/admin/StatisticsPage.js | 27 +++--- modern/src/admin/UsersPage.js | 82 +++++++++---------- modern/src/attributes/AddAttributeDialog.js | 36 ++++---- modern/src/attributes/EditAttributesView.js | 83 +++++++++---------- modern/src/attributes/deviceAttributes.js | 4 +- modern/src/attributes/geofenceAttributes.js | 4 +- modern/src/attributes/positionAttributes.js | 10 +-- modern/src/attributes/userAttributes.js | 12 +-- modern/src/common/converter.js | 24 ++---- modern/src/common/formatter.js | 48 +++++------ modern/src/common/preferences.js | 30 +++---- modern/src/common/stringUtils.js | 8 +- modern/src/components/NavBar.js | 4 +- modern/src/components/SideNav.js | 42 +++++----- modern/src/components/registration/LoginForm.js | 71 ++++++++-------- modern/src/components/registration/RegisterForm.js | 82 ++++++++++--------- .../components/registration/ResetPasswordForm.js | 13 ++- modern/src/form/LinkField.js | 30 +++---- modern/src/form/SelectField.js | 23 +++--- modern/src/index.js | 4 +- modern/src/map/AccuracyMap.js | 36 ++++---- modern/src/map/CurrentLocationMap.js | 2 +- modern/src/map/CurrentPositionsMap.js | 6 +- modern/src/map/GeofenceEditMap.js | 32 ++++---- modern/src/map/GeofenceMap.js | 56 ++++++------- modern/src/map/Map.js | 16 ++-- modern/src/map/PositionsMap.js | 71 ++++++++-------- modern/src/map/ReplayPathMap.js | 28 ++++--- modern/src/map/SelectedDeviceMap.js | 4 +- modern/src/map/StatusView.js | 65 ++++++++++++--- modern/src/map/mapStyles.js | 42 +++++----- modern/src/map/mapUtil.js | 57 ++++++------- modern/src/reactHelper.js | 3 +- modern/src/reports/ChartReportPage.js | 69 ++++++++-------- modern/src/reports/EventReportPage.js | 39 +++++---- modern/src/reports/Graph.js | 37 ++++----- modern/src/reports/ReplayPage.js | 36 ++++---- modern/src/reports/ReportFilter.js | 85 +++++++++++-------- modern/src/reports/ReportLayout.js | 34 ++++---- modern/src/reports/RouteReportPage.js | 24 +++--- modern/src/reports/StopReportPage.js | 33 ++++---- modern/src/reports/SummaryReportPage.js | 38 +++++---- modern/src/reports/TripReportPage.js | 33 ++++---- modern/src/settings/ComputedAttributePage.js | 60 ++++++++------ modern/src/settings/ComputedAttributesPage.js | 80 +++++++++--------- modern/src/settings/DriverPage.js | 27 +++--- modern/src/settings/DriversPage.js | 74 ++++++++--------- modern/src/settings/GroupPage.js | 27 +++--- modern/src/settings/GroupsPage.js | 70 ++++++++-------- modern/src/settings/MaintenancePage.js | 90 ++++++++++---------- modern/src/settings/MaintenancesPage.js | 84 +++++++++---------- modern/src/settings/NotificationPage.js | 56 +++++++------ modern/src/settings/NotificationsPage.js | 80 +++++++++--------- modern/src/settings/OptionsLayout/useRoutes.js | 26 +++--- modern/src/setupProxy.js | 4 +- modern/src/store/devices.js | 8 +- modern/src/store/drivers.js | 4 +- modern/src/store/geofences.js | 6 +- modern/src/store/groups.js | 4 +- modern/src/store/maintenances.js | 4 +- modern/src/store/positions.js | 4 +- modern/src/theme/dimensions.js | 2 +- modern/src/theme/index.js | 2 +- modern/src/theme/overrides.js | 50 ++++++------ 83 files changed, 1502 insertions(+), 1389 deletions(-) (limited to 'modern/src') diff --git a/modern/src/App.js b/modern/src/App.js index b76995e..ac7cdb2 100644 --- a/modern/src/App.js +++ b/modern/src/App.js @@ -1,7 +1,9 @@ import React from 'react'; import { ThemeProvider } from '@material-ui/core/styles'; -import { Switch, Route } from 'react-router-dom' +import { Switch, Route } from 'react-router-dom'; import CssBaseline from '@material-ui/core/CssBaseline'; +import { useSelector } from 'react-redux'; +import { LinearProgress } from '@material-ui/core'; import MainPage from './MainPage'; import RouteReportPage from './reports/RouteReportPage'; import ServerPage from './admin/ServerPage'; @@ -16,8 +18,6 @@ import GroupPage from './settings/GroupPage'; import PositionPage from './PositionPage'; import EventReportPage from './reports/EventReportPage'; import ReplayPage from './reports/ReplayPage'; -import { useSelector } from 'react-redux'; -import { LinearProgress } from '@material-ui/core'; import TripReportPage from './reports/TripReportPage'; import StopReportPage from './reports/StopReportPage'; import SummaryReportPage from './reports/SummaryReportPage'; @@ -40,7 +40,7 @@ import GeofencesPage from './GeofencesPage'; import GeofencePage from './GeofencePage'; const App = () => { - const initialized = useSelector(state => !!state.session.server && !!state.session.user); + const initialized = useSelector((state) => !!state.session.server && !!state.session.user); return ( @@ -48,44 +48,44 @@ const App = () => { - - - + + + {!initialized ? () : ( - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + )} ); -} +}; export default App; diff --git a/modern/src/CachingController.js b/modern/src/CachingController.js index 3f808de..d6e2006 100644 --- a/modern/src/CachingController.js +++ b/modern/src/CachingController.js @@ -1,10 +1,12 @@ -import { useDispatch, useSelector } from 'react-redux'; -import { connect } from 'react-redux'; -import { geofencesActions, groupsActions, driversActions, maintenancesActions } from './store'; +import { useDispatch, useSelector, connect } from 'react-redux'; + +import { + geofencesActions, groupsActions, driversActions, maintenancesActions, +} from './store'; import { useEffectAsync } from './reactHelper'; const CachingController = () => { - const authenticated = useSelector(state => !!state.session.user); + const authenticated = useSelector((state) => !!state.session.user); const dispatch = useDispatch(); useEffectAsync(async () => { @@ -23,8 +25,8 @@ const CachingController = () => { dispatch(groupsActions.update(await response.json())); } } - }, [authenticated]); - + }, [authenticated]); + useEffectAsync(async () => { if (authenticated) { const response = await fetch('/api/drivers'); @@ -33,7 +35,7 @@ const CachingController = () => { } } }, [authenticated]); - + useEffectAsync(async () => { if (authenticated) { const response = await fetch('/api/maintenance'); @@ -41,9 +43,9 @@ const CachingController = () => { dispatch(maintenancesActions.update(await response.json())); } } - }, [authenticated]); - + }, [authenticated]); + return null; -} +}; export default connect()(CachingController); diff --git a/modern/src/DevicePage.js b/modern/src/DevicePage.js index ed5a6cb..a20ba22 100644 --- a/modern/src/DevicePage.js +++ b/modern/src/DevicePage.js @@ -1,10 +1,12 @@ import React, { useState } from 'react'; import TextField from '@material-ui/core/TextField'; +import { + Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, FormControlLabel, Checkbox, +} from '@material-ui/core'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import t from './common/localization'; import EditItemView from './EditItemView'; -import { Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, FormControlLabel, Checkbox } from '@material-ui/core'; -import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import EditAttributesView from './attributes/EditAttributesView'; import deviceAttributes from './attributes/deviceAttributes'; import SelectField from './form/SelectField'; @@ -25,7 +27,8 @@ const DevicePage = () => { return ( - {item && + {item + && ( <> }> @@ -37,15 +40,17 @@ const DevicePage = () => { setItem({...item, name: event.target.value})} + onChange={(event) => setItem({ ...item, name: event.target.value })} label={t('sharedName')} - variant="filled" /> + variant="filled" + /> setItem({...item, uniqueId: event.target.value})} + onChange={(event) => setItem({ ...item, uniqueId: event.target.value })} label={t('deviceIdentifier')} - variant="filled" /> + variant="filled" + /> @@ -58,42 +63,48 @@ const DevicePage = () => { setItem({...item, groupId: Number(event.target.value)})} + onChange={(event) => setItem({ ...item, groupId: Number(event.target.value) })} endpoint="/api/groups" label={t('groupParent')} - variant="filled" /> + variant="filled" + /> setItem({...item, phone: event.target.value})} + onChange={(event) => setItem({ ...item, phone: event.target.value })} label={t('sharedPhone')} - variant="filled" /> + variant="filled" + /> setItem({...item, model: event.target.value})} + onChange={(event) => setItem({ ...item, model: event.target.value })} label={t('deviceModel')} - variant="filled" /> + variant="filled" + /> setItem({...item, contact: event.target.value})} + onChange={(event) => setItem({ ...item, contact: event.target.value })} label={t('deviceContact')} - variant="filled" /> + variant="filled" + /> setItem({...item, category: event.target.value})} - data={deviceCategories.map(category => ({ + onChange={(event) => setItem({ ...item, category: event.target.value })} + data={deviceCategories.map((category) => ({ id: category, - name: t(`category${category.replace(/^\w/, c => c.toUpperCase())}`) + name: t(`category${category.replace(/^\w/, (c) => c.toUpperCase())}`), }))} label={t('deviceCategory')} - variant="filled" /> + variant="filled" + /> setItem({...item, disabled: event.target.checked})} />} - label={t('sharedDisabled')} /> + control={ setItem({ ...item, disabled: event.target.checked })} />} + label={t('sharedDisabled')} + /> @@ -105,12 +116,13 @@ const DevicePage = () => { setItem({...item, attributes})} + setAttributes={(attributes) => setItem({ ...item, attributes })} definitions={deviceAttributes} - /> + /> - {item.id && + {item.id + && ( }> @@ -121,57 +133,62 @@ const DevicePage = () => { + variant="filled" + /> t(prefixString('event', it.type))} + titleGetter={(it) => t(prefixString('event', it.type))} label={t('sharedNotifications')} - variant="filled" /> + variant="filled" + /> + variant="filled" + /> it.description} + titleGetter={(it) => it.description} label={t('sharedComputedAttributes')} - variant="filled" /> + variant="filled" + /> + variant="filled" + /> - } + )} - } + )} ); -} +}; export default DevicePage; diff --git a/modern/src/DevicesList.js b/modern/src/DevicesList.js index f66d717..85b936c 100644 --- a/modern/src/DevicesList.js +++ b/modern/src/DevicesList.js @@ -34,7 +34,7 @@ const DeviceRow = ({ data, index, style }) => { const { items, onMenuClick } = data; const item = items[index]; - + return (
@@ -61,7 +61,7 @@ const DeviceView = ({ updateTimestamp, onMenuClick }) => { const classes = useStyles(); const dispatch = useDispatch(); - const items = useSelector(state => Object.values(state.devices.items)); + const items = useSelector((state) => Object.values(state.devices.items)); useEffectAsync(async () => { const response = await fetch('/api/devices'); @@ -79,7 +79,8 @@ const DeviceView = ({ updateTimestamp, onMenuClick }) => { height={height} itemCount={items.length} itemData={{ items, onMenuClick }} - itemSize={72 + 1} > + itemSize={72 + 1} + > {DeviceRow} @@ -88,10 +89,8 @@ const DeviceView = ({ updateTimestamp, onMenuClick }) => { ); }; -const DevicesList = () => { - return ( - - ); -}; +const DevicesList = () => ( + +); export default DevicesList; diff --git a/modern/src/EditCollectionView.js b/modern/src/EditCollectionView.js index 572a1d1..7d5e4b2 100644 --- a/modern/src/EditCollectionView.js +++ b/modern/src/EditCollectionView.js @@ -10,7 +10,7 @@ import { useSelector } from 'react-redux'; import t from './common/localization'; import RemoveDialog from './RemoveDialog'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles((theme) => ({ fab: { position: 'absolute', bottom: theme.spacing(2), @@ -18,7 +18,9 @@ const useStyles = makeStyles(theme => ({ }, })); -const EditCollectionView = ({ content, editPath, endpoint, disableAdd }) => { +const EditCollectionView = ({ + content, editPath, endpoint, disableAdd, +}) => { const classes = useStyles(); const history = useHistory(); @@ -26,47 +28,48 @@ const EditCollectionView = ({ content, editPath, endpoint, disableAdd }) => { const [selectedAnchorEl, setSelectedAnchorEl] = useState(null); const [removeDialogShown, setRemoveDialogShown] = useState(false); const [updateTimestamp, setUpdateTimestamp] = useState(Date.now()); - const adminEnabled = useSelector(state => state.session.user && state.session.user.administrator); + const adminEnabled = useSelector((state) => state.session.user && state.session.user.administrator); const menuShow = (anchorId, itemId) => { setSelectedAnchorEl(anchorId); setSelectedId(itemId); - } + }; const menuHide = () => { setSelectedAnchorEl(null); - } + }; const handleAdd = () => { history.push(editPath); menuHide(); - } + }; const handleEdit = () => { history.push(`${editPath}/${selectedId}`); menuHide(); - } + }; const handleRemove = () => { setRemoveDialogShown(true); menuHide(); - } + }; const handleRemoveResult = () => { setRemoveDialogShown(false); setUpdateTimestamp(Date.now()); - } + }; const Content = content; return ( <> - {adminEnabled && !disableAdd && + {adminEnabled && !disableAdd + && ( - } + )} {t('sharedEdit')} {t('sharedRemove')} @@ -74,6 +77,6 @@ const EditCollectionView = ({ content, editPath, endpoint, disableAdd }) => { ); -} +}; export default EditCollectionView; diff --git a/modern/src/EditItemView.js b/modern/src/EditItemView.js index bab56c7..a77f578 100644 --- a/modern/src/EditItemView.js +++ b/modern/src/EditItemView.js @@ -9,20 +9,22 @@ import t from './common/localization'; import { useEffectAsync } from './reactHelper'; import OptionsLayout from './settings/OptionsLayout'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles((theme) => ({ container: { - marginTop: theme.spacing(2) + marginTop: theme.spacing(2), }, buttons: { display: 'flex', justifyContent: 'space-evenly', '& > *': { - flexBasis: '33%' - } - } + flexBasis: '33%', + }, + }, })); -const EditItemView = ({ children, endpoint, item, setItem }) => { +const EditItemView = ({ + children, endpoint, item, setItem, +}) => { const history = useHistory(); const classes = useStyles(); const { id } = useParams(); @@ -47,7 +49,7 @@ const EditItemView = ({ children, endpoint, item, setItem }) => { const response = await fetch(url, { method: !id ? 'POST' : 'PUT', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(item) + body: JSON.stringify(item), }); if (response.ok) { diff --git a/modern/src/GeofencePage.js b/modern/src/GeofencePage.js index 6c5db9b..06456fc 100644 --- a/modern/src/GeofencePage.js +++ b/modern/src/GeofencePage.js @@ -1,10 +1,12 @@ import React, { useState } from 'react'; import TextField from '@material-ui/core/TextField'; +import { + Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, +} from '@material-ui/core'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import t from './common/localization'; import EditItemView from './EditItemView'; -import { Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography } from '@material-ui/core'; -import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import EditAttributesView from './attributes/EditAttributesView'; import geofenceAttributes from './attributes/geofenceAttributes'; @@ -21,7 +23,8 @@ const GeofencePage = () => { return ( - {item && + {item + && ( <> }> @@ -33,9 +36,10 @@ const GeofencePage = () => { setItem({...item, name: event.target.value})} + onChange={(event) => setItem({ ...item, name: event.target.value })} label={t('sharedName')} - variant="filled" /> + variant="filled" + /> @@ -47,15 +51,15 @@ const GeofencePage = () => { setItem({...item, attributes})} + setAttributes={(attributes) => setItem({ ...item, attributes })} definitions={geofenceAttributes} - /> + /> - } + )} ); -} +}; export default GeofencePage; diff --git a/modern/src/GeofencesList.js b/modern/src/GeofencesList.js index 2988bef..572ac5b 100644 --- a/modern/src/GeofencesList.js +++ b/modern/src/GeofencesList.js @@ -28,7 +28,7 @@ const GeofenceView = ({ onMenuClick }) => { const classes = useStyles(); const dispatch = useDispatch(); - const items = useSelector(state => Object.values(state.geofences.items)); + const items = useSelector((state) => Object.values(state.geofences.items)); return ( @@ -47,12 +47,10 @@ const GeofenceView = ({ onMenuClick }) => { ))} ); -} +}; -const GeofencesList = () => { - return ( - - ); -} +const GeofencesList = () => ( + +); export default GeofencesList; diff --git a/modern/src/GeofencesPage.js b/modern/src/GeofencesPage.js index 59b8459..71219c1 100644 --- a/modern/src/GeofencesPage.js +++ b/modern/src/GeofencesPage.js @@ -1,21 +1,22 @@ import React from 'react'; -import { Divider, isWidthUp, makeStyles, withWidth, Typography, IconButton } from '@material-ui/core'; +import { + Divider, isWidthUp, makeStyles, withWidth, Typography, IconButton, +} from '@material-ui/core'; import Drawer from '@material-ui/core/Drawer'; import ContainerDimensions from 'react-container-dimensions'; +import ArrowBackIcon from '@material-ui/icons/ArrowBack'; import Map from './map/Map'; import CurrentLocationMap from './map/CurrentLocationMap'; import GeofenceEditMap from './map/GeofenceEditMap'; import GeofencesList from './GeofencesList'; -import ArrowBackIcon from '@material-ui/icons/ArrowBack'; - import t from './common/localization'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles((theme) => ({ root: { height: '100%', display: 'flex', - flexDirection: 'column' + flexDirection: 'column', }, content: { flexGrow: 1, @@ -23,27 +24,27 @@ const useStyles = makeStyles(theme => ({ display: 'flex', flexDirection: 'row', [theme.breakpoints.down('xs')]: { - flexDirection: 'column-reverse' - } + flexDirection: 'column-reverse', + }, }, drawerPaper: { position: 'relative', [theme.breakpoints.up('sm')]: { - width: 350 + width: 350, }, [theme.breakpoints.down('xs')]: { - height: 250 - } + height: 250, + }, }, drawerHeader: { ...theme.mixins.toolbar, display: 'flex', alignItems: 'center', - padding: theme.spacing(0, 1) + padding: theme.spacing(0, 1), }, mapContainer: { - flexGrow: 1 - } + flexGrow: 1, + }, })); const GeofencesPage = ({ width }) => { diff --git a/modern/src/Logo.js b/modern/src/Logo.js index bea14d8..1fb1ac8 100644 --- a/modern/src/Logo.js +++ b/modern/src/Logo.js @@ -1,31 +1,28 @@ import React from 'react'; -const Logo = ({ fill }) => { - - return ( - - - - - - - - - - +const Logo = ({ fill }) => ( + + + + + + + + + + - - - - - - - - + + + + + + + - - - ) -} + + + +); export default Logo; diff --git a/modern/src/MainPage.js b/modern/src/MainPage.js index 8d0b18d..88608df 100644 --- a/modern/src/MainPage.js +++ b/modern/src/MainPage.js @@ -11,7 +11,7 @@ import GeofenceMap from './map/GeofenceMap'; import CurrentPositionsMap from './map/CurrentPositionsMap'; import CurrentLocationMap from './map/CurrentLocationMap'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles((theme) => ({ root: { height: '100%', display: 'flex', @@ -24,7 +24,7 @@ const useStyles = makeStyles(theme => ({ flexDirection: 'row', [theme.breakpoints.down('xs')]: { flexDirection: 'column-reverse', - } + }, }, drawerPaper: { position: 'relative', @@ -50,8 +50,9 @@ const MainPage = ({ width }) => {
+ variant="permanent" + classes={{ paper: classes.drawerPaper }} + >
@@ -68,6 +69,6 @@ const MainPage = ({ width }) => {
); -} +}; export default withWidth()(MainPage); diff --git a/modern/src/MainToolbar.js b/modern/src/MainToolbar.js index 311f024..9a72729 100644 --- a/modern/src/MainToolbar.js +++ b/modern/src/MainToolbar.js @@ -2,7 +2,6 @@ import React, { useState } from 'react'; import { useHistory } from 'react-router-dom'; import { makeStyles } from '@material-ui/core/styles'; import { useDispatch, useSelector } from 'react-redux'; -import { sessionActions } from './store'; import AppBar from '@material-ui/core/AppBar'; import Toolbar from '@material-ui/core/Toolbar'; import Typography from '@material-ui/core/Typography'; @@ -20,23 +19,24 @@ import MapIcon from '@material-ui/icons/Map'; import PersonIcon from '@material-ui/icons/Person'; import DescriptionIcon from '@material-ui/icons/Description'; import ReplayIcon from '@material-ui/icons/Replay'; +import { sessionActions } from './store'; import t from './common/localization'; import * as selectors from './selectors'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles((theme) => ({ flex: { - flexGrow: 1 + flexGrow: 1, }, appBar: { - zIndex: theme.zIndex.drawer + 1 + zIndex: theme.zIndex.drawer + 1, }, list: { - width: 250 + width: 250, }, menuButton: { marginLeft: -12, - marginRight: 20 - } + marginRight: 20, + }, })); const MainToolbar = () => { @@ -111,7 +111,7 @@ const MainToolbar = () => { history.push(`/settings/notifications`)} + onClick={() => history.push('/settings/notifications')} > diff --git a/modern/src/PositionPage.js b/modern/src/PositionPage.js index a91a7a1..f1766f6 100644 --- a/modern/src/PositionPage.js +++ b/modern/src/PositionPage.js @@ -1,14 +1,16 @@ import React, { Fragment, useState } from 'react'; -import t from './common/localization'; -import { makeStyles, Typography, ListItem, ListItemText, ListItemSecondaryAction, List, Container, Paper, Divider } from '@material-ui/core'; +import { + makeStyles, Typography, ListItem, ListItemText, ListItemSecondaryAction, List, Container, Paper, Divider, +} from '@material-ui/core'; import { useParams } from 'react-router-dom'; +import t from './common/localization'; import { useEffectAsync } from './reactHelper'; import MainToolbar from './MainToolbar'; import { formatPosition } from './common/formatter'; import { prefixString } from './common/stringUtils'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles((theme) => ({ root: { marginTop: theme.spacing(2), marginBottom: theme.spacing(2), @@ -26,7 +28,7 @@ const PositionPage = () => { if (id) { const response = await fetch(`/api/positions?id=${id}`, { headers: { - 'Accept': 'application/json' + Accept: 'application/json', }, }); if (response.ok) { @@ -38,28 +40,27 @@ const PositionPage = () => { } }, [id]); - const formatKey = (key) => { - return t(prefixString('position', key)) || `${t('sharedAttribute')} "${key}"`; - }; + const formatKey = (key) => t(prefixString('position', key)) || `${t('sharedAttribute')} "${key}"`; const attributesList = () => { - const combinedList = {...item, ...item.attributes}; + const combinedList = { ...item, ...item.attributes }; return Object.entries(combinedList).filter(([_, value]) => typeof value !== 'object'); - } + }; return ( <> - + - {item && + {item + && ( {attributesList().map(([key, value], index, list) => ( + /> {formatPosition(value, key)} @@ -70,11 +71,11 @@ const PositionPage = () => { ))} - } + )} ); -} +}; export default PositionPage; diff --git a/modern/src/RegisterDialog.js b/modern/src/RegisterDialog.js index c640c51..c4b99f3 100644 --- a/modern/src/RegisterDialog.js +++ b/modern/src/RegisterDialog.js @@ -1,4 +1,3 @@ -import t from './common/localization' import React, { useState } from 'react'; import Button from '@material-ui/core/Button'; import Dialog from '@material-ui/core/Dialog'; @@ -7,6 +6,7 @@ import DialogContent from '@material-ui/core/DialogContent'; import DialogContentText from '@material-ui/core/DialogContentText'; import TextField from '@material-ui/core/TextField'; import Snackbar from '@material-ui/core/Snackbar'; +import t from './common/localization'; const RegisterDialog = ({ showDialog, onResult }) => { const [name, setName] = useState(''); @@ -14,80 +14,79 @@ const RegisterDialog = ({ showDialog, onResult }) => { const [password, setPassword] = useState(''); const [snackbarOpen, setSnackbarOpen] = useState(false); - const submitDisabled = () => { - return !name || !/(.+)@(.+)\.(.{2,})/.test(email) || !password; - } + const submitDisabled = () => !name || !/(.+)@(.+)\.(.{2,})/.test(email) || !password; const handleRegister = async () => { const response = await fetch('/api/users', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({name, email, password}) + body: JSON.stringify({ name, email, password }), }); if (response.ok) { showDialog = false; setSnackbarOpen(true); - } - } + } + }; if (snackbarOpen) { - return ( { onResult(true) }} - message={t('loginCreated')} /> + onClose={() => { onResult(true); }} + message={t('loginCreated')} + /> ); - - } else if (showDialog) { - + } if (showDialog) { return ( { onResult(false) }}> + open + onClose={() => { onResult(false); }} + > {t('loginRegister')} setName(event.target.value)} /> + onChange={(event) => setName(event.target.value)} + /> setEmail(event.target.value)} /> + autoComplete="email" + onChange={(event) => setEmail(event.target.value)} + /> setPassword(event.target.value)} /> + type="password" + autoComplete="current-password" + onChange={(event) => setPassword(event.target.value)} + /> - ) - + ); } }; diff --git a/modern/src/RemoveDialog.js b/modern/src/RemoveDialog.js index bbcfb22..8ff162c 100644 --- a/modern/src/RemoveDialog.js +++ b/modern/src/RemoveDialog.js @@ -1,12 +1,14 @@ -import t from './common/localization' import React from 'react'; import Button from '@material-ui/core/Button'; import Dialog from '@material-ui/core/Dialog'; import DialogActions from '@material-ui/core/DialogActions'; import DialogContent from '@material-ui/core/DialogContent'; import DialogContentText from '@material-ui/core/DialogContentText'; +import t from './common/localization'; -const RemoveDialog = ({ open, endpoint, itemId, onResult }) => { +const RemoveDialog = ({ + open, endpoint, itemId, onResult, +}) => { const handleRemove = async () => { const response = await fetch(`/api/${endpoint}/${itemId}`, { method: 'DELETE' }); if (response.ok) { @@ -17,7 +19,8 @@ const RemoveDialog = ({ open, endpoint, itemId, onResult }) => { return ( { onResult(false) }}> + onClose={() => { onResult(false); }} + > {t('sharedRemoveConfirm')} diff --git a/modern/src/SocketController.js b/modern/src/SocketController.js index cda693a..901f506 100644 --- a/modern/src/SocketController.js +++ b/modern/src/SocketController.js @@ -1,19 +1,19 @@ -import { useDispatch, useSelector } from 'react-redux'; -import { connect } from 'react-redux'; -import { positionsActions, devicesActions, sessionActions } from './store'; +import { useDispatch, useSelector, connect } from 'react-redux'; + import { useHistory } from 'react-router-dom'; +import { positionsActions, devicesActions, sessionActions } from './store'; import { useEffectAsync } from './reactHelper'; -const displayNotifications = events => { - if ("Notification" in window) { - if (Notification.permission === "granted") { +const displayNotifications = (events) => { + if ('Notification' in window) { + if (Notification.permission === 'granted') { for (const event of events) { const notification = new Notification(`Event: ${event.type}`); setTimeout(notification.close.bind(notification), 4 * 1000); } - } else if (Notification.permission !== "denied") { - Notification.requestPermission(permission => { - if (permission === "granted") { + } else if (Notification.permission !== 'denied') { + Notification.requestPermission((permission) => { + if (permission === 'granted') { displayNotifications(events); } }); @@ -24,11 +24,11 @@ const displayNotifications = events => { const SocketController = () => { const dispatch = useDispatch(); const history = useHistory(); - const authenticated = useSelector(state => !!state.session.user); + const authenticated = useSelector((state) => !!state.session.user); const connectSocket = () => { const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; - const socket = new WebSocket(protocol + '//' + window.location.host + '/api/socket'); + const socket = new WebSocket(`${protocol}//${window.location.host}/api/socket`); socket.onclose = () => { setTimeout(() => connectSocket(), 60 * 1000); @@ -46,7 +46,7 @@ const SocketController = () => { displayNotifications(data.events); } }; - } + }; useEffectAsync(async () => { const response = await fetch('/api/server'); @@ -73,6 +73,6 @@ const SocketController = () => { }, [authenticated]); return null; -} +}; export default connect()(SocketController); diff --git a/modern/src/StartPage.js b/modern/src/StartPage.js index 53f8c35..1472f50 100644 --- a/modern/src/StartPage.js +++ b/modern/src/StartPage.js @@ -2,7 +2,7 @@ import React from 'react'; import { useMediaQuery, makeStyles, Paper } from '@material-ui/core'; import { useTheme } from '@material-ui/core/styles'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles((theme) => ({ root: { display: 'flex', height: '100vh', @@ -23,20 +23,20 @@ const useStyles = makeStyles(theme => ({ }, }, paper: { - display:'flex', + display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', flex: 1, boxShadow: '-2px 0px 16px rgba(0, 0, 0, 0.25)', [theme.breakpoints.up('lg')]: { - padding: theme.spacing(0, 25, 0, 0) + padding: theme.spacing(0, 25, 0, 0), }, }, form: { maxWidth: theme.spacing(52), padding: theme.spacing(5), - width: "100%", + width: '100%', }, })); @@ -47,11 +47,12 @@ const StartPage = ({ children }) => { return (
- {!useMediaQuery(theme.breakpoints.down('md')) && + {!useMediaQuery(theme.breakpoints.down('md')) + && ( - + - } + )}
@@ -59,7 +60,7 @@ const StartPage = ({ children }) => {
- ) -} + ); +}; export default StartPage; diff --git a/modern/src/UserPage.js b/modern/src/UserPage.js index dfe8b98..6afbdf7 100644 --- a/modern/src/UserPage.js +++ b/modern/src/UserPage.js @@ -1,11 +1,13 @@ import React, { useState } from 'react'; import TextField from '@material-ui/core/TextField'; +import { + Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, +} from '@material-ui/core'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import t from './common/localization'; import userAttributes from './attributes/userAttributes'; import EditItemView from './EditItemView'; -import { Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography } from '@material-ui/core'; -import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import EditAttributesView from './attributes/EditAttributesView'; import LinkField from './form/LinkField'; @@ -22,7 +24,8 @@ const UserPage = () => { return ( - {item && + {item + && ( <> }> @@ -34,21 +37,24 @@ const UserPage = () => { setItem({...item, name: event.target.value})} + onChange={(event) => setItem({ ...item, name: event.target.value })} label={t('sharedName')} - variant="filled" /> + variant="filled" + /> setItem({...item, email: event.target.value})} + onChange={(event) => setItem({ ...item, email: event.target.value })} label={t('userEmail')} - variant="filled" /> + variant="filled" + /> setItem({...item, password: event.target.value})} + onChange={(event) => setItem({ ...item, password: event.target.value })} label={t('userPassword')} - variant="filled" /> + variant="filled" + /> @@ -60,12 +66,13 @@ const UserPage = () => { setItem({...item, attributes})} + setAttributes={(attributes) => setItem({ ...item, attributes })} definitions={userAttributes} - /> + /> - {item.id && + {item.id + && ( }> @@ -76,28 +83,30 @@ const UserPage = () => { + variant="filled" + /> + variant="filled" + /> - } + )} - } + )} ); -} +}; export default UserPage; diff --git a/modern/src/admin/ServerPage.js b/modern/src/admin/ServerPage.js index c33a631..6d5b575 100644 --- a/modern/src/admin/ServerPage.js +++ b/modern/src/admin/ServerPage.js @@ -1,31 +1,33 @@ import React from 'react'; import TextField from '@material-ui/core/TextField'; -import t from '../common/localization'; -import { Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, Button, FormControl, Container, Checkbox, FormControlLabel } from '@material-ui/core'; +import { + Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, Button, FormControl, Container, Checkbox, FormControlLabel, +} from '@material-ui/core'; import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import { useHistory } from 'react-router-dom'; import { useDispatch, useSelector } from 'react-redux'; +import t from '../common/localization'; import { sessionActions } from '../store'; import EditAttributesView from '../attributes/EditAttributesView'; import deviceAttributes from '../attributes/deviceAttributes'; import userAttributes from '../attributes/userAttributes'; import OptionsLayout from '../settings/OptionsLayout'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles((theme) => ({ container: { - marginTop: theme.spacing(2) + marginTop: theme.spacing(2), }, buttons: { display: 'flex', justifyContent: 'space-evenly', '& > *': { - flexBasis: '33%' - } + flexBasis: '33%', + }, }, details: { - flexDirection: 'column' - } + flexDirection: 'column', + }, })); const ServerPage = () => { @@ -33,15 +35,14 @@ const ServerPage = () => { const dispatch = useDispatch(); const classes = useStyles(); - const item = useSelector(state => state.session.server); - const setItem = updatedItem => - dispatch(sessionActions.updateServer(updatedItem)); + const item = useSelector((state) => state.session.server); + const setItem = (updatedItem) => dispatch(sessionActions.updateServer(updatedItem)); const handleSave = async () => { const response = await fetch('/api/server', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(item) + body: JSON.stringify(item), }); if (response.ok) { @@ -64,9 +65,7 @@ const ServerPage = () => { - setItem({ ...item, announcement: event.target.value }) - } + onChange={(event) => setItem({ ...item, announcement: event.target.value })} label={t('serverAnnouncement')} variant="filled" /> @@ -80,53 +79,45 @@ const ServerPage = () => { - setItem({ ...item, registration: event.target.checked }) - } + onChange={(event) => setItem({ ...item, registration: event.target.checked })} /> - } + )} label={t('serverRegistration')} /> - setItem({ ...item, readonly: event.target.checked }) - } + onChange={(event) => setItem({ ...item, readonly: event.target.checked })} /> - } + )} label={t('serverReadonly')} /> - setItem({ - ...item, - deviceReadonly: event.target.checked - }) - } + onChange={(event) => setItem({ + ...item, + deviceReadonly: event.target.checked, + })} /> - } + )} label={t('userDeviceReadonly')} /> - setItem({ - ...item, - limitCommands: event.target.checked - }) - } + onChange={(event) => setItem({ + ...item, + limitCommands: event.target.checked, + })} /> - } + )} label={t('userLimitCommands')} /> @@ -140,9 +131,9 @@ const ServerPage = () => { setItem({ ...item, attributes })} + setAttributes={(attributes) => setItem({ ...item, attributes })} definitions={{ ...userAttributes, ...deviceAttributes }} - /> + /> diff --git a/modern/src/admin/StatisticsPage.js b/modern/src/admin/StatisticsPage.js index b1504c8..8a6e601 100644 --- a/modern/src/admin/StatisticsPage.js +++ b/modern/src/admin/StatisticsPage.js @@ -1,9 +1,10 @@ - import React, { useState } from 'react'; -import { FormControl, InputLabel,Select, MenuItem, TextField, Button, TableContainer, Table, TableRow, TableCell, TableHead, TableBody, Paper } from '@material-ui/core'; +import { + FormControl, InputLabel, Select, MenuItem, TextField, Button, TableContainer, Table, TableRow, TableCell, TableHead, TableBody, Paper, +} from '@material-ui/core'; +import moment from 'moment'; import t from '../common/localization'; import { formatDate } from '../common/formatter'; -import moment from 'moment'; import OptionsLayout from '../settings/OptionsLayout'; const Filter = ({ setItems }) => { @@ -59,10 +60,10 @@ const Filter = ({ setItems }) => { const query = new URLSearchParams({ from: selectedFrom.toISOString(), - to: selectedTo.toISOString() + to: selectedTo.toISOString(), }); const response = await fetch(`/api/statistics?${query.toString()}`, { - Accept: 'application/json' + Accept: 'application/json', }); if (response.ok) { setItems(await response.json()); @@ -73,7 +74,7 @@ const Filter = ({ setItems }) => { <> {t('reportPeriod')} - setPeriod(e.target.value)}> {t('reportToday')} {t('reportYesterday')} {t('reportThisWeek')} @@ -90,9 +91,7 @@ const Filter = ({ setItems }) => { label={t('reportFrom')} type="datetime-local" value={from.format(moment.HTML5_FMT.DATETIME_LOCAL)} - onChange={e => - setFrom(moment(e.target.value, moment.HTML5_FMT.DATETIME_LOCAL)) - } + onChange={(e) => setFrom(moment(e.target.value, moment.HTML5_FMT.DATETIME_LOCAL))} fullWidth /> )} @@ -103,9 +102,7 @@ const Filter = ({ setItems }) => { label={t('reportTo')} type="datetime-local" value={to.format(moment.HTML5_FMT.DATETIME_LOCAL)} - onChange={e => - setTo(moment(e.target.value, moment.HTML5_FMT.DATETIME_LOCAL)) - } + onChange={(e) => setTo(moment(e.target.value, moment.HTML5_FMT.DATETIME_LOCAL))} fullWidth /> )} @@ -117,7 +114,7 @@ const Filter = ({ setItems }) => { > {t('reportShow')} - + ); }; @@ -144,7 +141,7 @@ const StatisticsPage = () => { - {items.map(item => ( + {items.map((item) => ( {formatDate(item.captureTime)} {item.activeUsers} @@ -155,7 +152,7 @@ const StatisticsPage = () => { {item.mailSent} {item.smsSent} {item.geocoderRequests} - {item.geolocationRequests} + {item.geolocationRequests} ))} diff --git a/modern/src/admin/UsersPage.js b/modern/src/admin/UsersPage.js index ceaab6a..6afe099 100644 --- a/modern/src/admin/UsersPage.js +++ b/modern/src/admin/UsersPage.js @@ -1,5 +1,7 @@ import React, { useState } from 'react'; -import { TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton } from '@material-ui/core'; +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'; @@ -7,11 +9,11 @@ import EditCollectionView from '../EditCollectionView'; import { formatBoolean } from '../common/formatter'; import OptionsLayout from '../settings/OptionsLayout'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles((theme) => ({ columnAction: { width: theme.spacing(1), - padding: theme.spacing(0, 1) - } + padding: theme.spacing(0, 1), + }, })); const UsersView = ({ updateTimestamp, onMenuClick }) => { @@ -28,48 +30,46 @@ const UsersView = ({ updateTimestamp, onMenuClick }) => { return ( - - - - - {t('sharedName')} - {t('userEmail')} - {t('userAdmin')} - {t('sharedDisabled')} - - - - {items.map(item => ( - - +
+ + + + {t('sharedName')} + {t('userEmail')} + {t('userAdmin')} + {t('sharedDisabled')} + + + + {items.map((item) => ( + + onMenuClick(event.currentTarget, item.id)} + onClick={(event) => onMenuClick(event.currentTarget, item.id)} > - - - - {item.name} - {item.email} - {formatBoolean(item, 'administrator')} - {formatBoolean(item, 'disabled')} - - ))} - -
+ + + + {item.name} + {item.email} + {formatBoolean(item, 'administrator')} + {formatBoolean(item, 'disabled')} + + ))} + +
); }; -const UsersPage = () => { - return ( - - - - ); -}; +const UsersPage = () => ( + + + +); export default UsersPage; diff --git a/modern/src/attributes/AddAttributeDialog.js b/modern/src/attributes/AddAttributeDialog.js index ee4c48c..24c208a 100644 --- a/modern/src/attributes/AddAttributeDialog.js +++ b/modern/src/attributes/AddAttributeDialog.js @@ -1,12 +1,14 @@ import React, { useState } from 'react'; -import { Button, Dialog, DialogActions, DialogContent, FormControl, InputLabel, MenuItem, Select, TextField } from "@material-ui/core"; +import { + Button, Dialog, DialogActions, DialogContent, FormControl, InputLabel, MenuItem, Select, TextField, +} from '@material-ui/core'; -import t from '../common/localization'; import { Autocomplete, createFilterOptions } from '@material-ui/lab'; +import t from '../common/localization'; const AddAttributeDialog = ({ open, onResult, definitions }) => { const filter = createFilterOptions({ - stringify: option => option.name, + stringify: (option) => option.name, }); const options = Object.entries(definitions).map(([key, value]) => ({ @@ -39,10 +41,8 @@ const AddAttributeDialog = ({ open, onResult, definitions }) => { return filtered; }} options={options} - getOptionLabel={option => { - return option && typeof option === 'object' ? option.name : option; - }} - renderOption={option => option.name} + getOptionLabel={(option) => (option && typeof option === 'object' ? option.name : option)} + renderOption={(option) => option.name} freeSolo renderInput={(params) => ( @@ -52,14 +52,16 @@ const AddAttributeDialog = ({ open, onResult, definitions }) => { variant="filled" margin="normal" fullWidth - disabled={key in definitions}> + disabled={key in definitions} + > {t('sharedType')}
@@ -67,17 +69,19 @@ const AddAttributeDialog = ({ open, onResult, definitions }) => {
- ) -} + ); +}; export default AddAttributeDialog; diff --git a/modern/src/attributes/EditAttributesView.js b/modern/src/attributes/EditAttributesView.js index 619d857..5ca7cad 100644 --- a/modern/src/attributes/EditAttributesView.js +++ b/modern/src/attributes/EditAttributesView.js @@ -1,13 +1,14 @@ import React, { useState } from 'react'; -import t from '../common/localization'; - -import { Button, Checkbox, FilledInput, FormControl, FormControlLabel, Grid, IconButton, InputAdornment, InputLabel, makeStyles } from "@material-ui/core"; +import { + Button, Checkbox, FilledInput, FormControl, FormControlLabel, Grid, IconButton, InputAdornment, InputLabel, makeStyles, +} from '@material-ui/core'; import CloseIcon from '@material-ui/icons/Close'; import AddIcon from '@material-ui/icons/Add'; +import t from '../common/localization'; import AddAttributeDialog from './AddAttributeDialog'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles((theme) => ({ addButton: { marginTop: theme.spacing(2), marginBottom: theme.spacing(1), @@ -23,8 +24,8 @@ const EditAttributesView = ({ attributes, setAttributes, definitions }) => { const [addDialogShown, setAddDialogShown] = useState(false); const convertToList = (attributes) => { - let booleanList = []; - let otherList = []; + const booleanList = []; + const otherList = []; for (const key in attributes) { const value = attributes[key]; const type = getAttributeType(value); @@ -35,12 +36,12 @@ const EditAttributesView = ({ attributes, setAttributes, definitions }) => { } } return otherList.concat(booleanList); - } + }; const handleAddResult = (definition) => { setAddDialogShown(false); if (definition) { - switch(definition.type) { + switch (definition.type) { case 'number': updateAttribute(definition.key, 0); break; @@ -48,20 +49,20 @@ const EditAttributesView = ({ attributes, setAttributes, definitions }) => { updateAttribute(definition.key, false); break; default: - updateAttribute(definition.key, ""); + updateAttribute(definition.key, ''); break; } } - } + }; const updateAttribute = (key, value) => { - let updatedAttributes = {...attributes}; + const updatedAttributes = { ...attributes }; updatedAttributes[key] = value; setAttributes(updatedAttributes); }; const deleteAttribute = (key) => { - let updatedAttributes = {...attributes}; + const updatedAttributes = { ...attributes }; delete updatedAttributes[key]; setAttributes(updatedAttributes); }; @@ -74,11 +75,10 @@ const EditAttributesView = ({ attributes, setAttributes, definitions }) => { const getAttributeType = (value) => { if (typeof value === 'number') { return 'number'; - } else if (typeof value === 'boolean') { + } if (typeof value === 'boolean') { return 'boolean'; - } else { - return 'string'; } + return 'string'; }; return ( @@ -88,37 +88,37 @@ const EditAttributesView = ({ attributes, setAttributes, definitions }) => { return ( updateAttribute(key, e.target.checked)} - /> - } - label={getAttributeName(key)} /> + onChange={(e) => updateAttribute(key, e.target.checked)} + /> + )} + label={getAttributeName(key)} + /> deleteAttribute(key)}> ); - } else { - return ( - - {getAttributeName(key)} - updateAttribute(key, e.target.value)} - endAdornment={ - - deleteAttribute(key)}> - - - - } - /> - - ); } + return ( + + {getAttributeName(key)} + updateAttribute(key, e.target.value)} + endAdornment={( + + deleteAttribute(key)}> + + + + )} + /> + + ); })} + /> ); -} +}; export default EditAttributesView; diff --git a/modern/src/attributes/deviceAttributes.js b/modern/src/attributes/deviceAttributes.js index 891a225..26e3d92 100644 --- a/modern/src/attributes/deviceAttributes.js +++ b/modern/src/attributes/deviceAttributes.js @@ -1,7 +1,7 @@ -import t from '../common/localization' +import t from '../common/localization'; export default { - 'speedLimit': { + speedLimit: { name: t('attributeSpeedLimit'), type: 'string', }, diff --git a/modern/src/attributes/geofenceAttributes.js b/modern/src/attributes/geofenceAttributes.js index 4b9c9e6..59a8869 100644 --- a/modern/src/attributes/geofenceAttributes.js +++ b/modern/src/attributes/geofenceAttributes.js @@ -1,7 +1,7 @@ -import t from '../common/localization' +import t from '../common/localization'; export default { - 'speedLimit': { + speedLimit: { name: t('attributeSpeedLimit'), type: 'string', }, diff --git a/modern/src/attributes/positionAttributes.js b/modern/src/attributes/positionAttributes.js index b1efe3d..94f396a 100644 --- a/modern/src/attributes/positionAttributes.js +++ b/modern/src/attributes/positionAttributes.js @@ -1,19 +1,19 @@ -import t from '../common/localization' +import t from '../common/localization'; export default { - 'raw': { + raw: { name: t('positionRaw'), type: 'string', }, - 'index': { + index: { name: t('positionIndex'), type: 'number', }, - 'ignition': { + ignition: { name: t('positionIgnition'), type: 'boolean', }, - 'odometer': { + odometer: { name: t('positionOdometer'), type: 'number', dataType: 'distance', diff --git a/modern/src/attributes/userAttributes.js b/modern/src/attributes/userAttributes.js index bcec29f..6f842f9 100644 --- a/modern/src/attributes/userAttributes.js +++ b/modern/src/attributes/userAttributes.js @@ -1,7 +1,7 @@ -import t from '../common/localization' +import t from '../common/localization'; export default { - 'notificationTokens': { + notificationTokens: { name: t('attributeNotificationTokens'), type: 'string', }, @@ -49,19 +49,19 @@ export default { name: t('attributeUiHidePositionAttributes'), type: 'string', }, - 'distanceUnit': { + distanceUnit: { name: t('settingsDistanceUnit'), type: 'string', }, - 'speedUnit': { + speedUnit: { name: t('settingsSpeedUnit'), type: 'string', }, - 'volumeUnit': { + volumeUnit: { name: t('settingsVolumeUnit'), type: 'string', }, - 'timezone': { + timezone: { name: t('sharedTimezone'), type: 'string', }, diff --git a/modern/src/common/converter.js b/modern/src/common/converter.js index 9cdc623..d45db5d 100644 --- a/modern/src/common/converter.js +++ b/modern/src/common/converter.js @@ -1,4 +1,4 @@ -const speedConverter = unit => { +const speedConverter = (unit) => { switch (unit) { case 'kmh': return 1.852; @@ -10,7 +10,7 @@ const speedConverter = unit => { } }; -const distanceConverter = unit => { +const distanceConverter = (unit) => { switch (unit) { case 'mi': return 0.000621371; @@ -19,21 +19,13 @@ const distanceConverter = unit => { case 'km': default: return 0.001; - } -} + } +}; -export const speedFromKnots = (value, unit) => { - return value * speedConverter(unit); -} +export const speedFromKnots = (value, unit) => value * speedConverter(unit); -export const speedToKnots = (value, unit) => { - return value / speedConverter(unit); -} +export const speedToKnots = (value, unit) => value / speedConverter(unit); -export const distanceFromMeters = (value, unit) => { - return value * distanceConverter(unit); -} +export const distanceFromMeters = (value, unit) => value * distanceConverter(unit); -export const distanceToMeters = (value, unit) => { - return value / distanceConverter(unit); -} +export const distanceToMeters = (value, unit) => value / distanceConverter(unit); diff --git a/modern/src/common/formatter.js b/modern/src/common/formatter.js index 0d8ac4c..7441d01 100644 --- a/modern/src/common/formatter.js +++ b/modern/src/common/formatter.js @@ -1,5 +1,5 @@ import moment from 'moment'; -import t from '../common/localization'; +import t from './localization'; export const formatPosition = (value, key) => { if (value != null && typeof value === 'object') { @@ -18,29 +18,22 @@ export const formatPosition = (value, key) => { case 'course': return value.toFixed(1); case 'batteryLevel': - return value + '%'; + return `${value}%`; default: if (typeof value === 'number') { return formatNumber(value); - } else if (typeof value === 'boolean') { + } if (typeof value === 'boolean') { return formatBoolean(value); - } else { - return value; } + return value; } }; -export const formatBoolean = (value) => { - return value ? t('sharedYes') : t('sharedNo'); -}; +export const formatBoolean = (value) => (value ? t('sharedYes') : t('sharedNo')); -export const formatNumber = (value, precision = 1) => { - return Number(value.toFixed(precision)); -}; +export const formatNumber = (value, precision = 1) => Number(value.toFixed(precision)); -export const formatDate = (value, format = 'YYYY-MM-DD HH:mm') => { - return moment(value).format(format); -}; +export const formatDate = (value, format = 'YYYY-MM-DD HH:mm') => moment(value).format(format); export const formatDistance = (value, unit) => { switch (unit) { @@ -50,7 +43,7 @@ export const formatDistance = (value, unit) => { return `${(value * 0.000539957).toFixed(2)} ${t('sharedNmi')}`; case 'km': default: - return `${(value * 0.001).toFixed(2)} ${t('sharedKm')}`; + return `${(value * 0.001).toFixed(2)} ${t('sharedKm')}`; } }; @@ -62,8 +55,8 @@ export const formatSpeed = (value, unit) => { return `${(value * 1.15078).toFixed(2)} ${t('sharedMph')}`; case 'kn': default: - return `${(value * 1).toFixed(2)} ${t('sharedKn')}`; - } + return `${(value * 1).toFixed(2)} ${t('sharedKn')}`; + } }; export const formatVolume = (value, unit) => { @@ -74,16 +67,15 @@ export const formatVolume = (value, unit) => { return `${(value / 3.785).toFixed(2)} ${t('sharedGallonAbbreviation')}`; case 'ltr': default: - return `${(value / 1).toFixed(2)} ${t('sharedLiterAbbreviation')}`; - } -} - -export const formatHours = (value) => { - return moment.duration(value).humanize(); + return `${(value / 1).toFixed(2)} ${t('sharedLiterAbbreviation')}`; + } }; +export const formatHours = (value) => moment.duration(value).humanize(); + export const formatCoordinate = (key, value, unit) => { - var hemisphere, degrees, minutes, seconds; + let hemisphere; let degrees; let minutes; let + seconds; if (key === 'latitude') { hemisphere = value >= 0 ? 'N' : 'S'; } else { @@ -95,14 +87,14 @@ export const formatCoordinate = (key, value, unit) => { value = Math.abs(value); degrees = Math.floor(value); minutes = (value - degrees) * 60; - return degrees + '° ' + minutes.toFixed(6) + '\' ' + hemisphere; + return `${degrees}° ${minutes.toFixed(6)}' ${hemisphere}`; case 'dms': value = Math.abs(value); degrees = Math.floor(value); minutes = Math.floor((value - degrees) * 60); seconds = Math.round((value - degrees - minutes / 60) * 3600); - return degrees + '° ' + minutes + '\' ' + seconds + '" ' + hemisphere; + return `${degrees}° ${minutes}' ${seconds}" ${hemisphere}`; default: - return value.toFixed(6) + '°'; - } + return `${value.toFixed(6)}°`; + } }; diff --git a/modern/src/common/preferences.js b/modern/src/common/preferences.js index 24fe389..aba3c82 100644 --- a/modern/src/common/preferences.js +++ b/modern/src/common/preferences.js @@ -1,21 +1,15 @@ import { useSelector } from 'react-redux'; -export const usePreference = (key, defaultValue) => { - return useSelector(state => { - if (state.session.server.forceSettings) { - return state.session.server[key] || state.session.user[key] || defaultValue; - } else { - return state.session.user[key] || state.session.server[key] || defaultValue; - } - }); -}; +export const usePreference = (key, defaultValue) => useSelector((state) => { + if (state.session.server.forceSettings) { + return state.session.server[key] || state.session.user[key] || defaultValue; + } + return state.session.user[key] || state.session.server[key] || defaultValue; +}); -export const useAttributePreference = (key, defaultValue) => { - return useSelector(state => { - if (state.session.server.forceSettings) { - return state.session.server.attributes[key] || state.session.user.attributes[key] || defaultValue; - } else { - return state.session.user.attributes[key] || state.session.server.attributes[key] || defaultValue; - } - }); -}; +export const useAttributePreference = (key, defaultValue) => useSelector((state) => { + if (state.session.server.forceSettings) { + return state.session.server.attributes[key] || state.session.user.attributes[key] || defaultValue; + } + return state.session.user.attributes[key] || state.session.server.attributes[key] || defaultValue; +}); diff --git a/modern/src/common/stringUtils.js b/modern/src/common/stringUtils.js index 7bd68c8..fc997fe 100644 --- a/modern/src/common/stringUtils.js +++ b/modern/src/common/stringUtils.js @@ -1,7 +1,3 @@ -export const prefixString = (prefix, value) => { - return prefix + value.charAt(0).toUpperCase() + value.slice(1); -} +export const prefixString = (prefix, value) => prefix + value.charAt(0).toUpperCase() + value.slice(1); -export const unprefixString = (prefix, value) => { - return value.charAt(prefix.length).toLowerCase() + value.slice(prefix.length + 1); -} +export const unprefixString = (prefix, value) => value.charAt(prefix.length).toLowerCase() + value.slice(prefix.length + 1); diff --git a/modern/src/components/NavBar.js b/modern/src/components/NavBar.js index 68e38bf..93e79bb 100644 --- a/modern/src/components/NavBar.js +++ b/modern/src/components/NavBar.js @@ -1,5 +1,7 @@ import React from 'react'; -import { AppBar, Toolbar, Typography, IconButton } from '@material-ui/core'; +import { + AppBar, Toolbar, Typography, IconButton, +} from '@material-ui/core'; import MenuIcon from '@material-ui/icons/Menu'; const Navbar = ({ setOpenDrawer, title }) => ( diff --git a/modern/src/components/SideNav.js b/modern/src/components/SideNav.js index 8bd43ac..aa07808 100644 --- a/modern/src/components/SideNav.js +++ b/modern/src/components/SideNav.js @@ -1,5 +1,7 @@ import React from 'react'; -import { List, ListItem, ListItemText, ListItemIcon, Divider, ListSubheader } from '@material-ui/core'; +import { + List, ListItem, ListItemText, ListItemIcon, Divider, ListSubheader, +} from '@material-ui/core'; import { Link, useLocation } from 'react-router-dom'; const SideNav = ({ routes }) => { @@ -7,26 +9,24 @@ const SideNav = ({ routes }) => { return ( - {routes.map((route, index) => - route.subheader ? ( - <> - - {route.subheader} - - ) : ( - - {route.icon} - - - ) - )} + {routes.map((route, index) => (route.subheader ? ( + <> + + {route.subheader} + + ) : ( + + {route.icon} + + + )))} ); }; diff --git a/modern/src/components/registration/LoginForm.js b/modern/src/components/registration/LoginForm.js index 382b4fd..e083541 100644 --- a/modern/src/components/registration/LoginForm.js +++ b/modern/src/components/registration/LoginForm.js @@ -1,24 +1,25 @@ import React, { useState } from 'react'; -import { Grid, useMediaQuery, makeStyles, InputLabel, Select, MenuItem, FormControl, Button, TextField, Link } from '@material-ui/core'; +import { + Grid, useMediaQuery, makeStyles, InputLabel, Select, MenuItem, FormControl, Button, TextField, Link, +} from '@material-ui/core'; import { useTheme } from '@material-ui/core/styles'; import { useDispatch, useSelector } from 'react-redux'; import { useHistory } from 'react-router-dom'; import { sessionActions } from '../../store'; import t from '../../common/localization'; -import StartPage from './../../StartPage'; +import StartPage from '../../StartPage'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles((theme) => ({ logoContainer: { textAlign: 'center', color: theme.palette.primary.main, }, resetPassword: { cursor: 'pointer', - } + }, })); const LoginForm = () => { - const classes = useStyles(); const dispatch = useDispatch(); const history = useHistory(); @@ -27,16 +28,16 @@ const LoginForm = () => { const [failed, setFailed] = useState(false); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); - const registrationEnabled = useSelector(state => state.session.server ? state.session.server['registration'] : false); - const emailEnabled = useSelector(state => state.session.server ? state.session.server['emailEnabled'] : false); + const registrationEnabled = useSelector((state) => (state.session.server ? state.session.server.registration : false)); + const emailEnabled = useSelector((state) => (state.session.server ? state.session.server.emailEnabled : false)); const handleEmailChange = (event) => { setEmail(event.target.value); - } + }; const handlePasswordChange = (event) => { setPassword(event.target.value); - } + }; const handleLogin = async (event) => { event.preventDefault(); @@ -49,38 +50,40 @@ const LoginForm = () => { setFailed(true); setPassword(''); } - } + }; - const handleSpecialKey = e => { + const handleSpecialKey = (e) => { if (e.keyCode === 13 && email && password) { handleLogin(e); } - } + }; return ( - - {useMediaQuery(theme.breakpoints.down('md')) && + + {useMediaQuery(theme.breakpoints.down('md')) + && ( - + - } + )} + variant="filled" + /> { fullWidth error={failed} label={t('userPassword')} - name='password' + name="password" value={password} - type='password' - autoComplete='current-password' + type="password" + autoComplete="current-password" onChange={handlePasswordChange} onKeyUp={handleSpecialKey} - variant='filled' /> + variant="filled" + /> - @@ -122,14 +127,16 @@ const LoginForm = () => { - {emailEnabled && + {emailEnabled && ( + - history.push('/reset-password')} className={classes.resetPassword} underline="none">{t('loginReset')} + history.push('/reset-password')} className={classes.resetPassword} underline="none">{t('loginReset')} - } + + )} - ) -} + ); +}; export default LoginForm; diff --git a/modern/src/components/registration/RegisterForm.js b/modern/src/components/registration/RegisterForm.js index b2a8222..06f5355 100644 --- a/modern/src/components/registration/RegisterForm.js +++ b/modern/src/components/registration/RegisterForm.js @@ -1,27 +1,28 @@ import React, { useState } from 'react'; -import { Grid, Button, TextField, Typography, Link, makeStyles, Snackbar } from '@material-ui/core'; +import { + Grid, Button, TextField, Typography, Link, makeStyles, Snackbar, +} from '@material-ui/core'; import { useHistory } from 'react-router-dom'; import ArrowBackIcon from '@material-ui/icons/ArrowBack'; -import StartPage from './../../StartPage'; -import t from './../../common/localization'; +import StartPage from '../../StartPage'; +import t from '../../common/localization'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles((theme) => ({ register: { fontSize: theme.spacing(3), fontWeight: 500, marginLeft: theme.spacing(2), - textTransform: "uppercase" + textTransform: 'uppercase', }, link: { fontSize: theme.spacing(3), fontWeight: 500, marginTop: theme.spacing(0.5), - cursor: 'pointer' - } + cursor: 'pointer', + }, })); const RegisterForm = () => { - const classes = useStyles(); const history = useHistory(); @@ -30,21 +31,19 @@ const RegisterForm = () => { const [password, setPassword] = useState(''); const [snackbarOpen, setSnackbarOpen] = useState(false); - const submitDisabled = () => { - return !name || !/(.+)@(.+)\.(.{2,})/.test(email) || !password; - } + const submitDisabled = () => !name || !/(.+)@(.+)\.(.{2,})/.test(email) || !password; const handleRegister = async () => { const response = await fetch('/api/users', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({name, email, password}) + body: JSON.stringify({ name, email, password }), }); if (response.ok) { setSnackbarOpen(true); - } - } + } + }; return ( @@ -53,18 +52,19 @@ const RegisterForm = () => { open={snackbarOpen} onClose={() => history.push('/login')} autoHideDuration={6000} - message={t('loginCreated')} /> - + message={t('loginCreated')} + /> + - + history.push('/login')}> - + {t('loginRegister')} @@ -74,50 +74,54 @@ const RegisterForm = () => { required fullWidth label={t('sharedName')} - name='name' + name="name" value={name || ''} - autoComplete='name' + autoComplete="name" autoFocus - onChange={event => setName(event.target.value)} - variant='filled' /> + onChange={(event) => setName(event.target.value)} + variant="filled" + /> setEmail(event.target.value)} - variant='filled' /> + autoComplete="email" + onChange={(event) => setEmail(event.target.value)} + variant="filled" + /> setPassword(event.target.value)} - variant='filled' /> + type="password" + autoComplete="current-password" + onChange={(event) => setPassword(event.target.value)} + variant="filled" + /> - ) -} + ); +}; export default RegisterForm; diff --git a/modern/src/components/registration/ResetPasswordForm.js b/modern/src/components/registration/ResetPasswordForm.js index c268f80..f4dd2e4 100644 --- a/modern/src/components/registration/ResetPasswordForm.js +++ b/modern/src/components/registration/ResetPasswordForm.js @@ -1,12 +1,9 @@ import React from 'react'; -const ResetPasswordForm = () => { - - return ( - <> -
Reset Password Comming Soon!!!
- - ) -} +const ResetPasswordForm = () => ( + <> +
Reset Password Comming Soon!!!
+ +); export default ResetPasswordForm; diff --git a/modern/src/form/LinkField.js b/modern/src/form/LinkField.js index b228fb3..26e1471 100644 --- a/modern/src/form/LinkField.js +++ b/modern/src/form/LinkField.js @@ -1,4 +1,6 @@ -import { FormControl, InputLabel, MenuItem, Select } from '@material-ui/core'; +import { + FormControl, InputLabel, MenuItem, Select, +} from '@material-ui/core'; import React, { useState } from 'react'; import { useEffectAsync } from '../reactHelper'; @@ -11,8 +13,8 @@ const LinkField = ({ baseId, keyBase, keyLink, - keyGetter = item => item.id, - titleGetter = item => item.name, + keyGetter = (item) => item.id, + titleGetter = (item) => item.name, }) => { const [items, setItems] = useState(); const [linked, setLinked] = useState(); @@ -28,28 +30,28 @@ const LinkField = ({ const response = await fetch(endpointLinked); if (response.ok) { const data = await response.json(); - setLinked(data.map(it => it.id)); + setLinked(data.map((it) => it.id)); } }, []); - const createBody = linkId => { + const createBody = (linkId) => { const body = {}; body[keyBase] = baseId; body[keyLink] = linkId; return body; - } + }; - const onChange = async event => { + const onChange = async (event) => { const oldValue = linked; const newValue = event.target.value; - for (const added of newValue.filter(it => !oldValue.includes(it))) { + for (const added of newValue.filter((it) => !oldValue.includes(it))) { await fetch('/api/permissions', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(createBody(added)), }); } - for (const removed of oldValue.filter(it => !newValue.includes(it))) { + for (const removed of oldValue.filter((it) => !newValue.includes(it))) { await fetch('/api/permissions', { method: 'DELETE', headers: { 'Content-Type': 'application/json' }, @@ -66,16 +68,16 @@ const LinkField = ({ ); - } else { - return null; } -} + return null; +}; export default LinkField; diff --git a/modern/src/form/SelectField.js b/modern/src/form/SelectField.js index b179c58..303d203 100644 --- a/modern/src/form/SelectField.js +++ b/modern/src/form/SelectField.js @@ -1,4 +1,6 @@ -import { FormControl, InputLabel, MenuItem, Select } from '@material-ui/core'; +import { + FormControl, InputLabel, MenuItem, Select, +} from '@material-ui/core'; import React, { useState } from 'react'; import { useEffectAsync } from '../reactHelper'; @@ -12,8 +14,8 @@ const SelectField = ({ onChange, endpoint, data, - keyGetter = item => item.id, - titleGetter = item => item.name, + keyGetter = (item) => item.id, + titleGetter = (item) => item.name, }) => { const [items, setItems] = useState(data); @@ -33,19 +35,18 @@ const SelectField = ({ ); - } else { - return null; } -} + return null; +}; export default SelectField; diff --git a/modern/src/index.js b/modern/src/index.js index 82ddef9..155bf62 100644 --- a/modern/src/index.js +++ b/modern/src/index.js @@ -1,7 +1,7 @@ -import 'typeface-roboto' +import 'typeface-roboto'; import React from 'react'; import ReactDOM from 'react-dom'; -import { HashRouter } from 'react-router-dom' +import { HashRouter } from 'react-router-dom'; import { Provider } from 'react-redux'; import App from './App'; diff --git a/modern/src/map/AccuracyMap.js b/modern/src/map/AccuracyMap.js index e81fc8f..4baa105 100644 --- a/modern/src/map/AccuracyMap.js +++ b/modern/src/map/AccuracyMap.js @@ -7,33 +7,31 @@ import { map } from './Map'; const AccuracyMap = () => { const id = 'accuracy'; - const positions = useSelector(state => ({ + const positions = useSelector((state) => ({ type: 'FeatureCollection', - features: Object.values(state.positions.items).filter(position => position.accuracy > 0).map(position => - circle([position.longitude, position.latitude], position.accuracy * 0.001) - ), + features: Object.values(state.positions.items).filter((position) => position.accuracy > 0).map((position) => circle([position.longitude, position.latitude], position.accuracy * 0.001)), })); useEffect(() => { map.addSource(id, { - 'type': 'geojson', - 'data': { + type: 'geojson', + data: { type: 'FeatureCollection', - features: [] - } + features: [], + }, }); map.addLayer({ - 'source': id, - 'id': id, - 'type': 'fill', - 'filter': [ - 'all', - ['==', '$type', 'Polygon'], + source: id, + id, + type: 'fill', + filter: [ + 'all', + ['==', '$type', 'Polygon'], ], - 'paint': { - 'fill-color':'#3bb2d0', - 'fill-outline-color':'#3bb2d0', - 'fill-opacity':0.25, + paint: { + 'fill-color': '#3bb2d0', + 'fill-outline-color': '#3bb2d0', + 'fill-opacity': 0.25, }, }); @@ -48,6 +46,6 @@ const AccuracyMap = () => { }, [positions]); return null; -} +}; export default AccuracyMap; diff --git a/modern/src/map/CurrentLocationMap.js b/modern/src/map/CurrentLocationMap.js index 06aaad0..69724ce 100644 --- a/modern/src/map/CurrentLocationMap.js +++ b/modern/src/map/CurrentLocationMap.js @@ -16,6 +16,6 @@ const CurrentLocationMap = () => { }, []); return null; -} +}; export default CurrentLocationMap; diff --git a/modern/src/map/CurrentPositionsMap.js b/modern/src/map/CurrentPositionsMap.js index 0bfe4fc..9e00774 100644 --- a/modern/src/map/CurrentPositionsMap.js +++ b/modern/src/map/CurrentPositionsMap.js @@ -1,11 +1,11 @@ -import React, { } from 'react'; +import React, { } from 'react'; import { useSelector } from 'react-redux'; import PositionsMap from './PositionsMap'; const CurrentPositionsMap = () => { - const positions = useSelector(state => Object.values(state.positions.items)); + const positions = useSelector((state) => Object.values(state.positions.items)); return (); -} +}; export default CurrentPositionsMap; diff --git a/modern/src/map/GeofenceEditMap.js b/modern/src/map/GeofenceEditMap.js index fe84338..f24fcb3 100644 --- a/modern/src/map/GeofenceEditMap.js +++ b/modern/src/map/GeofenceEditMap.js @@ -1,13 +1,13 @@ -import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css' +import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css'; import MapboxDraw from '@mapbox/mapbox-gl-draw'; 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 { map } from './Map'; import { geofenceToFeature, geometryToArea } from './mapUtil'; -import { useDispatch, useSelector } from 'react-redux'; import { geofencesActions } from '../store'; -import { useHistory } from 'react-router-dom'; const draw = new MapboxDraw({ displayControlsDefault: false, @@ -17,15 +17,15 @@ const draw = new MapboxDraw({ }, userProperties: true, styles: [...theme, { - 'id': 'gl-draw-title', - 'type': 'symbol', - 'filter': ['all'], - 'layout': { + id: 'gl-draw-title', + type: 'symbol', + filter: ['all'], + layout: { 'text-field': '{user_name}', 'text-font': ['Roboto Regular'], 'text-size': 12, }, - 'paint': { + paint: { 'text-halo-color': 'white', 'text-halo-width': 1, }, @@ -36,25 +36,25 @@ const GeofenceEditMap = () => { const dispatch = useDispatch(); const history = useHistory(); - const geofences = useSelector(state => Object.values(state.geofences.items)); + const geofences = useSelector((state) => Object.values(state.geofences.items)); const refreshGeofences = async () => { const response = await fetch('/api/geofences'); if (response.ok) { dispatch(geofencesActions.refresh(await response.json())); } - } + }; useEffect(() => { refreshGeofences(); map.addControl(draw, 'top-left'); - map.on('draw.create', async event => { + map.on('draw.create', async (event) => { const feature = event.features[0]; const newItem = { name: '', area: geometryToArea(feature.geometry) }; draw.delete(feature.id); - const response = await fetch(`/api/geofences`, { + const response = await fetch('/api/geofences', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(newItem), @@ -65,7 +65,7 @@ const GeofenceEditMap = () => { } }); - map.on('draw.delete', async event => { + map.on('draw.delete', async (event) => { const feature = event.features[0]; const response = await fetch(`/api/geofences/${feature.id}`, { method: 'DELETE' }); if (response.ok) { @@ -73,9 +73,9 @@ const GeofenceEditMap = () => { } }); - map.on('draw.update', async event => { + map.on('draw.update', async (event) => { const feature = event.features[0]; - const item = geofences.find(i => i.id === feature.id); + const item = geofences.find((i) => i.id === feature.id); if (item) { const updatedItem = { ...item, area: geometryToArea(feature.geometry) }; const response = await fetch(`/api/geofences/${feature.id}`, { @@ -100,6 +100,6 @@ const GeofenceEditMap = () => { }, [geofences]); return null; -} +}; export default GeofenceEditMap; diff --git a/modern/src/map/GeofenceMap.js b/modern/src/map/GeofenceMap.js index 8db175a..d00cbb1 100644 --- a/modern/src/map/GeofenceMap.js +++ b/modern/src/map/GeofenceMap.js @@ -7,49 +7,49 @@ import { geofenceToFeature } from './mapUtil'; const GeofenceMap = () => { const id = 'geofences'; - const geofences = useSelector(state => Object.values(state.geofences.items)); + const geofences = useSelector((state) => Object.values(state.geofences.items)); useEffect(() => { map.addSource(id, { - 'type': 'geojson', - 'data': { + type: 'geojson', + data: { type: 'FeatureCollection', - features: [] - } + features: [], + }, }); map.addLayer({ - 'source': id, - 'id': 'geofences-fill', - 'type': 'fill', - 'filter': [ - 'all', - ['==', '$type', 'Polygon'], + source: id, + id: 'geofences-fill', + type: 'fill', + filter: [ + 'all', + ['==', '$type', 'Polygon'], ], - 'paint': { - 'fill-color':'#3bb2d0', - 'fill-outline-color':'#3bb2d0', - 'fill-opacity':0.1, + paint: { + 'fill-color': '#3bb2d0', + 'fill-outline-color': '#3bb2d0', + 'fill-opacity': 0.1, }, }); map.addLayer({ - 'source': id, - 'id': 'geofences-line', - 'type': 'line', - 'paint': { - 'line-color': '#3bb2d0', - 'line-width': 2, + source: id, + id: 'geofences-line', + type: 'line', + paint: { + 'line-color': '#3bb2d0', + 'line-width': 2, }, }); map.addLayer({ - 'source': id, - 'id': 'geofences-title', - 'type': 'symbol', - 'layout': { + source: id, + id: 'geofences-title', + type: 'symbol', + layout: { 'text-field': '{name}', 'text-font': ['Roboto Regular'], 'text-size': 12, }, - 'paint': { + paint: { 'text-halo-color': 'white', 'text-halo-width': 1, }, @@ -66,11 +66,11 @@ const GeofenceMap = () => { useEffect(() => { map.getSource(id).setData({ type: 'FeatureCollection', - features: geofences.map(geofenceToFeature) + features: geofences.map(geofenceToFeature), }); }, [geofences]); return null; -} +}; export default GeofenceMap; diff --git a/modern/src/map/Map.js b/modern/src/map/Map.js index 46c59d2..672bd26 100644 --- a/modern/src/map/Map.js +++ b/modern/src/map/Map.js @@ -1,8 +1,10 @@ import 'maplibre-gl/dist/maplibre-gl.css'; import './switcher/switcher.css'; import maplibregl from 'maplibre-gl'; +import React, { + useRef, useLayoutEffect, useEffect, useState, +} from 'react'; import { SwitcherControl } from './switcher/switcher'; -import React, { useRef, useLayoutEffect, useEffect, useState } from 'react'; import { deviceCategories } from '../common/deviceCategories'; import { prepareIcon, loadImage } from './mapUtil'; import { styleCarto, styleMapbox, styleOsm } from './mapStyles'; @@ -22,18 +24,18 @@ export const map = new maplibregl.Map({ let ready = false; const readyListeners = new Set(); -const addReadyListener = listener => { +const addReadyListener = (listener) => { readyListeners.add(listener); listener(ready); }; -const removeReadyListener = listener => { +const removeReadyListener = (listener) => { readyListeners.delete(listener); }; -const updateReadyValue = value => { +const updateReadyValue = (value) => { ready = value; - readyListeners.forEach(listener => listener(value)); + readyListeners.forEach((listener) => listener(value)); }; const initMap = async () => { @@ -42,7 +44,7 @@ const initMap = async () => { map.addImage('background', await prepareIcon(background), { pixelRatio: window.devicePixelRatio, }); - await Promise.all(deviceCategories.map(async category => { + await Promise.all(deviceCategories.map(async (category) => { for (const color of ['green', 'red', 'gray']) { const icon = await loadImage(`images/icon/${category}.svg`); map.addImage(`${category}-${color}`, prepareIcon(background, icon, palette.common[color]), { @@ -93,7 +95,7 @@ const Map = ({ children }) => { }, [mapboxAccessToken]); useEffect(() => { - const listener = ready => setMapReady(ready); + const listener = (ready) => setMapReady(ready); addReadyListener(listener); return () => { removeReadyListener(listener); diff --git a/modern/src/map/PositionsMap.js b/modern/src/map/PositionsMap.js index 35d6d92..2de01d2 100644 --- a/modern/src/map/PositionsMap.js +++ b/modern/src/map/PositionsMap.js @@ -3,9 +3,9 @@ import ReactDOM from 'react-dom'; import maplibregl from 'maplibre-gl'; import { Provider, useSelector } from 'react-redux'; +import { useHistory } from 'react-router-dom'; import { map } from './Map'; import store from '../store'; -import { useHistory } from 'react-router-dom'; import StatusView from './StatusView'; const PositionsMap = ({ positions }) => { @@ -13,9 +13,9 @@ const PositionsMap = ({ positions }) => { const clusters = `${id}-clusters`; const history = useHistory(); - const devices = useSelector(state => state.devices.items); + const devices = useSelector((state) => state.devices.items); - const deviceColor = device => { + const deviceColor = (device) => { switch (device.status) { case 'online': return 'green'; @@ -33,15 +33,15 @@ const PositionsMap = ({ positions }) => { name: device.name, category: device.category || 'default', color: deviceColor(device), - } + }; }; const onMouseEnter = () => map.getCanvas().style.cursor = 'pointer'; const onMouseLeave = () => map.getCanvas().style.cursor = ''; - const onMarkerClick = useCallback(event => { + const onMarkerClick = useCallback((event) => { const feature = event.features[0]; - let coordinates = feature.geometry.coordinates.slice(); + const coordinates = feature.geometry.coordinates.slice(); while (Math.abs(event.lngLat.lng - coordinates[0]) > 180) { coordinates[0] += event.lngLat.lng > coordinates[0] ? 360 : -360; } @@ -49,50 +49,52 @@ const PositionsMap = ({ positions }) => { const placeholder = document.createElement('div'); ReactDOM.render( - history.push(`/position/${positionId}`)} /> + history.push(`/position/${positionId}`)} /> , - placeholder + placeholder, ); new maplibregl.Popup({ offset: 25, - anchor: 'top' + anchor: 'top', }) .setDOMContent(placeholder) .setLngLat(coordinates) .addTo(map); }, [history]); - const onClusterClick = event => { + const onClusterClick = (event) => { const features = map.queryRenderedFeatures(event.point, { layers: [clusters], }); const clusterId = features[0].properties.cluster_id; map.getSource(id).getClusterExpansionZoom(clusterId, (error, zoom) => { - if (!error) map.easeTo({ - center: features[0].geometry.coordinates, - zoom: zoom, - }); + if (!error) { + map.easeTo({ + center: features[0].geometry.coordinates, + zoom, + }); + } }); }; useEffect(() => { map.addSource(id, { - 'type': 'geojson', - 'data': { + type: 'geojson', + data: { type: 'FeatureCollection', features: [], }, - 'cluster': true, - 'clusterMaxZoom': 14, - 'clusterRadius': 50, + cluster: true, + clusterMaxZoom: 14, + clusterRadius: 50, }); map.addLayer({ - 'id': id, - 'type': 'symbol', - 'source': id, - 'filter': ['!', ['has', 'point_count']], - 'layout': { + id, + type: 'symbol', + source: id, + filter: ['!', ['has', 'point_count']], + layout: { 'icon-image': '{category}-{color}', 'icon-allow-overlap': true, 'text-field': '{name}', @@ -102,17 +104,17 @@ const PositionsMap = ({ positions }) => { 'text-font': ['Roboto Regular'], 'text-size': 12, }, - 'paint': { + paint: { 'text-halo-color': 'white', 'text-halo-width': 1, }, }); map.addLayer({ - 'id': clusters, - 'type': 'symbol', - 'source': id, - 'filter': ['has', 'point_count'], - 'layout': { + id: clusters, + type: 'symbol', + source: id, + filter: ['has', 'point_count'], + layout: { 'icon-image': 'background', 'text-field': '{point_count_abbreviated}', 'text-font': ['Roboto Regular'], @@ -120,7 +122,6 @@ const PositionsMap = ({ positions }) => { }, }); - map.on('mouseenter', id, onMouseEnter); map.on('mouseleave', id, onMouseLeave); map.on('mouseenter', clusters, onMouseEnter); @@ -129,7 +130,7 @@ const PositionsMap = ({ positions }) => { map.on('click', clusters, onClusterClick); return () => { - Array.from(map.getContainer().getElementsByClassName('maplibregl-popup')).forEach(el => el.remove()); + Array.from(map.getContainer().getElementsByClassName('maplibregl-popup')).forEach((el) => el.remove()); map.off('mouseenter', id, onMouseEnter); map.off('mouseleave', id, onMouseLeave); @@ -147,18 +148,18 @@ const PositionsMap = ({ positions }) => { useEffect(() => { map.getSource(id).setData({ type: 'FeatureCollection', - features: positions.filter(it => devices.hasOwnProperty(it.deviceId)).map(position => ({ + features: positions.filter((it) => devices.hasOwnProperty(it.deviceId)).map((position) => ({ type: 'Feature', geometry: { type: 'Point', coordinates: [position.longitude, position.latitude], }, properties: createFeature(devices, position), - })) + })), }); }, [devices, positions]); return null; -} +}; export default PositionsMap; diff --git a/modern/src/map/ReplayPathMap.js b/modern/src/map/ReplayPathMap.js index b40aa69..62b3f27 100644 --- a/modern/src/map/ReplayPathMap.js +++ b/modern/src/map/ReplayPathMap.js @@ -7,8 +7,8 @@ const ReplayPathMap = ({ positions }) => { useEffect(() => { map.addSource(id, { - 'type': 'geojson', - 'data': { + type: 'geojson', + data: { type: 'Feature', geometry: { type: 'LineString', @@ -17,16 +17,16 @@ const ReplayPathMap = ({ positions }) => { }, }); map.addLayer({ - 'source': id, - 'id': id, - 'type': 'line', - 'layout': { + source: id, + id, + type: 'line', + layout: { 'line-join': 'round', 'line-cap': 'round', }, - 'paint': { - 'line-color': '#333', - 'line-width': 5, + paint: { + 'line-color': '#333', + 'line-width': 5, }, }); @@ -37,23 +37,25 @@ const ReplayPathMap = ({ positions }) => { }, []); useEffect(() => { - const coordinates = positions.map(item => [item.longitude, item.latitude]); + const coordinates = positions.map((item) => [item.longitude, item.latitude]); map.getSource(id).setData({ type: 'Feature', geometry: { type: 'LineString', - coordinates: coordinates, + coordinates, }, }); if (coordinates.length) { const bounds = coordinates.reduce((bounds, item) => bounds.extend(item), new maplibregl.LngLatBounds(coordinates[0], coordinates[0])); map.fitBounds(bounds, { - padding: { top: 50, bottom: 250, left: 25, right: 25 }, + padding: { + top: 50, bottom: 250, left: 25, right: 25, + }, }); } }, [positions]); return null; -} +}; export default ReplayPathMap; diff --git a/modern/src/map/SelectedDeviceMap.js b/modern/src/map/SelectedDeviceMap.js index 655fca9..e6c5f58 100644 --- a/modern/src/map/SelectedDeviceMap.js +++ b/modern/src/map/SelectedDeviceMap.js @@ -4,7 +4,7 @@ import { useSelector } from 'react-redux'; import { map } from './Map'; const SelectedDeviceMap = () => { - const mapCenter = useSelector(state => { + const mapCenter = useSelector((state) => { if (state.devices.selectedId) { const position = state.positions.items[state.devices.selectedId] || null; if (position) { @@ -19,6 +19,6 @@ const SelectedDeviceMap = () => { }, [mapCenter]); return null; -} +}; export default SelectedDeviceMap; diff --git a/modern/src/map/StatusView.js b/modern/src/map/StatusView.js index ae049af..20e5b74 100644 --- a/modern/src/map/StatusView.js +++ b/modern/src/map/StatusView.js @@ -1,27 +1,68 @@ -import t from '../common/localization' import React from 'react'; import { useSelector } from 'react-redux'; +import t from '../common/localization'; import { formatPosition } from '../common/formatter'; const StatusView = ({ deviceId, onShowDetails }) => { - const device = useSelector(state => state.devices.items[deviceId]); - const position = useSelector(state => state.positions.items[deviceId]); + const device = useSelector((state) => state.devices.items[deviceId]); + const position = useSelector((state) => state.positions.items[deviceId]); - const handleClick = e => { + const handleClick = (e) => { e.preventDefault(); onShowDetails(position.id); }; return ( <> - {t('deviceStatus')}: {formatPosition(device.status, 'status')}
- {t('sharedLocation')}: {formatPosition(position, 'latitude')} {formatPosition(position, 'longitude')}
- {t('positionSpeed')}: {formatPosition(position.speed, 'speed')}
- {t('positionCourse')}: {formatPosition(position.course, 'course')}
- {t('positionDistance')}: {formatPosition(position.attributes.totalDistance, 'distance')}
- {position.attributes.batteryLevel && - <>{t('positionBattery')}: {formatPosition(position.attributes.batteryLevel, 'batteryLevel')}
- } + + {t('deviceStatus')} + : + + {' '} + {formatPosition(device.status, 'status')} +
+ + {t('sharedLocation')} + : + + {' '} + {formatPosition(position, 'latitude')} + {' '} + {formatPosition(position, 'longitude')} +
+ + {t('positionSpeed')} + : + + {' '} + {formatPosition(position.speed, 'speed')} +
+ + {t('positionCourse')} + : + + {' '} + {formatPosition(position.course, 'course')} +
+ + {t('positionDistance')} + : + + {' '} + {formatPosition(position.attributes.totalDistance, 'distance')} +
+ {position.attributes.batteryLevel + && ( + <> + + {t('positionBattery')} + : + + {' '} + {formatPosition(position.attributes.batteryLevel, 'batteryLevel')} +
+ + )} {t('sharedShowDetails')} ); diff --git a/modern/src/map/mapStyles.js b/modern/src/map/mapStyles.js index 00a8666..9650ead 100644 --- a/modern/src/map/mapStyles.js +++ b/modern/src/map/mapStyles.js @@ -4,7 +4,7 @@ export const styleCustom = (url, attribution) => ({ osm: { type: 'raster', tiles: [url], - attribution: attribution, + attribution, tileSize: 256, }, }, @@ -22,30 +22,30 @@ export const styleOsm = () => styleCustom( ); export const styleCarto = () => ({ - 'version': 8, - 'sources': { + version: 8, + sources: { 'raster-tiles': { - 'type': 'raster', - 'tiles': [ - 'https://a.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png', - 'https://b.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png', - 'https://c.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png', - 'https://d.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png' + type: 'raster', + tiles: [ + 'https://a.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png', + 'https://b.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png', + 'https://c.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png', + 'https://d.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png', ], - 'tileSize': 256, - 'attribution': '© OpenStreetMap contributors, © CARTO' - } + tileSize: 256, + attribution: '© OpenStreetMap contributors, © CARTO', + }, }, - 'glyphs': 'https://cdn.traccar.com/map/fonts/{fontstack}/{range}.pbf', - 'layers': [ + glyphs: 'https://cdn.traccar.com/map/fonts/{fontstack}/{range}.pbf', + layers: [ { - 'id': 'simple-tiles', - 'type': 'raster', - 'source': 'raster-tiles', - 'minzoom': 0, - 'maxzoom': 22, - } - ] + id: 'simple-tiles', + type: 'raster', + source: 'raster-tiles', + minzoom: 0, + maxzoom: 22, + }, + ], }); export const styleMapbox = (style) => `mapbox://styles/mapbox/${style}`; diff --git a/modern/src/map/mapUtil.js b/modern/src/map/mapUtil.js index 67ce345..e3c32f4 100644 --- a/modern/src/map/mapUtil.js +++ b/modern/src/map/mapUtil.js @@ -2,13 +2,11 @@ import { parse, stringify } from 'wellknown'; import canvasTintImage from 'canvas-tint-image'; import circle from '@turf/circle'; -export const loadImage = (url) => { - return new Promise(imageLoaded => { - const image = new Image(); - image.onload = () => imageLoaded(image); - image.src = url; - }); -}; +export const loadImage = (url) => new Promise((imageLoaded) => { + const image = new Image(); + image.onload = () => imageLoaded(image); + image.src = url; +}); export const prepareIcon = (background, icon, color) => { const pixelRatio = window.devicePixelRatio; @@ -32,44 +30,39 @@ export const prepareIcon = (background, icon, color) => { return context.getImageData(0, 0, canvas.width, canvas.height); }; -export const reverseCoordinates = it => { +export const reverseCoordinates = (it) => { if (!it) { return it; - } else if (Array.isArray(it)) { + } if (Array.isArray(it)) { if (it.length === 2 && !Number.isNaN(it[0]) && !Number.isNaN(it[1])) { return [it[1], it[0]]; - } else { - return it.map(it => reverseCoordinates(it)); - } - } else { - return { - ...it, - coordinates: reverseCoordinates(it.coordinates), } + return it.map((it) => reverseCoordinates(it)); } -} + return { + ...it, + coordinates: reverseCoordinates(it.coordinates), + }; +}; export const geofenceToFeature = (item) => { if (item.area.indexOf('CIRCLE') > -1) { - let coordinates = item.area.replace(/CIRCLE|\(|\)|,/g, " ").trim().split(/ +/); - var options = { steps: 32, units: 'meters' }; - let polygon = circle([Number(coordinates[1]), Number(coordinates[0])], Number(coordinates[2]), options); + const coordinates = item.area.replace(/CIRCLE|\(|\)|,/g, ' ').trim().split(/ +/); + const options = { steps: 32, units: 'meters' }; + const polygon = circle([Number(coordinates[1]), Number(coordinates[0])], Number(coordinates[2]), options); return { id: item.id, type: 'Feature', geometry: polygon.geometry, - properties: { name: item.name } - }; - } else { - return { - id: item.id, - type: 'Feature', - geometry: reverseCoordinates(parse(item.area)), - properties: { name: item.name } + properties: { name: item.name }, }; } -} + return { + id: item.id, + type: 'Feature', + geometry: reverseCoordinates(parse(item.area)), + properties: { name: item.name }, + }; +}; -export const geometryToArea = (geometry) => { - return stringify(reverseCoordinates(geometry)); -} +export const geometryToArea = (geometry) => stringify(reverseCoordinates(geometry)); diff --git a/modern/src/reactHelper.js b/modern/src/reactHelper.js index b0eb016..d8e9200 100644 --- a/modern/src/reactHelper.js +++ b/modern/src/reactHelper.js @@ -1,7 +1,6 @@ - import { useRef, useEffect } from 'react'; -export const usePrevious = value => { +export const usePrevious = (value) => { const ref = useRef(); useEffect(() => { ref.current = value; diff --git a/modern/src/reports/ChartReportPage.js b/modern/src/reports/ChartReportPage.js index 8eeedc4..c55ed6d 100644 --- a/modern/src/reports/ChartReportPage.js +++ b/modern/src/reports/ChartReportPage.js @@ -1,5 +1,7 @@ import React, { useState } from 'react'; -import { Grid, FormControl, InputLabel, Select, MenuItem } from '@material-ui/core'; +import { + Grid, FormControl, InputLabel, Select, MenuItem, +} from '@material-ui/core'; import ReportLayout from './ReportLayout'; import ReportFilter from './ReportFilter'; import Graph from './Graph'; @@ -9,66 +11,61 @@ import { speedFromKnots } from '../common/converter'; import t from '../common/localization'; const Filter = ({ children, setItems }) => { - const speedUnit = useAttributePreference('speedUnit'); const handleSubmit = async (deviceId, from, to, mail, headers) => { - const query = new URLSearchParams({ deviceId, from, to, mail }); + const query = new URLSearchParams({ + deviceId, from, to, mail, + }); const response = await fetch(`/api/reports/route?${query.toString()}`, { headers }); if (response.ok) { const positions = await response.json(); - let formattedPositions = positions.map(position => { - return { - speed: Number(speedFromKnots(position.speed, speedUnit)), - altitude: position.altitude, - accuracy: position.accuracy, - fixTime: formatDate(position.fixTime) - } - }); + const formattedPositions = positions.map((position) => ({ + speed: Number(speedFromKnots(position.speed, speedUnit)), + altitude: position.altitude, + accuracy: position.accuracy, + fixTime: formatDate(position.fixTime), + })); setItems(formattedPositions); } - } + }; return ( <> {children} - ) -} - -const ChartType = ({ type, setType }) => { + ); +}; - return ( - - - - {t('reportChartType')} - - - +const ChartType = ({ type, setType }) => ( + + + + {t('reportChartType')} + + - ) -} - + +); const ChartReportPage = () => { - const [items, setItems] = useState([]); const [type, setType] = useState('speed'); return ( - - }> + )} + > - ) -} + ); +}; export default ChartReportPage; diff --git a/modern/src/reports/EventReportPage.js b/modern/src/reports/EventReportPage.js index b938dc8..b5c3dae 100644 --- a/modern/src/reports/EventReportPage.js +++ b/modern/src/reports/EventReportPage.js @@ -1,7 +1,9 @@ import React, { useState } from 'react'; import { DataGrid } from '@material-ui/data-grid'; -import { Grid, FormControl, InputLabel, Select, MenuItem } from '@material-ui/core'; -import { useTheme } from "@material-ui/core/styles"; +import { + Grid, FormControl, InputLabel, Select, MenuItem, +} from '@material-ui/core'; +import { useTheme } from '@material-ui/core/styles'; import { useSelector } from 'react-redux'; import { formatDate } from '../common/formatter'; import ReportFilter from './ReportFilter'; @@ -10,12 +12,13 @@ import { prefixString } from '../common/stringUtils'; import t from '../common/localization'; const Filter = ({ setItems }) => { - const [eventTypes, setEventTypes] = useState(['allEvents']); const handleSubmit = async (deviceId, from, to, mail, headers) => { - const query = new URLSearchParams({ deviceId, from, to, mail }); - eventTypes.forEach(it => query.append('type', it)); + const query = new URLSearchParams({ + deviceId, from, to, mail, + }); + eventTypes.forEach((it) => query.append('type', it)); const response = await fetch(`/api/reports/events?${query.toString()}`, { headers }); if (response.ok) { const contentType = response.headers.get('content-type'); @@ -34,7 +37,7 @@ const Filter = ({ setItems }) => { {t('reportEventTypes')} - setEventTypes(e.target.value)} multiple> {t('eventAll')} {t('eventDeviceOnline')} {t('eventDeviceUnknown')} @@ -58,21 +61,20 @@ const Filter = ({ setItems }) => { ); -} +}; const EventReportPage = () => { - const theme = useTheme(); - const geofences = useSelector(state => state.geofences.items); + const geofences = useSelector((state) => state.geofences.items); const [items, setItems] = useState([]); - const formatGeofence = value => { + const formatGeofence = (value) => { if (value > 0) { - const geofence = geofences[value]; - return geofence ? geofence.name : ''; + const geofence = geofences[value]; + return geofence ? geofence.name : ''; } return null; - } + }; const columns = [{ headerName: t('positionFixTime'), @@ -101,12 +103,13 @@ const EventReportPage = () => { return ( }> + rows={items} + columns={columns} + hideFooter + autoHeight + /> ); -} +}; export default EventReportPage; diff --git a/modern/src/reports/Graph.js b/modern/src/reports/Graph.js index 990eb5d..63d24ee 100644 --- a/modern/src/reports/Graph.js +++ b/modern/src/reports/Graph.js @@ -1,9 +1,11 @@ import React from 'react'; import { withWidth } from '@material-ui/core'; -import {LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts'; +import { + LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, +} from 'recharts'; -const CustomizedAxisTick = ({ x, y, payload }) =>{ - if(!payload.value) { +const CustomizedAxisTick = ({ x, y, payload }) => { + if (!payload.value) { return payload.value; } const parts = payload.value.split(' '); @@ -13,22 +15,19 @@ const CustomizedAxisTick = ({ x, y, payload }) =>{ {parts[1]} ); -} +}; -const Graph = ({ type, items }) => { - - return ( - - - } height={60} /> - - - - - - - - ); -} +const Graph = ({ type, items }) => ( + + + } height={60} /> + + + + + + + +); export default withWidth()(Graph); diff --git a/modern/src/reports/ReplayPage.js b/modern/src/reports/ReplayPage.js index dfa9999..12bbd35 100644 --- a/modern/src/reports/ReplayPage.js +++ b/modern/src/reports/ReplayPage.js @@ -1,5 +1,7 @@ import React, { useState } from 'react'; -import { Accordion, AccordionDetails, AccordionSummary, Container, makeStyles, Paper, Slider, Tooltip, Typography } from '@material-ui/core'; +import { + Accordion, AccordionDetails, AccordionSummary, Container, makeStyles, Paper, Slider, Tooltip, Typography, +} from '@material-ui/core'; import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import MainToolbar from '../MainToolbar'; import Map from '../map/Map'; @@ -9,7 +11,7 @@ import PositionsMap from '../map/PositionsMap'; import { formatPosition } from '../common/formatter'; import ReportFilter from './ReportFilter'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles((theme) => ({ root: { height: '100%', display: 'flex', @@ -31,13 +33,11 @@ const useStyles = makeStyles(theme => ({ }, })); -const TimeLabel = ({ children, open, value }) => { - return ( - - {children} - - ); -}; +const TimeLabel = ({ children, open, value }) => ( + + {children} + +); const ReplayPage = () => { const classes = useStyles(); @@ -61,12 +61,12 @@ const ReplayPage = () => { - {index < positions.length && - - } + {index < positions.length + && } - {!!positions.length && + {!!positions.length + && ( { value={index} onChange={(_, index) => setIndex(index)} valueLabelDisplay="auto" - valueLabelFormat={i => i < positions.length ? formatPosition(positions[i], 'fixTime') : ''} + valueLabelFormat={(i) => (i < positions.length ? formatPosition(positions[i], 'fixTime') : '')} ValueLabelComponent={TimeLabel} - /> + /> - } + )}
setExpanded(!expanded)}> }> - + {t('reportConfigure')} @@ -95,6 +95,6 @@ const ReplayPage = () => {
); -} +}; export default ReplayPage; diff --git a/modern/src/reports/ReportFilter.js b/modern/src/reports/ReportFilter.js index 524f7bb..dec8d01 100644 --- a/modern/src/reports/ReportFilter.js +++ b/modern/src/reports/ReportFilter.js @@ -1,11 +1,13 @@ import React, { useState } from 'react'; -import { FormControl, InputLabel, Select, MenuItem, Button, TextField, Grid, Typography } from '@material-ui/core'; +import { + FormControl, InputLabel, Select, MenuItem, Button, TextField, Grid, Typography, +} from '@material-ui/core'; import { useSelector } from 'react-redux'; import moment from 'moment'; import t from '../common/localization'; const ReportFilter = ({ children, handleSubmit, showOnly }) => { - const devices = useSelector(state => Object.values(state.devices.items)); + const devices = useSelector((state) => Object.values(state.devices.items)); const [deviceId, setDeviceId] = useState(); const [period, setPeriod] = useState('today'); const [from, setFrom] = useState(moment().subtract(1, 'hour')); @@ -51,9 +53,9 @@ const ReportFilter = ({ children, handleSubmit, showOnly }) => { selectedFrom.toISOString(), selectedTo.toISOString(), mail, - { Accept: accept } + { Accept: accept }, ); - } + }; return ( @@ -81,56 +83,69 @@ const ReportFilter = ({ children, handleSubmit, showOnly }) => { - {period === 'custom' && + {period === 'custom' && ( + setFrom(moment(e.target.value, moment.HTML5_FMT.DATETIME_LOCAL))} - fullWidth /> - } - {period === 'custom' && + onChange={(e) => setFrom(moment(e.target.value, moment.HTML5_FMT.DATETIME_LOCAL))} + fullWidth + /> + + )} + {period === 'custom' && ( + setTo(moment(e.target.value, moment.HTML5_FMT.DATETIME_LOCAL))} - fullWidth /> - } + onChange={(e) => setTo(moment(e.target.value, moment.HTML5_FMT.DATETIME_LOCAL))} + fullWidth + /> + + )} {children} - - {!showOnly && + {!showOnly + && ( - - } - {!showOnly && + + + )} + {!showOnly + && ( - - } + + + )} ); -} +}; export default ReportFilter; diff --git a/modern/src/reports/ReportLayout.js b/modern/src/reports/ReportLayout.js index 5b54335..92ffc0c 100644 --- a/modern/src/reports/ReportLayout.js +++ b/modern/src/reports/ReportLayout.js @@ -7,7 +7,7 @@ import { Drawer, makeStyles, IconButton, - Hidden + Hidden, } from '@material-ui/core'; import TimelineIcon from '@material-ui/icons/Timeline'; import PauseCircleFilledIcon from '@material-ui/icons/PauseCircleFilled'; @@ -21,35 +21,35 @@ import SideNav from '../components/SideNav'; import NavBar from '../components/NavBar'; import t from '../common/localization'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles((theme) => ({ root: { display: 'flex', - height: '100%' + height: '100%', }, drawerContainer: { - width: theme.dimensions.drawerWidthDesktop + width: theme.dimensions.drawerWidthDesktop, }, drawer: { width: theme.dimensions.drawerWidthDesktop, [theme.breakpoints.down('md')]: { - width: theme.dimensions.drawerWidthTablet - } + width: theme.dimensions.drawerWidthTablet, + }, }, content: { flex: 1, - padding: theme.spacing(5, 3, 3, 3) + padding: theme.spacing(5, 3, 3, 3), }, drawerHeader: { ...theme.mixins.toolbar, display: 'flex', alignItems: 'center', - padding: theme.spacing(0, 1) + padding: theme.spacing(0, 1), }, toolbar: { [theme.breakpoints.down('md')]: { - ...theme.mixins.toolbar - } - } + ...theme.mixins.toolbar, + }, + }, })); const routes = [ @@ -57,24 +57,24 @@ const routes = [ { name: t('reportEvents'), href: '/reports/event', - icon: + icon: , }, { name: t('reportTrips'), href: '/reports/trip', - icon: + icon: , }, { name: t('reportStops'), href: '/reports/stop', - icon: + icon: , }, { name: t('reportSummary'), href: '/reports/summary', - icon: + icon: , }, - { name: t('reportChart'), href: '/reports/chart', icon: } + { name: t('reportChart'), href: '/reports/chart', icon: }, ]; const ReportLayout = ({ children, filter }) => { @@ -85,7 +85,7 @@ const ReportLayout = ({ children, filter }) => { const [reportTitle, setReportTitle] = useState(); useEffect(() => { - routes.forEach(route => { + routes.forEach((route) => { switch (location.pathname) { case `${route.href}`: setReportTitle(route.name); diff --git a/modern/src/reports/RouteReportPage.js b/modern/src/reports/RouteReportPage.js index c09d4f5..fffcdcb 100644 --- a/modern/src/reports/RouteReportPage.js +++ b/modern/src/reports/RouteReportPage.js @@ -1,17 +1,20 @@ import React, { useState } from 'react'; import { Paper } from '@material-ui/core'; import { DataGrid } from '@material-ui/data-grid'; -import { useTheme } from "@material-ui/core/styles"; -import { formatDistance, formatSpeed, formatBoolean, formatDate, formatCoordinate } from '../common/formatter'; +import { useTheme } from '@material-ui/core/styles'; +import { + formatDistance, formatSpeed, formatBoolean, formatDate, formatCoordinate, +} from '../common/formatter'; import ReportFilter from './ReportFilter'; import ReportLayout from './ReportLayout'; import { useAttributePreference, usePreference } from '../common/preferences'; import t from '../common/localization'; const Filter = ({ setItems }) => { - const handleSubmit = async (deviceId, from, to, mail, headers) => { - const query = new URLSearchParams({ deviceId, from, to, mail }); + const query = new URLSearchParams({ + deviceId, from, to, mail, + }); const response = await fetch(`/api/reports/route?${query.toString()}`, { headers }); if (response.ok) { const contentType = response.headers.get('content-type'); @@ -23,7 +26,7 @@ const Filter = ({ setItems }) => { } } } - } + }; return ; }; @@ -78,7 +81,7 @@ const RouteReportPage = () => { width: theme.dimensions.columnWidthNumber, valueGetter: ({ row }) => row.attributes.totalDistance, valueFormatter: ({ value }) => formatDistance(value, distanceUnit), - }] + }]; const [items, setItems] = useState([]); @@ -86,10 +89,11 @@ const RouteReportPage = () => { }> + rows={items} + columns={columns} + hideFooter + autoHeight + /> ); diff --git a/modern/src/reports/StopReportPage.js b/modern/src/reports/StopReportPage.js index 57f5956..d2e7e7e 100644 --- a/modern/src/reports/StopReportPage.js +++ b/modern/src/reports/StopReportPage.js @@ -1,16 +1,19 @@ import React, { useState } from 'react'; import { DataGrid } from '@material-ui/data-grid'; -import { useTheme } from "@material-ui/core/styles"; -import { formatDistance, formatHours, formatDate, formatVolume } from '../common/formatter'; +import { useTheme } from '@material-ui/core/styles'; +import { + formatDistance, formatHours, formatDate, formatVolume, +} from '../common/formatter'; import ReportFilter from './ReportFilter'; import ReportLayout from './ReportLayout'; import { useAttributePreference } from '../common/preferences'; import t from '../common/localization'; const Filter = ({ setItems }) => { - const handleSubmit = async (deviceId, from, to, mail, headers) => { - const query = new URLSearchParams({ deviceId, from, to, mail }); + const query = new URLSearchParams({ + deviceId, from, to, mail, + }); const response = await fetch(`/api/reports/stops?${query.toString()}`, { headers }); if (response.ok) { const contentType = response.headers.get('content-type'); @@ -22,13 +25,12 @@ const Filter = ({ setItems }) => { } } } - } + }; return ; }; const StopReportPage = () => { - const theme = useTheme(); const distanceUnit = useAttributePreference('distanceUnit'); @@ -41,7 +43,7 @@ const StopReportPage = () => { field: 'startTime', type: 'dateTime', width: theme.dimensions.columnWidthDate, - valueFormatter: ({ value }) => formatDate(value), + valueFormatter: ({ value }) => formatDate(value), }, { headerName: t('positionOdometer'), field: 'startOdometer', @@ -53,7 +55,7 @@ const StopReportPage = () => { field: 'address', type: 'string', hide: true, - width: theme.dimensions.columnWidthString, + width: theme.dimensions.columnWidthString, }, { headerName: t('reportEndTime'), field: 'endTime', @@ -78,17 +80,18 @@ const StopReportPage = () => { type: 'number', width: theme.dimensions.columnWidthNumber, hide: true, - valueFormatter: ({ value }) => formatVolume(value, volumeUnit), - }] - + valueFormatter: ({ value }) => formatVolume(value, volumeUnit), + }]; + return ( }> Math.random()} /> + getRowId={() => Math.random()} + /> ); }; diff --git a/modern/src/reports/SummaryReportPage.js b/modern/src/reports/SummaryReportPage.js index 53e697d..4523e65 100644 --- a/modern/src/reports/SummaryReportPage.js +++ b/modern/src/reports/SummaryReportPage.js @@ -1,19 +1,22 @@ import React, { useState } from 'react'; import { DataGrid } from '@material-ui/data-grid'; import { Grid, FormControlLabel, Checkbox } from '@material-ui/core'; -import { useTheme } from "@material-ui/core/styles"; -import { formatDistance, formatHours, formatDate, formatSpeed, formatVolume } from '../common/formatter'; +import { useTheme } from '@material-ui/core/styles'; +import { + formatDistance, formatHours, formatDate, formatSpeed, formatVolume, +} from '../common/formatter'; import ReportFilter from './ReportFilter'; import ReportLayout from './ReportLayout'; import { useAttributePreference } from '../common/preferences'; import t from '../common/localization'; const Filter = ({ setItems }) => { - const [daily, setDaily] = useState(false); const handleSubmit = async (deviceId, from, to, mail, headers) => { - const query = new URLSearchParams({ deviceId, from, to, daily, mail }); + const query = new URLSearchParams({ + deviceId, from, to, daily, mail, + }); const response = await fetch(`/api/reports/summary?${query.toString()}`, { headers }); if (response.ok) { const contentType = response.headers.get('content-type'); @@ -25,21 +28,21 @@ const Filter = ({ setItems }) => { } } } - } + }; return ( setDaily(e.target.checked)} />} - label={t('reportDaily')} /> + control={ setDaily(e.target.checked)} />} + label={t('reportDaily')} + /> ); -} +}; const SummaryReportPage = () => { - const theme = useTheme(); const distanceUnit = useAttributePreference('distanceUnit'); @@ -96,19 +99,20 @@ const SummaryReportPage = () => { type: 'number', width: theme.dimensions.columnWidthNumber, hide: true, - valueFormatter: ({ value }) => formatVolume(value, volumeUnit), - }] - + valueFormatter: ({ value }) => formatVolume(value, volumeUnit), + }]; + return ( }> Math.random()} /> + getRowId={() => Math.random()} + /> ); -} +}; export default SummaryReportPage; diff --git a/modern/src/reports/TripReportPage.js b/modern/src/reports/TripReportPage.js index e8c9129..f611dde 100644 --- a/modern/src/reports/TripReportPage.js +++ b/modern/src/reports/TripReportPage.js @@ -1,16 +1,19 @@ import React, { useState } from 'react'; import { DataGrid } from '@material-ui/data-grid'; -import { useTheme } from "@material-ui/core/styles"; -import { formatDistance, formatSpeed, formatHours, formatDate, formatVolume } from '../common/formatter'; +import { useTheme } from '@material-ui/core/styles'; +import { + formatDistance, formatSpeed, formatHours, formatDate, formatVolume, +} from '../common/formatter'; import ReportFilter from './ReportFilter'; import ReportLayout from './ReportLayout'; import { useAttributePreference } from '../common/preferences'; import t from '../common/localization'; const Filter = ({ setItems }) => { - const handleSubmit = async (deviceId, from, to, mail, headers) => { - const query = new URLSearchParams({ deviceId, from, to, mail }); + const query = new URLSearchParams({ + deviceId, from, to, mail, + }); const response = await fetch(`/api/reports/trips?${query.toString()}`, { headers }); if (response.ok) { const contentType = response.headers.get('content-type'); @@ -22,15 +25,14 @@ const Filter = ({ setItems }) => { } } } - } + }; return ; -} +}; const TripReportPage = () => { - const theme = useTheme(); - + const distanceUnit = useAttributePreference('distanceUnit'); const speedUnit = useAttributePreference('speedUnit'); const volumeUnit = useAttributePreference('volumeUnit'); @@ -109,19 +111,20 @@ const TripReportPage = () => { field: 'driverName', type: 'string', width: theme.dimensions.columnWidthString, - hide: true - }] + hide: true, + }]; return ( }> Math.random()} /> + getRowId={() => Math.random()} + /> ); -} +}; export default TripReportPage; diff --git a/modern/src/settings/ComputedAttributePage.js b/modern/src/settings/ComputedAttributePage.js index 73759fa..fea613a 100644 --- a/modern/src/settings/ComputedAttributePage.js +++ b/modern/src/settings/ComputedAttributePage.js @@ -1,19 +1,19 @@ import React, { useState } from 'react'; -import { Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, FormControl, InputLabel, MenuItem, Select, TextField } from "@material-ui/core"; +import { + Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, FormControl, InputLabel, MenuItem, Select, TextField, +} from '@material-ui/core'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import t from '../common/localization'; import EditItemView from '../EditItemView'; -import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import positionAttributes from '../attributes/positionAttributes'; - const useStyles = makeStyles(() => ({ details: { flexDirection: 'column', }, })); -const ComputedAttributePage =() => { - +const ComputedAttributePage = () => { const classes = useStyles(); const [item, setItem] = useState(); const [key, setKey] = useState(); @@ -24,20 +24,21 @@ const ComputedAttributePage =() => { type: value.type, })); - const handleChange = event => { + const handleChange = (event) => { const newValue = event.target.value; setKey(newValue); const positionAttribute = positionAttributes[newValue]; - if(positionAttribute && positionAttribute.type) { - setItem({...item, attribute: newValue, type: positionAttribute.type}); + if (positionAttribute && positionAttribute.type) { + setItem({ ...item, attribute: newValue, type: positionAttribute.type }); } else { - setItem({...item, attribute: newValue}); + setItem({ ...item, attribute: newValue }); } - } + }; return ( - {item && + {item + && ( }> @@ -48,46 +49,51 @@ const ComputedAttributePage =() => { setItem({...item, description: event.target.value})} + onChange={(event) => setItem({ ...item, description: event.target.value })} label={t('sharedDescription')} - variant="filled" /> + variant="filled" + /> {t('sharedAttribute')} - {options.map((option) => ( {option.name} ))} - + setItem({...item, expression: event.target.value})} + onChange={(event) => setItem({ ...item, expression: event.target.value })} label={t('sharedExpression')} multiline rows={4} - variant="filled" /> + variant="filled" + /> + disabled={key in positionAttributes} + > {t('sharedType')} - } + )} - ) -} + ); +}; export default ComputedAttributePage; diff --git a/modern/src/settings/ComputedAttributesPage.js b/modern/src/settings/ComputedAttributesPage.js index d747598..fcf49d3 100644 --- a/modern/src/settings/ComputedAttributesPage.js +++ b/modern/src/settings/ComputedAttributesPage.js @@ -1,5 +1,7 @@ import React, { useState } from 'react'; -import { TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton } from '@material-ui/core'; +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'; @@ -7,11 +9,11 @@ import { useEffectAsync } from '../reactHelper'; import EditCollectionView from '../EditCollectionView'; import OptionsLayout from './OptionsLayout'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles((theme) => ({ columnAction: { width: theme.spacing(1), - padding: theme.spacing(0, 1) - } + padding: theme.spacing(0, 1), + }, })); const ComputedAttributeView = ({ updateTimestamp, onMenuClick }) => { @@ -19,7 +21,7 @@ const ComputedAttributeView = ({ updateTimestamp, onMenuClick }) => { const [items, setItems] = useState([]); const adminEnabled = useSelector( - state => state.session.user && state.session.user.administrator + (state) => state.session.user && state.session.user.administrator, ); useEffectAsync(async () => { @@ -31,50 +33,48 @@ const ComputedAttributeView = ({ updateTimestamp, onMenuClick }) => { return ( - - - - {adminEnabled && } - {t('sharedDescription')} - {t('sharedAttribute')} - {t('sharedExpression')} - {t('sharedType')} - - - - {items.map(item => ( - +
+ + + {adminEnabled && } + {t('sharedDescription')} + {t('sharedAttribute')} + {t('sharedExpression')} + {t('sharedType')} + + + + {items.map((item) => ( + {adminEnabled && ( - onMenuClick(event.currentTarget, item.id)} - > + onMenuClick(event.currentTarget, item.id)} + > )} - {item.description} - {item.attribute} - {item.expression} - {item.type} - - ))} - -
+ {item.description} + {item.attribute} + {item.expression} + {item.type} + + ))} + +
); }; -const ComputedAttributesPage = () => { - return ( - - - - ); -}; +const ComputedAttributesPage = () => ( + + + +); export default ComputedAttributesPage; diff --git a/modern/src/settings/DriverPage.js b/modern/src/settings/DriverPage.js index 86feab8..01400c5 100644 --- a/modern/src/settings/DriverPage.js +++ b/modern/src/settings/DriverPage.js @@ -1,9 +1,11 @@ import React, { useState } from 'react'; import TextField from '@material-ui/core/TextField'; +import { + Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, +} from '@material-ui/core'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import t from '../common/localization'; import EditItemView from '../EditItemView'; -import { Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography } from '@material-ui/core'; -import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import EditAttributesView from '../attributes/EditAttributesView'; const useStyles = makeStyles(() => ({ @@ -19,7 +21,8 @@ const DriverPage = () => { return ( - {item && + {item + && ( <> }> @@ -31,15 +34,17 @@ const DriverPage = () => { setItem({...item, name: event.target.value})} + onChange={(event) => setItem({ ...item, name: event.target.value })} label={t('sharedName')} - variant="filled" /> + variant="filled" + /> setItem({...item, uniqueId: event.target.value})} + onChange={(event) => setItem({ ...item, uniqueId: event.target.value })} label={t('deviceIdentifier')} - variant="filled" /> + variant="filled" + /> @@ -51,15 +56,15 @@ const DriverPage = () => { setItem({...item, attributes})} + setAttributes={(attributes) => setItem({ ...item, attributes })} definitions={{}} - /> + /> - } + )} ); -} +}; export default DriverPage; diff --git a/modern/src/settings/DriversPage.js b/modern/src/settings/DriversPage.js index d5427b2..57f69b6 100644 --- a/modern/src/settings/DriversPage.js +++ b/modern/src/settings/DriversPage.js @@ -1,16 +1,18 @@ import React, { useState } from 'react'; -import { TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton } from '@material-ui/core'; +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 => ({ +const useStyles = makeStyles((theme) => ({ columnAction: { width: theme.spacing(1), - padding: theme.spacing(0, 1) - } + padding: theme.spacing(0, 1), + }, })); const DriversView = ({ updateTimestamp, onMenuClick }) => { @@ -27,44 +29,42 @@ const DriversView = ({ updateTimestamp, onMenuClick }) => { return ( - - - - - {t('sharedName')} - {t('deviceIdentifier')} - - - - {items.map(item => ( - - +
+ + + + {t('sharedName')} + {t('deviceIdentifier')} + + + + {items.map((item) => ( + + onMenuClick(event.currentTarget, item.id)} + onClick={(event) => onMenuClick(event.currentTarget, item.id)} > - - - - {item.name} - {item.uniqueId} - - ))} - -
+ + + + {item.name} + {item.uniqueId} + + ))} + +
); }; -const DriversPage = () => { - return ( - - - - ); -}; +const DriversPage = () => ( + + + +); export default DriversPage; diff --git a/modern/src/settings/GroupPage.js b/modern/src/settings/GroupPage.js index b9fa871..f9af0f8 100644 --- a/modern/src/settings/GroupPage.js +++ b/modern/src/settings/GroupPage.js @@ -1,10 +1,12 @@ import React, { useState } from 'react'; import TextField from '@material-ui/core/TextField'; +import { + Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, +} from '@material-ui/core'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import t from '../common/localization'; import EditItemView from '../EditItemView'; -import { Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography } from '@material-ui/core'; -import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import EditAttributesView from '../attributes/EditAttributesView'; import deviceAttributes from '../attributes/deviceAttributes'; import SelectField from '../form/SelectField'; @@ -22,7 +24,8 @@ const GroupPage = () => { return ( - {item && + {item + && ( <> }> @@ -34,9 +37,10 @@ const GroupPage = () => { setItem({...item, name: event.target.value})} + onChange={(event) => setItem({ ...item, name: event.target.value })} label={t('sharedName')} - variant="filled" /> + variant="filled" + /> @@ -49,10 +53,11 @@ const GroupPage = () => { setItem({...item, groupId: Number(event.target.value)})} + onChange={(event) => setItem({ ...item, groupId: Number(event.target.value) })} endpoint="/api/groups" label={t('groupParent')} - variant="filled" /> + variant="filled" + /> @@ -64,15 +69,15 @@ const GroupPage = () => { setItem({...item, attributes})} + setAttributes={(attributes) => setItem({ ...item, attributes })} definitions={deviceAttributes} - /> + /> - } + )} ); -} +}; export default GroupPage; diff --git a/modern/src/settings/GroupsPage.js b/modern/src/settings/GroupsPage.js index 2fc65c1..3b1058e 100644 --- a/modern/src/settings/GroupsPage.js +++ b/modern/src/settings/GroupsPage.js @@ -1,16 +1,18 @@ import React, { useState } from 'react'; -import { TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton } from '@material-ui/core'; +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 => ({ +const useStyles = makeStyles((theme) => ({ columnAction: { width: theme.spacing(1), - padding: theme.spacing(0, 1) - } + padding: theme.spacing(0, 1), + }, })); const GroupsView = ({ updateTimestamp, onMenuClick }) => { @@ -27,42 +29,40 @@ const GroupsView = ({ updateTimestamp, onMenuClick }) => { return ( - - - - - {t('sharedName')} - - - - {items.map(item => ( - - +
+ + + + {t('sharedName')} + + + + {items.map((item) => ( + + onMenuClick(event.currentTarget, item.id)} + onClick={(event) => onMenuClick(event.currentTarget, item.id)} > - - - - {item.name} - - ))} - -
+ + + + {item.name} + + ))} + +
); }; -const GroupsPage = () => { - return ( - - - - ); -}; +const GroupsPage = () => ( + + + +); export default GroupsPage; diff --git a/modern/src/settings/MaintenancePage.js b/modern/src/settings/MaintenancePage.js index 3b4fde5..9d60937 100644 --- a/modern/src/settings/MaintenancePage.js +++ b/modern/src/settings/MaintenancePage.js @@ -1,14 +1,18 @@ import React, { useState } from 'react'; +import { + Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, TextField, FormControl, InputLabel, MenuItem, Select, +} from '@material-ui/core'; +import InputAdornment from '@material-ui/core/InputAdornment'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import t from '../common/localization'; import { prefixString } from '../common/stringUtils'; import EditItemView from '../EditItemView'; -import { Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, TextField, FormControl, InputLabel, MenuItem, Select, } from '@material-ui/core'; -import InputAdornment from '@material-ui/core/InputAdornment'; -import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import EditAttributesView from '../attributes/EditAttributesView'; import positionAttributes from '../attributes/positionAttributes'; import { useAttributePreference } from '../common/preferences'; -import { speedFromKnots, speedToKnots, distanceFromMeters, distanceToMeters } from '../common/converter'; +import { + speedFromKnots, speedToKnots, distanceFromMeters, distanceToMeters, +} from '../common/converter'; const useStyles = makeStyles(() => ({ details: { @@ -17,46 +21,46 @@ const useStyles = makeStyles(() => ({ })); const MaintenancePage = () => { - const classes = useStyles(); const [item, setItem] = useState(); - const [labels, setLabels] = useState({start: '', period: ''}); + const [labels, setLabels] = useState({ start: '', period: '' }); const speedUnit = useAttributePreference('speedUnit'); const distanceUnit = useAttributePreference('distanceUnit'); const convertToList = (attributes) => { - let otherList = []; + const otherList = []; for (const key in attributes) { const value = attributes[key]; if (value.type === 'number') { - otherList.push({key, name: value.name, type: value.type}); + otherList.push({ key, name: value.name, type: value.type }); } } return otherList; - } + }; - const onMaintenanceTypeChange = event => { + const onMaintenanceTypeChange = (event) => { const newValue = event.target.value; - setItem({ ...item, type: newValue, start: 0, period: 0 }); + setItem({ + ...item, type: newValue, start: 0, period: 0, + }); const attribute = positionAttributes[newValue]; if (attribute && attribute.dataType) { switch (attribute.dataType) { case 'distance': - setLabels({ ...labels, start: t(prefixString('shared', distanceUnit)), period: t(prefixString('shared', distanceUnit))}); + setLabels({ ...labels, start: t(prefixString('shared', distanceUnit)), period: t(prefixString('shared', distanceUnit)) }); break; case 'speed': - setLabels({ ...labels, start: t(prefixString('shared', speedUnit)), period: t(prefixString('shared', speedUnit))}); + setLabels({ ...labels, start: t(prefixString('shared', speedUnit)), period: t(prefixString('shared', speedUnit)) }); break; default: break; } } - } - - const rawToValue = value => { + }; + const rawToValue = (value) => { const attribute = positionAttributes[item.type]; if (attribute && attribute.dataType) { switch (attribute.dataType) { @@ -69,10 +73,9 @@ const MaintenancePage = () => { } } return value; - } - - const valueToRaw = value => { + }; + const valueToRaw = (value) => { const attribute = positionAttributes[item.type]; if (attribute && attribute.dataType) { switch (attribute.dataType) { @@ -85,11 +88,12 @@ const MaintenancePage = () => { } } return value; - } + }; return ( - {item && + {item + && ( <> }> @@ -101,39 +105,43 @@ const MaintenancePage = () => { setItem({...item, name: event.target.value})} + onChange={(event) => setItem({ ...item, name: event.target.value })} label={t('sharedName')} - variant="filled" /> + variant="filled" + /> {t('sharedType')} - + {convertToList(positionAttributes).map(({ key, name }) => ( + {name} + ))} - + setItem({...item, start: valueToRaw(event.target.value)})} + onChange={(event) => setItem({ ...item, start: valueToRaw(event.target.value) })} label={t('maintenanceStart')} variant="filled" InputProps={{ - endAdornment: {labels.start}, - }} /> + endAdornment: {labels.start}, + }} + /> setItem({...item, period: valueToRaw(event.target.value)})} + onChange={(event) => setItem({ ...item, period: valueToRaw(event.target.value) })} label={t('maintenancePeriod')} variant="filled" InputProps={{ - endAdornment: {labels.period}, - }} /> + endAdornment: {labels.period}, + }} + /> @@ -145,15 +153,15 @@ const MaintenancePage = () => { setItem({...item, attributes})} + setAttributes={(attributes) => setItem({ ...item, attributes })} definitions={{}} - /> + /> - + - } + )} ); -} +}; export default MaintenancePage; diff --git a/modern/src/settings/MaintenancesPage.js b/modern/src/settings/MaintenancesPage.js index d713eaa..b8e74d2 100644 --- a/modern/src/settings/MaintenancesPage.js +++ b/modern/src/settings/MaintenancesPage.js @@ -1,5 +1,7 @@ import React, { useState } from 'react'; -import { TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton } from '@material-ui/core'; +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'; @@ -10,11 +12,11 @@ import { formatDistance, formatSpeed } from '../common/formatter'; import { useAttributePreference } from '../common/preferences'; import OptionsLayout from './OptionsLayout'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles((theme) => ({ columnAction: { width: theme.spacing(1), - padding: theme.spacing(0, 1) - } + padding: theme.spacing(0, 1), + }, })); const MaintenancesView = ({ updateTimestamp, onMenuClick }) => { @@ -37,7 +39,7 @@ const MaintenancesView = ({ updateTimestamp, onMenuClick }) => { switch (attribute.dataType) { case 'speed': return formatSpeed(value, speedUnit); - case 'distance': + case 'distance': return formatDistance(value, distanceUnit); default: return value; @@ -49,48 +51,46 @@ const MaintenancesView = ({ updateTimestamp, onMenuClick }) => { return ( - - - - - {t('sharedName')} - {t('sharedType')} - {t('maintenanceStart')} - {t('maintenancePeriod')} - - - - {items.map(item => ( - - +
+ + + + {t('sharedName')} + {t('sharedType')} + {t('maintenanceStart')} + {t('maintenancePeriod')} + + + + {items.map((item) => ( + + onMenuClick(event.currentTarget, item.id)} + onClick={(event) => onMenuClick(event.currentTarget, item.id)} > - - - - {item.name} - {item.type} - {convertAttribute(item.type, item.start)} - {convertAttribute(item.type, item.period)} - - ))} - -
+ + + + {item.name} + {item.type} + {convertAttribute(item.type, item.start)} + {convertAttribute(item.type, item.period)} + + ))} + +
); }; -const MaintenacesPage = () => { - return ( - - - - ); -}; +const MaintenacesPage = () => ( + + + +); export default MaintenacesPage; diff --git a/modern/src/settings/NotificationPage.js b/modern/src/settings/NotificationPage.js index 33904e7..11c427f 100644 --- a/modern/src/settings/NotificationPage.js +++ b/modern/src/settings/NotificationPage.js @@ -1,9 +1,11 @@ import React, { useState } from 'react'; +import { + Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, FormControlLabel, Checkbox, +} from '@material-ui/core'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import t, { findStringKeys } from '../common/localization'; import EditItemView from '../EditItemView'; -import { Accordion, AccordionSummary, AccordionDetails, makeStyles, Typography, FormControlLabel, Checkbox } from '@material-ui/core'; -import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import { prefixString, unprefixString } from '../common/stringUtils'; import SelectField from '../form/SelectField'; @@ -18,14 +20,15 @@ const NotificationPage = () => { const [item, setItem] = useState(); - const alarms = findStringKeys(it => it.startsWith('alarm')).map(it => ({ + const alarms = findStringKeys((it) => it.startsWith('alarm')).map((it) => ({ key: unprefixString('alarm', it), name: t(it), })); return ( - {item && + {item + && ( <> }> @@ -38,47 +41,52 @@ const NotificationPage = () => { margin="normal" value={item.type || 'alarm'} emptyValue={null} - onChange={e => setItem({...item, type: e.target.value})} + onChange={(e) => setItem({ ...item, type: e.target.value })} endpoint="/api/notifications/types" - keyGetter={it => it.type} - titleGetter={it => t(prefixString('event', it.type))} + keyGetter={(it) => it.type} + titleGetter={(it) => t(prefixString('event', it.type))} label={t('sharedType')} - variant="filled" /> + variant="filled" + /> setItem({...item, notificators: e.target.value.join()})} + onChange={(e) => setItem({ ...item, notificators: e.target.value.join() })} endpoint="/api/notifications/notificators" - keyGetter={it => it.type} - titleGetter={it => t(prefixString('notificator', it.type))} + keyGetter={(it) => it.type} + titleGetter={(it) => t(prefixString('notificator', it.type))} label={t('notificationNotificators')} - variant="filled" /> - {(!item.type || item.type === 'alarm') && + variant="filled" + /> + {(!item.type || item.type === 'alarm') + && ( setItem({...item, attributes: {...item.attributes, alarms: e.target.value.join()}})} + onChange={(e) => setItem({ ...item, attributes: { ...item.attributes, alarms: e.target.value.join() } })} data={alarms} - keyGetter={it => it.key} + keyGetter={(it) => it.key} label={t('sharedAlarms')} - variant="filled" /> - } + variant="filled" + /> + )} setItem({...item, always: event.target.checked})} - /> - } - label={t('notificationAlways')} /> + onChange={(event) => setItem({ ...item, always: event.target.checked })} + /> + )} + label={t('notificationAlways')} + /> - } + )} ); -} +}; export default NotificationPage; diff --git a/modern/src/settings/NotificationsPage.js b/modern/src/settings/NotificationsPage.js index 5707f89..079f88d 100644 --- a/modern/src/settings/NotificationsPage.js +++ b/modern/src/settings/NotificationsPage.js @@ -1,5 +1,7 @@ import React, { useState } from 'react'; -import { TableContainer, Table, TableRow, TableCell, TableHead, TableBody, makeStyles, IconButton } from '@material-ui/core'; +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'; @@ -8,11 +10,11 @@ import { prefixString } from '../common/stringUtils'; import { formatBoolean } from '../common/formatter'; import OptionsLayout from './OptionsLayout'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles((theme) => ({ columnAction: { width: theme.spacing(1), - padding: theme.spacing(0, 1) - } + padding: theme.spacing(0, 1), + }, })); const NotificationsView = ({ updateTimestamp, onMenuClick }) => { @@ -32,7 +34,7 @@ const NotificationsView = ({ updateTimestamp, onMenuClick }) => { return value .split(/[, ]+/) .filter(Boolean) - .map(it => t(prefixString(prefix, it))) + .map((it) => t(prefixString(prefix, it))) .join(', '); } return ''; @@ -40,52 +42,50 @@ const NotificationsView = ({ updateTimestamp, onMenuClick }) => { return ( - - - - - {t('notificationType')} - {t('notificationAlways')} - {t('sharedAlarms')} - {t('notificationNotificators')} - - - - {items.map(item => ( - - +
+ + + + {t('notificationType')} + {t('notificationAlways')} + {t('sharedAlarms')} + {t('notificationNotificators')} + + + + {items.map((item) => ( + + onMenuClick(event.currentTarget, item.id)} + onClick={(event) => onMenuClick(event.currentTarget, item.id)} > - - - - {t(prefixString('event', item.type))} - {formatBoolean(item.always)} + + + + {t(prefixString('event', item.type))} + {formatBoolean(item.always)} {formatList('alarm', item.attributes.alarms)} {formatList('notificator', item.notificators)} - - ))} - -
+ + ))} + +
); }; -const NotificationsPage = () => { - return ( - - - - ); -}; +const NotificationsPage = () => ( + + + +); export default NotificationsPage; diff --git a/modern/src/settings/OptionsLayout/useRoutes.js b/modern/src/settings/OptionsLayout/useRoutes.js index 901719f..f2603dd 100644 --- a/modern/src/settings/OptionsLayout/useRoutes.js +++ b/modern/src/settings/OptionsLayout/useRoutes.js @@ -13,7 +13,7 @@ import t from '../../common/localization'; const accountRoute = { name: t('settingsUser'), - icon: + icon: , }; const adminRoutes = [ @@ -21,18 +21,18 @@ const adminRoutes = [ { name: t('settingsServer'), href: '/admin/server', - icon: + icon: , }, { name: t('settingsUsers'), href: '/admin/users', - icon: + icon: , }, { name: t('statisticsTitle'), href: '/admin/statistics', - icon: - } + icon: , + }, ]; const mainRoutes = [ @@ -41,38 +41,38 @@ const mainRoutes = [ match: 'geofence', name: t('sharedGeofences'), href: '/geofences', - icon: + icon: , }, { match: 'notification', name: t('sharedNotifications'), href: '/settings/notifications', - icon: + icon: , }, { match: 'group', name: t('settingsGroups'), href: '/settings/groups', - icon: + icon: , }, { match: 'driver', name: t('sharedDrivers'), href: '/settings/drivers', - icon: + icon: , }, { match: 'attribute', name: t('sharedComputedAttributes'), href: '/settings/attributes', - icon: + icon: , }, { match: 'maintenance', name: t('sharedMaintenance'), href: '/settings/maintenances', - icon: - } + icon: , + }, ]; export default () => { @@ -81,6 +81,6 @@ export default () => { accountRoute.href = `/user/${userId}`; return useMemo(() => [...mainRoutes, ...(isAdmin ? adminRoutes : [])], [ - isAdmin + isAdmin, ]); }; diff --git a/modern/src/setupProxy.js b/modern/src/setupProxy.js index c16655c..e5ca76d 100644 --- a/modern/src/setupProxy.js +++ b/modern/src/setupProxy.js @@ -1,6 +1,6 @@ const proxy = require('http-proxy-middleware'); module.exports = function (app) { - app.use(proxy('/api/socket', { target: 'ws://' + process.env.REACT_APP_URL_NAME, ws: true })); - app.use(proxy('/api', { target: 'http://' + process.env.REACT_APP_URL_NAME })); + app.use(proxy('/api/socket', { target: `ws://${process.env.REACT_APP_URL_NAME}`, ws: true })); + app.use(proxy('/api', { target: `http://${process.env.REACT_APP_URL_NAME}` })); }; diff --git a/modern/src/store/devices.js b/modern/src/store/devices.js index 66c1607..cca23cb 100644 --- a/modern/src/store/devices.js +++ b/modern/src/store/devices.js @@ -4,15 +4,15 @@ const { reducer, actions } = createSlice({ name: 'devices', initialState: { items: {}, - selectedId: null + selectedId: null, }, reducers: { refresh(state, action) { state.items = {}; - action.payload.forEach(item => state.items[item['id']] = item); + action.payload.forEach((item) => state.items[item.id] = item); }, update(state, action) { - action.payload.forEach(item => state.items[item['id']] = item); + action.payload.forEach((item) => state.items[item.id] = item); }, select(state, action) { state.selectedId = action.payload.id; @@ -20,7 +20,7 @@ const { reducer, actions } = createSlice({ remove(state, action) { delete state.items[action.payload]; }, - } + }, }); export { actions as devicesActions }; diff --git a/modern/src/store/drivers.js b/modern/src/store/drivers.js index 63522d7..38933d8 100644 --- a/modern/src/store/drivers.js +++ b/modern/src/store/drivers.js @@ -7,9 +7,9 @@ const { reducer, actions } = createSlice({ }, reducers: { update(state, action) { - action.payload.forEach(item => state.items[item['id']] = item); + action.payload.forEach((item) => state.items[item.id] = item); }, - } + }, }); export { actions as driversActions }; diff --git a/modern/src/store/geofences.js b/modern/src/store/geofences.js index 504b7d0..f2b7666 100644 --- a/modern/src/store/geofences.js +++ b/modern/src/store/geofences.js @@ -8,12 +8,12 @@ const { reducer, actions } = createSlice({ reducers: { refresh(state, action) { state.items = {}; - action.payload.forEach(item => state.items[item['id']] = item); + action.payload.forEach((item) => state.items[item.id] = item); }, update(state, action) { - action.payload.forEach(item => state.items[item['id']] = item); + action.payload.forEach((item) => state.items[item.id] = item); }, - } + }, }); export { actions as geofencesActions }; diff --git a/modern/src/store/groups.js b/modern/src/store/groups.js index 483323f..11fc5db 100644 --- a/modern/src/store/groups.js +++ b/modern/src/store/groups.js @@ -7,9 +7,9 @@ const { reducer, actions } = createSlice({ }, reducers: { update(state, action) { - action.payload.forEach(item => state.items[item['id']] = item); + action.payload.forEach((item) => state.items[item.id] = item); }, - } + }, }); export { actions as groupsActions }; diff --git a/modern/src/store/maintenances.js b/modern/src/store/maintenances.js index 0813f6b..08b2adb 100644 --- a/modern/src/store/maintenances.js +++ b/modern/src/store/maintenances.js @@ -7,9 +7,9 @@ const { reducer, actions } = createSlice({ }, reducers: { update(state, action) { - action.payload.forEach(item => state.items[item['id']] = item); + action.payload.forEach((item) => state.items[item.id] = item); }, - } + }, }); export { actions as maintenancesActions }; diff --git a/modern/src/store/positions.js b/modern/src/store/positions.js index 1df468c..8858298 100644 --- a/modern/src/store/positions.js +++ b/modern/src/store/positions.js @@ -7,9 +7,9 @@ const { reducer, actions } = createSlice({ }, reducers: { update(state, action) { - action.payload.forEach(item => state.items[item['deviceId']] = item); + action.payload.forEach((item) => state.items[item.deviceId] = item); }, - } + }, }); export { actions as positionsActions }; diff --git a/modern/src/theme/dimensions.js b/modern/src/theme/dimensions.js index a2403ab..fcdbaee 100644 --- a/modern/src/theme/dimensions.js +++ b/modern/src/theme/dimensions.js @@ -8,5 +8,5 @@ export default { columnWidthDate: 160, columnWidthNumber: 130, columnWidthString: 160, - columnWidthBoolean: 130 + columnWidthBoolean: 130, }; diff --git a/modern/src/theme/index.js b/modern/src/theme/index.js index 5a3b2a9..dc0a35b 100644 --- a/modern/src/theme/index.js +++ b/modern/src/theme/index.js @@ -6,7 +6,7 @@ import dimensions from './dimensions'; const theme = createMuiTheme({ palette, overrides, - dimensions + dimensions, }); export default theme; diff --git a/modern/src/theme/overrides.js b/modern/src/theme/overrides.js index cd6c5a5..a6d08cf 100644 --- a/modern/src/theme/overrides.js +++ b/modern/src/theme/overrides.js @@ -4,17 +4,17 @@ export default { MuiFormControl: { root: { marginTop: 5, - marginBottom: 5 - } + marginBottom: 5, + }, }, MuiInputLabel: { filled: { transform: 'translate(12px, 14px) scale(1)', - '&$shrink' :{ - transform: 'translate(12px, -14px) scale(0.72)' - } + '&$shrink': { + transform: 'translate(12px, -14px) scale(0.72)', + }, }, - }, + }, MuiFilledInput: { root: { height: dimensions.inputHeight, @@ -28,19 +28,19 @@ export default { boxSizing: 'border-box', '&:-webkit-autofill': { WebkitBoxShadow: '0 0 0 100px #eeeeee inset', - }, + }, }, underline: { - "&:before": { + '&:before': { borderBottom: 'none', }, - "&:after": { + '&:after': { borderBottom: 'none', }, - "&:hover:before": { + '&:hover:before': { borderBottom: 'none', - }, - } + }, + }, }, MuiButton: { root: { @@ -48,31 +48,31 @@ export default { marginTop: 5, marginBottom: 5, '&$disabled': { - opacity: .4, + opacity: 0.4, color: undefined, - } + }, }, contained: { '&$disabled': { - opacity: .4, + opacity: 0.4, color: undefined, - backgroundColor: undefined - } - } + backgroundColor: undefined, + }, + }, }, MuiFormHelperText: { root: { - marginBottom: -10 + marginBottom: -10, }, contained: { - marginLeft: 12 - } + marginLeft: 12, + }, }, MuiAutocomplete: { inputRoot: { '&.MuiFilledInput-root': { - paddingTop: 0 - } - } - } + paddingTop: 0, + }, + }, + }, }; -- cgit v1.2.3