aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Tananaev <anton.tananaev@gmail.com>2020-09-28 20:43:47 -0700
committerAnton Tananaev <anton.tananaev@gmail.com>2020-09-28 20:43:47 -0700
commit94e8c40f52b239562aded5e70e334ddbb2eea23b (patch)
treebd5d8b9425a08ac055f0617818e6e54930c4d557
parent9d72339c8365da80154f635dc8184b135a53bab0 (diff)
downloadtrackermap-web-94e8c40f52b239562aded5e70e334ddbb2eea23b.tar.gz
trackermap-web-94e8c40f52b239562aded5e70e334ddbb2eea23b.tar.bz2
trackermap-web-94e8c40f52b239562aded5e70e334ddbb2eea23b.zip
Page for all attributes
-rw-r--r--modern/src/App.js2
-rw-r--r--modern/src/MainMap.js5
-rw-r--r--modern/src/PositionPage.js80
-rw-r--r--modern/src/StatusView.js12
-rw-r--r--modern/src/common/formatter.js4
-rw-r--r--modern/src/settings/NotificationPage.js1
-rw-r--r--web/l10n/en.json1
7 files changed, 99 insertions, 6 deletions
diff --git a/modern/src/App.js b/modern/src/App.js
index b25d1aba..9dc963b6 100644
--- a/modern/src/App.js
+++ b/modern/src/App.js
@@ -11,6 +11,7 @@ import UserPage from './UserPage';
import SocketController from './SocketController';
import NotificationsPage from './settings/NotificationsPage';
import NotificationPage from './settings/NotificationPage';
+import PositionPage from './PositionPage';
const App = () => {
return (
@@ -20,6 +21,7 @@ const App = () => {
<Switch>
<Route exact path='/' component={MainPage} />
<Route exact path='/login' component={LoginPage} />
+ <Route exact path='/position/:id?' component={PositionPage} />
<Route exact path='/user/:id?' component={UserPage} />
<Route exact path='/device/:id?' component={DevicePage} />
<Route exact path='/reports/route' component={RouteReportPage} />
diff --git a/modern/src/MainMap.js b/modern/src/MainMap.js
index 5ba50982..b3fafb6a 100644
--- a/modern/src/MainMap.js
+++ b/modern/src/MainMap.js
@@ -6,8 +6,11 @@ import mapboxgl from 'mapbox-gl';
import mapManager from './mapManager';
import store from './store';
import StatusView from './StatusView';
+import { useHistory } from 'react-router-dom';
const MainMap = () => {
+ const history = useHistory();
+
const containerEl = useRef(null);
const [mapReady, setMapReady] = useState(false);
@@ -67,7 +70,7 @@ const MainMap = () => {
const placeholder = document.createElement('div');
ReactDOM.render(
<Provider store={store}>
- <StatusView deviceId={feature.properties.deviceId} />
+ <StatusView deviceId={feature.properties.deviceId} onShowDetails={positionId => history.push(`/position/${positionId}`)} />
</Provider>,
placeholder);
diff --git a/modern/src/PositionPage.js b/modern/src/PositionPage.js
new file mode 100644
index 00000000..a91a7a15
--- /dev/null
+++ b/modern/src/PositionPage.js
@@ -0,0 +1,80 @@
+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 { useParams } from 'react-router-dom';
+import { useEffectAsync } from './reactHelper';
+import MainToolbar from './MainToolbar';
+import { formatPosition } from './common/formatter';
+import { prefixString } from './common/stringUtils';
+
+const useStyles = makeStyles(theme => ({
+ root: {
+ marginTop: theme.spacing(2),
+ marginBottom: theme.spacing(2),
+ },
+}));
+
+const PositionPage = () => {
+ const classes = useStyles();
+
+ const { id } = useParams();
+
+ const [item, setItem] = useState();
+
+ useEffectAsync(async () => {
+ if (id) {
+ const response = await fetch(`/api/positions?id=${id}`, {
+ headers: {
+ 'Accept': 'application/json'
+ },
+ });
+ if (response.ok) {
+ const items = await response.json();
+ setItem(items[0]);
+ }
+ } else {
+ setItem({});
+ }
+ }, [id]);
+
+ const formatKey = (key) => {
+ return t(prefixString('position', key)) || `${t('sharedAttribute')} "${key}"`;
+ };
+
+ const attributesList = () => {
+ const combinedList = {...item, ...item.attributes};
+ return Object.entries(combinedList).filter(([_, value]) => typeof value !== 'object');
+ }
+
+ return (
+ <>
+ <MainToolbar />
+ <Container maxWidth='sm' className={classes.root}>
+ <Paper>
+ {item &&
+ <List>
+ {attributesList().map(([key, value], index, list) => (
+ <Fragment key={key}>
+ <ListItem>
+ <ListItemText
+ primary={formatKey(key)}
+ />
+ <ListItemSecondaryAction>
+ <Typography variant="body2">
+ {formatPosition(value, key)}
+ </Typography>
+ </ListItemSecondaryAction>
+ </ListItem>
+ {index < list.length - 1 ? <Divider /> : null}
+ </Fragment>
+ ))}
+ </List>
+ }
+ </Paper>
+ </Container>
+ </>
+ );
+}
+
+export default PositionPage;
diff --git a/modern/src/StatusView.js b/modern/src/StatusView.js
index 61fd1504..0713d47e 100644
--- a/modern/src/StatusView.js
+++ b/modern/src/StatusView.js
@@ -3,9 +3,14 @@ import React from 'react';
import { useSelector } from 'react-redux';
import { formatPosition } from './common/formatter';
-const StatusView = (props) => {
- const device = useSelector(state => state.devices.items[props.deviceId]);
- const position = useSelector(state => state.positions.items[props.deviceId]);
+const StatusView = ({ deviceId, onShowDetails }) => {
+ const device = useSelector(state => state.devices.items[deviceId]);
+ const position = useSelector(state => state.positions.items[deviceId]);
+
+ const handleClick = e => {
+ e.preventDefault();
+ onShowDetails(position.id);
+ };
return (
<>
@@ -17,6 +22,7 @@ const StatusView = (props) => {
{position.attributes.batteryLevel &&
<><b>{t('positionBattery')}:</b> {formatPosition(position.attributes.batteryLevel, 'batteryLevel')}<br /></>
}
+ <a href="#" onClick={handleClick}>{t('sharedShowDetails')}</a>
</>
);
};
diff --git a/modern/src/common/formatter.js b/modern/src/common/formatter.js
index 057041e2..f04bb434 100644
--- a/modern/src/common/formatter.js
+++ b/modern/src/common/formatter.js
@@ -2,11 +2,13 @@ import moment from 'moment';
import t from '../common/localization';
export const formatPosition = (value, key) => {
- if (value != null && typeof value == 'object') {
+ if (value != null && typeof value === 'object') {
value = value[key];
}
switch (key) {
case 'fixTime':
+ case 'deviceTime':
+ case 'serverTime':
return moment(value).format('LLL');
case 'latitude':
case 'longitude':
diff --git a/modern/src/settings/NotificationPage.js b/modern/src/settings/NotificationPage.js
index 3e47650b..5a772d0c 100644
--- a/modern/src/settings/NotificationPage.js
+++ b/modern/src/settings/NotificationPage.js
@@ -1,5 +1,4 @@
import React, { useState } from 'react';
-import TextField from '@material-ui/core/TextField';
import t, { findStringKeys } from '../common/localization';
import EditItemView from '../EditItemView';
diff --git a/web/l10n/en.json b/web/l10n/en.json
index 6e0c62f1..139640b1 100644
--- a/web/l10n/en.json
+++ b/web/l10n/en.json
@@ -75,6 +75,7 @@
"sharedSavedCommands": "Saved Commands",
"sharedNew": "New…",
"sharedShowAddress": "Show Address",
+ "sharedShowDetails": "More Details",
"sharedDisabled": "Disabled",
"sharedMaintenance": "Maintenance",
"sharedDeviceAccumulators": "Accumulators",