import React, { useRef } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { makeStyles } from '@material-ui/core/styles'; import List from '@material-ui/core/List'; import ListItem from '@material-ui/core/ListItem'; import ListItemAvatar from '@material-ui/core/ListItemAvatar'; import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction'; import Grid from '@material-ui/core/Grid'; import ListItemText from '@material-ui/core/ListItemText'; import SvgIcon from '@material-ui/core/SvgIcon'; import Typography from '@material-ui/core/Typography'; import { FixedSizeList } from 'react-window'; import AutoSizer from 'react-virtualized-auto-sizer'; import BatteryFullIcon from '@material-ui/icons/BatteryFull'; import { ReactComponent as IgnitionIcon } from '../public/images/ignition.svg'; import FiberManualRecordIcon from '@material-ui/icons/FiberManualRecord'; import PersonIcon from '@material-ui/icons/Person'; import SpeedIcon from '@material-ui/icons/Speed'; import CalendarTodayIcon from '@material-ui/icons/CalendarToday'; import LockIcon from '@material-ui/icons/Lock'; import LockOpenIcon from '@material-ui/icons/LockOpen'; import PlaceIcon from '@material-ui/icons/Place'; import { devicesActions, uiActions } from './store'; import EditCollectionView from './EditCollectionView'; import { useEffectAsync } from './reactHelper'; import { formatPosition, formatSpeed, formatHours } from './common/formatter'; import { useAttributePreference } from './common/preferences'; import { getDevices, getFilteredDevices, getFilterTerm, getPosition } from './common/selectors'; import { useTranslation } from './LocalizationProvider'; const useStyles = makeStyles((theme) => ({ list: { maxHeight: '100%', }, listInner: { position: 'relative', margin: theme.spacing(1.5, 0), }, icon: { width: '40px', height: '40px', }, statusIcon: { paddingRight: '5px', }, listItem: { backgroundColor: 'white', '&:hover': { backgroundColor: 'white', }, height: '150px', }, listItemSecondary: { fontSize: '0.92rem', }, batteryText: { fontSize: '0.75rem', fontWeight: 'normal', lineHeight: '0.875rem', }, green: { color: theme.palette.common.green, }, red: { color: theme.palette.common.red, }, gray: { color: theme.palette.common.gray, }, indicators: { lineHeight: 1, }, })); const getBatteryStatus = (batteryLevel) => { if (batteryLevel >= 70) { return 'green'; } if (batteryLevel > 30) { return 'gray'; } return 'red'; }; const DeviceRow = ({ data, index, style }) => { const classes = useStyles(); const dispatch = useDispatch(); const t = useTranslation(); const speedUnit = useAttributePreference('speedUnit'); const { items } = data; const item = items[index]; const position = useSelector(getPosition(item.id)); const showIgnition = position?.attributes.hasOwnProperty('ignition') && position.attributes.ignition === true; const statusColor = () => { if (showIgnition) { return 'primary'; } else { return 'error'; } }; const getPositionHours = (pos, it) => { if (it.category && (it.category === 'backhoe' || it.category === 'tractor') && pos) { if (pos.attributes.io16) { return formatHours(parseInt(position.attributes.io16) * 60 * 1000, t); } else if (pos.attributes.hours) { return formatHours(position.attributes.hours, t); } } return null; } const getPositionLock = (pos) => { if (pos) { if (pos.attributes.output !== undefined) { return pos.attributes.output === 1; } else if (pos.attributes.out1 !== undefined) { return pos.attributes.out1; } } return null; } return (
{ dispatch(devicesActions.select(item)); dispatch(uiActions.setCollapsed(true)); setTimeout(() => { dispatch(devicesActions.unselect()); }, 1000); }}> {/* Avatar */} {/* Status icon (now ignition) */} {getPositionLock(position) === false && ( )} {getPositionLock(position) === true && ( )} {` ${item.name}`} } secondary={( <> {/* Contact */} {item.contact && ( <> {item.contact}
)} {position && ( <> {/* Speed */} {formatSpeed(position.speed, speedUnit, t)}
{/* Datetime */} {formatPosition(position, 'fixTime', t)} {/* Hours */} {getPositionHours(position, item) && ` (${getPositionHours(position, item)})`}
{/* Address */} {position.address && ( <> {` ${position.address}`} )} )} )} classes={{ secondary: classes.listItemSecondary }} /> {position && ( {/* Ignition */} {showIgnition && ( )} {/* Battery level */} {position.attributes.hasOwnProperty('batteryLevel') && ( {formatPosition(position.attributes.batteryLevel, 'batteryLevel', t)} )} )}
); }; const DeviceView = ({ updateTimestamp, onMenuClick }) => { const classes = useStyles(); const dispatch = useDispatch(); const listInnerEl = useRef(null); const filterTerm = useSelector(getFilterTerm); const filteredItems = useSelector(getFilteredDevices); const unfilteredItems = useSelector(getDevices); const items = (filterTerm.length > 0 ? filteredItems : unfilteredItems).sort((a, b) => a.name.localeCompare(b.name)); if (listInnerEl.current) { listInnerEl.current.className = classes.listInner; } useEffectAsync(async () => { const response = await fetch('/api/devices'); if (response.ok) { dispatch(devicesActions.refresh(await response.json())); } }, [updateTimestamp]); return ( {({ height, width }) => ( {DeviceRow} )} ); }; const DevicesList = () => ( ); export default DevicesList;