aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIván Ávalos <avalos@disroot.org>2021-12-13 20:23:18 -0600
committerIván Ávalos <avalos@disroot.org>2021-12-13 20:23:18 -0600
commita0cd63630f67f0dec0c839cdcf53e36d1d8aebb8 (patch)
treed7ac838bb1fc683059d435f2d47879c2ba44d22b
parent9b1a369f7e637471ad945642b3f90135e7d03d9d (diff)
downloadetbsa-traccar-web-a0cd63630f67f0dec0c839cdcf53e36d1d8aebb8.tar.gz
etbsa-traccar-web-a0cd63630f67f0dec0c839cdcf53e36d1d8aebb8.tar.bz2
etbsa-traccar-web-a0cd63630f67f0dec0c839cdcf53e36d1d8aebb8.zip
Revamped device list and map marker popup
-rw-r--r--modern/src/CommandsPage.js8
-rw-r--r--modern/src/DevicesList.js94
-rw-r--r--modern/src/map/StatusView.js34
3 files changed, 100 insertions, 36 deletions
diff --git a/modern/src/CommandsPage.js b/modern/src/CommandsPage.js
index e36c365..1458b43 100644
--- a/modern/src/CommandsPage.js
+++ b/modern/src/CommandsPage.js
@@ -66,18 +66,19 @@ const CommandsPage = () => {
}, [id]);
const handleSend = async () => {
- console.log ('Selected: ' + selectedCommand);
const response = await fetch(`/api/commands/send`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
- id: selectedCommand.id,
- deviceId: device.id,
+ 'id': selectedCommand,
+ 'deviceId': device.id,
}),
});
if (response.ok) {
history.goBack();
+ } else {
+ console.log ('response!', response);
}
};
@@ -90,6 +91,7 @@ const CommandsPage = () => {
<>
<CardContent>
<Typography gutterBottom variant="h5">{t('commandSend')}</Typography>
+ <Typography variant="body2" color="text.secondary">{device.name}</Typography>
{commands && (
<FormControl fullWidth aria-label="command">
<RadioGroup onChange={(event) => setSelectedCommand(event.target.value) }>
diff --git a/modern/src/DevicesList.js b/modern/src/DevicesList.js
index 3c1b44f..fda6f60 100644
--- a/modern/src/DevicesList.js
+++ b/modern/src/DevicesList.js
@@ -13,10 +13,18 @@ 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 { devicesActions, uiActions } from './store';
import EditCollectionView from './EditCollectionView';
import { useEffectAsync } from './reactHelper';
-import { formatPosition } from './common/formatter';
+import { formatPosition, formatSpeed, formatDate, formatHours } from './common/formatter';
+import { useAttributePreference } from './common/preferences';
import { getDevices, getFilteredDevices, getPosition } from './common/selectors';
import { useTranslation } from './LocalizationProvider';
@@ -32,12 +40,18 @@ const useStyles = makeStyles((theme) => ({
width: '40px',
height: '40px',
},
+ statusIcon: {
+ paddingRight: '5px',
+ },
listItem: {
backgroundColor: 'white',
'&:hover': {
backgroundColor: 'white',
},
},
+ listItemSecondary: {
+ fontSize: '0.92rem',
+ },
batteryText: {
fontSize: '0.75rem',
fontWeight: 'normal',
@@ -84,11 +98,21 @@ const DeviceRow = ({ data, index, style }) => {
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;
+ const statusColor = () => {
+ if (position && position.speed >= 2) {
+ return 'primary';
+ } else {
+ return 'error';
+ }
+ };
+
return (
<div style={style}>
<ListItem button key={item.id} className={classes.listItem} onClick={() => {
@@ -97,30 +121,60 @@ const DeviceRow = ({ data, index, style }) => {
setTimeout (() => {
dispatch(devicesActions.unselect());
}, 1000);
- }}>
+ }}>
+ {/* Avatar */}
<ListItemAvatar>
<img className={classes.icon} src={`images/icon/${(item.category || 'default').toLowerCase()}.png`} alt="" />
</ListItemAvatar>
- <ListItemText primary={item.name} secondary={item.status} classes={{ secondary: classes[getStatusColor(item.status)] }} />
+ {/* Status icon */}
+
+ <ListItemText primary={
+ <>
+ <FiberManualRecordIcon fontSize="inherit" color={statusColor()} classes={{ colorPrimary: classes.green }} />
+ {position && position.attributes.out1 == false && (
+ <LockOpenIcon fontSize="inherit" color="primary" classes={{ colorPrimary: classes.green }} />
+ )}
+ {position && position.attributes.out1 == true && (
+ <LockIcon fontSize="inherit" color="error" />
+ ) }
+ {` ${item.name}`}
+ </>} secondary={(
+ <>
+ {/* Contact */}
+ <PersonIcon fontSize="inherit" /> {item.contact}<br/>
+ {position && (
+ <>
+ {/* Speed */}
+ <SpeedIcon fontSize="inherit" /> {formatSpeed(position.speed, speedUnit, t)}<br/>
+ {/* Datetime */}
+ <CalendarTodayIcon fontSize="inherit" /> {formatDate(position.serverTime)}
+ {/* Hours */}
+ {position.attributes.hours && position.attributes.hours > 1 && ` (${formatHours(position.attributes.hours, t)})`}
+ </>
+ )}
+ </>
+ )} classes={{ secondary: classes.listItemSecondary }} />
<ListItemSecondaryAction className={classes.indicators}>
{position && (
- <Grid container direction="row" alignItems="center" alignContent="center" spacing={2}>
- {showIgnition && (
- <Grid item>
- <SvgIcon component={IgnitionIcon} />
+ <Grid container direction="row" alignItems="center" alignContent="center" spacing={2}>
+ {/* Ignition */}
+ {showIgnition && (
+ <Grid item>
+ <SvgIcon component={IgnitionIcon} />
+ </Grid>
+ )}
+ {/* Battery level */}
+ {position.attributes.hasOwnProperty('batteryLevel') && (
+ <Grid item container xs alignItems="center" alignContent="center">
+ <Grid item>
+ <span className={classes.batteryText}>{formatPosition(position.attributes.batteryLevel, 'batteryLevel', t)}</span>
+ </Grid>
+ <Grid item>
+ <BatteryFullIcon className={classes[getBatteryStatus(position.attributes.batteryLevel)]} />
+ </Grid>
+ </Grid>
+ )}
</Grid>
- )}
- {position.attributes.hasOwnProperty('batteryLevel') && (
- <Grid item container xs alignItems="center" alignContent="center">
- <Grid item>
- <span className={classes.batteryText}>{formatPosition(position.attributes.batteryLevel, 'batteryLevel', t)}</span>
- </Grid>
- <Grid item>
- <BatteryFullIcon className={classes[getBatteryStatus(position.attributes.batteryLevel)]} />
- </Grid>
- </Grid>
- )}
- </Grid>
)}
</ListItemSecondaryAction>
</ListItem>
@@ -158,7 +212,7 @@ const DeviceView = ({ updateTimestamp, onMenuClick }) => {
height={height}
itemCount={items.length}
itemData={{items, onMenuClick}}
- itemSize={92}
+ itemSize={144}
overscanCount={10}
innerRef={listInnerEl}
>
diff --git a/modern/src/map/StatusView.js b/modern/src/map/StatusView.js
index 6b6836c..6fb72c7 100644
--- a/modern/src/map/StatusView.js
+++ b/modern/src/map/StatusView.js
@@ -7,11 +7,12 @@ import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText';
import { useSelector } from 'react-redux';
-import ReplayIcon from '@material-ui/icons/Replay';
import EditIcon from '@material-ui/icons/Edit';
import SendIcon from '@material-ui/icons/Send';
import DeleteIcon from '@material-ui/icons/Delete';
import LinkIcon from '@material-ui/icons/Link';
+import InfoIcon from '@material-ui/icons/Info';
+import PlayCircleFilledIcon from '@material-ui/icons/PlayCircleFilled';
import {
formatSpeed, formatDate, formatHours,
@@ -42,6 +43,7 @@ const StatusView = ({
const t = useTranslation();
const [removeDialogShown, setRemoveDialogShown] = useState(false);
+ const session = useSelector((state) => state.session);
const device = useSelector((state) => state.devices.items[deviceId]);
const position = useSelector(getPosition(deviceId));
@@ -100,11 +102,13 @@ const StatusView = ({
</Grid>
<Grid item container>
<Grid item>
- <Button color="secondary" onClick={handleClick}>{t('sharedShowInfo')}</Button>
+ <IconButton onClick={handleClick}>
+ <InfoIcon />
+ </IconButton>
</Grid>
<Grid item>
<IconButton onClick={onShowHistory}>
- <ReplayIcon />
+ <PlayCircleFilledIcon />
</IconButton>
</Grid>
<Grid item>
@@ -117,16 +121,20 @@ const StatusView = ({
<SendIcon />
</IconButton>
</Grid>
- <Grid item>
- <IconButton onClick={handleEditClick}>
- <EditIcon />
- </IconButton>
- </Grid>
- <Grid item>
- <IconButton onClick={handleRemove} className={classes.red}>
- <DeleteIcon />
- </IconButton>
- </Grid>
+ {!session.server.deviceReadonly && (
+ <>
+ <Grid item>
+ <IconButton onClick={handleEditClick}>
+ <EditIcon />
+ </IconButton>
+ </Grid>
+ <Grid item>
+ <IconButton onClick={handleRemove} className={classes.red}>
+ <DeleteIcon />
+ </IconButton>
+ </Grid>
+ </>
+ )}
</Grid>
</Grid>
</Paper>