diff options
author | Anton Tananaev <anton@traccar.org> | 2022-10-21 18:14:12 -0700 |
---|---|---|
committer | Anton Tananaev <anton@traccar.org> | 2022-10-21 18:14:12 -0700 |
commit | 23f2332c7ce6cea72d91df102d35c03d0d3ce49e (patch) | |
tree | d44071ff0b198017028978165c58d69f91374e57 /modern/src/main/DevicesList.js | |
parent | 52421e5f09687d4ae57386a69f9ffc69c011f9bb (diff) | |
download | trackermap-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.js | 221 |
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; |