aboutsummaryrefslogtreecommitdiff
path: root/modern/src/main/DevicesList.js
diff options
context:
space:
mode:
authorAnton Tananaev <anton@traccar.org>2022-10-21 18:14:12 -0700
committerAnton Tananaev <anton@traccar.org>2022-10-21 18:14:12 -0700
commit23f2332c7ce6cea72d91df102d35c03d0d3ce49e (patch)
treed44071ff0b198017028978165c58d69f91374e57 /modern/src/main/DevicesList.js
parent52421e5f09687d4ae57386a69f9ffc69c011f9bb (diff)
downloadtrackermap-web-23f2332c7ce6cea72d91df102d35c03d0d3ce49e.tar.gz
trackermap-web-23f2332c7ce6cea72d91df102d35c03d0d3ce49e.tar.bz2
trackermap-web-23f2332c7ce6cea72d91df102d35c03d0d3ce49e.zip
Extract device row
Diffstat (limited to 'modern/src/main/DevicesList.js')
-rw-r--r--modern/src/main/DevicesList.js221
1 files changed, 0 insertions, 221 deletions
diff --git a/modern/src/main/DevicesList.js b/modern/src/main/DevicesList.js
deleted file mode 100644
index 054cf509..00000000
--- a/modern/src/main/DevicesList.js
+++ /dev/null
@@ -1,221 +0,0 @@
-import React, { useEffect, useRef, useState } from 'react';
-import { useDispatch, useSelector } from 'react-redux';
-import makeStyles from '@mui/styles/makeStyles';
-import {
- IconButton, Tooltip, Avatar, List, ListItemAvatar, ListItemText, ListItemButton,
-} from '@mui/material';
-import { FixedSizeList } from 'react-window';
-import AutoSizer from 'react-virtualized-auto-sizer';
-import BatteryFullIcon from '@mui/icons-material/BatteryFull';
-import BatteryChargingFullIcon from '@mui/icons-material/BatteryChargingFull';
-import Battery60Icon from '@mui/icons-material/Battery60';
-import BatteryCharging60Icon from '@mui/icons-material/BatteryCharging60';
-import Battery20Icon from '@mui/icons-material/Battery20';
-import BatteryCharging20Icon from '@mui/icons-material/BatteryCharging20';
-import ErrorIcon from '@mui/icons-material/Error';
-import moment from 'moment';
-import { devicesActions } from '../store';
-import { useEffectAsync } from '../reactHelper';
-import {
- formatAlarm, formatBoolean, formatPercentage, formatStatus, getStatusColor,
-} from '../common/util/formatter';
-import { useTranslation } from '../common/components/LocalizationProvider';
-import { mapIconKey, mapIcons } from '../map/core/preloadImages';
-import { useAdministrator } from '../common/util/permissions';
-import usePersistedState from '../common/util/usePersistedState';
-import { ReactComponent as EngineIcon } from '../resources/images/data/engine.svg';
-
-const useStyles = makeStyles((theme) => ({
- list: {
- maxHeight: '100%',
- },
- listInner: {
- position: 'relative',
- margin: theme.spacing(1.5, 0),
- },
- icon: {
- width: '25px',
- height: '25px',
- filter: 'brightness(0) invert(1)',
- },
- listItem: {
- backgroundColor: 'white',
- '&:hover': {
- backgroundColor: 'white',
- },
- },
- batteryText: {
- fontSize: '0.75rem',
- fontWeight: 'normal',
- lineHeight: '0.875rem',
- },
- positive: {
- color: theme.palette.colors.positive,
- },
- medium: {
- color: theme.palette.colors.medium,
- },
- negative: {
- color: theme.palette.colors.negative,
- },
- neutral: {
- color: theme.palette.colors.neutral,
- },
-}));
-
-const DeviceRow = ({ data, index, style }) => {
- const classes = useStyles();
- const dispatch = useDispatch();
- const t = useTranslation();
-
- const admin = useAdministrator();
-
- const { items } = data;
- const item = items[index];
- const position = useSelector((state) => state.positions.items[item.id]);
-
- const geofences = useSelector((state) => state.geofences.items);
-
- const [devicePrimary] = usePersistedState('devicePrimary', 'name');
- const [deviceSecondary] = usePersistedState('deviceSecondary', '');
-
- const formatProperty = (key) => {
- if (key === 'geofenceIds') {
- const geofenceIds = item[key] || [];
- return geofenceIds
- .filter((id) => geofences.hasOwnProperty(id))
- .map((id) => geofences[id].name)
- .join(', ');
- }
- return item[key];
- };
-
- const secondaryText = () => {
- let status;
- if (item.status === 'online' || !item.lastUpdate) {
- status = formatStatus(item.status, t);
- } else {
- status = moment(item.lastUpdate).fromNow();
- }
- return (
- <>
- {deviceSecondary && item[deviceSecondary] && `${formatProperty(deviceSecondary)} • `}
- <span className={classes[getStatusColor(item.status)]}>{status}</span>
- </>
- );
- };
-
- return (
- <div style={style}>
- <ListItemButton
- key={item.id}
- className={classes.listItem}
- onClick={() => dispatch(devicesActions.select(item.id))}
- disabled={!admin && item.disabled}
- >
- <ListItemAvatar>
- <Avatar>
- <img className={classes.icon} src={mapIcons[mapIconKey(item.category)]} alt="" />
- </Avatar>
- </ListItemAvatar>
- <ListItemText
- primary={formatProperty(devicePrimary)}
- primaryTypographyProps={{ noWrap: true }}
- secondary={secondaryText()}
- secondaryTypographyProps={{ noWrap: true }}
- />
- {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 ? (
- <EngineIcon width={20} height={20} className={classes.positive} />
- ) : (
- <EngineIcon width={20} height={20} 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>
- )}
- </>
- )}
- </ListItemButton>
- </div>
- );
-};
-
-const DevicesList = ({ devices }) => {
- const classes = useStyles();
- const dispatch = useDispatch();
- const listInnerEl = useRef(null);
-
- if (listInnerEl.current) {
- listInnerEl.current.className = classes.listInner;
- }
-
- const [, setTime] = useState(Date.now());
-
- useEffect(() => {
- const interval = setInterval(() => setTime(Date.now()), 60000);
- return () => {
- clearInterval(interval);
- };
- }, []);
-
- useEffectAsync(async () => {
- const response = await fetch('/api/devices');
- if (response.ok) {
- dispatch(devicesActions.refresh(await response.json()));
- } else {
- throw Error(await response.text());
- }
- }, []);
-
- return (
- <AutoSizer className={classes.list}>
- {({ height, width }) => (
- <List disablePadding>
- <FixedSizeList
- width={width}
- height={height}
- itemCount={devices.length}
- itemData={{ items: devices }}
- itemSize={72}
- overscanCount={10}
- innerRef={listInnerEl}
- >
- {DeviceRow}
- </FixedSizeList>
- </List>
- )}
- </AutoSizer>
- );
-};
-
-export default DevicesList;