aboutsummaryrefslogtreecommitdiff
path: root/modern/src
diff options
context:
space:
mode:
authorAnton Tananaev <anton@traccar.org>2022-05-24 08:21:22 -0700
committerAnton Tananaev <anton@traccar.org>2022-05-24 08:21:22 -0700
commitad94dc32e90626d42b8d4baeefadefa0042824ec (patch)
treeeca80659583961ce27628a38fd25d81584e5aa74 /modern/src
parentd5dd02b6eb1b71e420e68a72488f08374f04f678 (diff)
downloadtrackermap-web-ad94dc32e90626d42b8d4baeefadefa0042824ec.tar.gz
trackermap-web-ad94dc32e90626d42b8d4baeefadefa0042824ec.tar.bz2
trackermap-web-ad94dc32e90626d42b8d4baeefadefa0042824ec.zip
Show last update time
Diffstat (limited to 'modern/src')
-rw-r--r--modern/src/common/components/LocalizationProvider.js16
-rw-r--r--modern/src/main/DevicesList.js102
2 files changed, 69 insertions, 49 deletions
diff --git a/modern/src/common/components/LocalizationProvider.js b/modern/src/common/components/LocalizationProvider.js
index 147ac5ca..db3e1fb9 100644
--- a/modern/src/common/components/LocalizationProvider.js
+++ b/modern/src/common/components/LocalizationProvider.js
@@ -1,5 +1,9 @@
/* eslint-disable import/no-relative-packages */
-import React, { createContext, useContext, useMemo } from 'react';
+import React, {
+ createContext, useContext, useEffect, useMemo,
+} from 'react';
+import moment from 'moment';
+import 'moment/min/locales.min';
import af from '../../../../web/l10n/af.json';
import ar from '../../../../web/l10n/ar.json';
@@ -146,6 +150,16 @@ export const LocalizationProvider = ({ children }) => {
const value = useMemo(() => ({ languages, language, setLanguage }), [languages, language, setLanguage]);
+ useEffect(() => {
+ let selected;
+ if (language.length > 2) {
+ selected = `${language.slice(0, 2)}-${language.slice(-2).toLowerCase()}`;
+ } else {
+ selected = language;
+ }
+ moment.locale([selected, 'en']);
+ }, [language]);
+
return (
<LocalizationContext.Provider value={value}>
{children}
diff --git a/modern/src/main/DevicesList.js b/modern/src/main/DevicesList.js
index 06b75715..fe963124 100644
--- a/modern/src/main/DevicesList.js
+++ b/modern/src/main/DevicesList.js
@@ -6,7 +6,6 @@ import Avatar from '@mui/material/Avatar';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemAvatar from '@mui/material/ListItemAvatar';
-import ListItemSecondaryAction from '@mui/material/ListItemSecondaryAction';
import ListItemText from '@mui/material/ListItemText';
import { FixedSizeList } from 'react-window';
import AutoSizer from 'react-virtualized-auto-sizer';
@@ -20,6 +19,7 @@ import FlashOnIcon from '@mui/icons-material/FlashOn';
import FlashOffIcon from '@mui/icons-material/FlashOff';
import ErrorIcon from '@mui/icons-material/Error';
+import moment from 'moment';
import { devicesActions } from '../store';
import { useEffectAsync } from '../reactHelper';
import {
@@ -63,9 +63,6 @@ const useStyles = makeStyles((theme) => ({
neutral: {
color: theme.palette.colors.neutral,
},
- indicators: {
- lineHeight: 1,
- },
}));
const DeviceRow = ({ data, index, style }) => {
@@ -77,6 +74,15 @@ const DeviceRow = ({ data, index, style }) => {
const item = items[index];
const position = useSelector((state) => state.positions.items[item.id]);
+ const secondaryText = () => {
+ const status = formatStatus(item.status, t);
+ if (item.lastUpdate) {
+ const lastUpdate = moment(item.lastUpdate).fromNow();
+ return `${status} ${lastUpdate}`;
+ }
+ return status;
+ };
+
return (
<div style={style}>
<ListItem button key={item.id} className={classes.listItem} onClick={() => dispatch(devicesActions.select(item.id))}>
@@ -87,52 +93,52 @@ const DeviceRow = ({ data, index, style }) => {
</ListItemAvatar>
<ListItemText
primary={item.name}
- secondary={formatStatus(item.status, t)}
+ primaryTypographyProps={{ noWrap: true }}
+ secondary={secondaryText()}
+ secondaryTypographyProps={{ noWrap: true }}
classes={{ secondary: classes[getStatusColor(item.status)] }}
/>
- <ListItemSecondaryAction className={classes.indicators}>
- {position && (
- <>
- {position.attributes.hasOwnProperty('alarm') && (
- <Tooltip title={`${t('eventAlarm')}: ${formatAlarm(position.attributes.alarm, t)}`}>
- <IconButton size="small">
- <ErrorIcon fontSize="small" className={classes.negative} />
- </IconButton>
- </Tooltip>
- )}
- {position.attributes.hasOwnProperty('ignition') && (
- <Tooltip title={`${t('positionIgnition')}: ${formatBoolean(position.attributes.ignition, t)}`}>
- <IconButton size="small">
- {position.attributes.ignition ? (
- <FlashOnIcon fontSize="small" className={classes.positive} />
- ) : (
- <FlashOffIcon fontSize="small" className={classes.neutral} />
- )}
- </IconButton>
- </Tooltip>
- )}
- {position.attributes.hasOwnProperty('batteryLevel') && (
- <Tooltip title={`${t('positionBatteryLevel')}: ${formatPercentage(position.attributes.batteryLevel)}`}>
- <IconButton size="small">
- {position.attributes.batteryLevel > 70 ? (
- position.attributes.charge
- ? (<BatteryChargingFullIcon fontSize="small" className={classes.positive} />)
- : (<BatteryFullIcon fontSize="small" className={classes.positive} />)
- ) : position.attributes.batteryLevel > 30 ? (
- position.attributes.charge
- ? (<BatteryCharging60Icon fontSize="small" className={classes.medium} />)
- : (<Battery60Icon fontSize="small" className={classes.medium} />)
- ) : (
- position.attributes.charge
- ? (<BatteryCharging20Icon fontSize="small" className={classes.negative} />)
- : (<Battery20Icon fontSize="small" className={classes.negative} />)
- )}
- </IconButton>
- </Tooltip>
- )}
- </>
- )}
- </ListItemSecondaryAction>
+ {position && (
+ <>
+ {position.attributes.hasOwnProperty('alarm') && (
+ <Tooltip title={`${t('eventAlarm')}: ${formatAlarm(position.attributes.alarm, t)}`}>
+ <IconButton size="small">
+ <ErrorIcon fontSize="small" className={classes.negative} />
+ </IconButton>
+ </Tooltip>
+ )}
+ {position.attributes.hasOwnProperty('ignition') && (
+ <Tooltip title={`${t('positionIgnition')}: ${formatBoolean(position.attributes.ignition, t)}`}>
+ <IconButton size="small">
+ {position.attributes.ignition ? (
+ <FlashOnIcon fontSize="small" className={classes.positive} />
+ ) : (
+ <FlashOffIcon fontSize="small" className={classes.neutral} />
+ )}
+ </IconButton>
+ </Tooltip>
+ )}
+ {position.attributes.hasOwnProperty('batteryLevel') && (
+ <Tooltip title={`${t('positionBatteryLevel')}: ${formatPercentage(position.attributes.batteryLevel)}`}>
+ <IconButton size="small">
+ {position.attributes.batteryLevel > 70 ? (
+ position.attributes.charge
+ ? (<BatteryChargingFullIcon fontSize="small" className={classes.positive} />)
+ : (<BatteryFullIcon fontSize="small" className={classes.positive} />)
+ ) : position.attributes.batteryLevel > 30 ? (
+ position.attributes.charge
+ ? (<BatteryCharging60Icon fontSize="small" className={classes.medium} />)
+ : (<Battery60Icon fontSize="small" className={classes.medium} />)
+ ) : (
+ position.attributes.charge
+ ? (<BatteryCharging20Icon fontSize="small" className={classes.negative} />)
+ : (<Battery20Icon fontSize="small" className={classes.negative} />)
+ )}
+ </IconButton>
+ </Tooltip>
+ )}
+ </>
+ )}
</ListItem>
</div>
);