aboutsummaryrefslogtreecommitdiff
path: root/modern/src/map/StatusCard.js
diff options
context:
space:
mode:
authorAnton Tananaev <anton@traccar.org>2022-05-01 15:26:08 -0700
committerAnton Tananaev <anton@traccar.org>2022-05-01 15:26:08 -0700
commitaf6b60f85ba09a9d1a258cf9d1b6b61d4b8e4fe5 (patch)
tree6fe30c87a48ad5a438554f8cb594028b49efcfef /modern/src/map/StatusCard.js
parent90f292b7739835202842d88eeaf55a531d29d3c3 (diff)
downloadtrackermap-web-af6b60f85ba09a9d1a258cf9d1b6b61d4b8e4fe5.tar.gz
trackermap-web-af6b60f85ba09a9d1a258cf9d1b6b61d4b8e4fe5.tar.bz2
trackermap-web-af6b60f85ba09a9d1a258cf9d1b6b61d4b8e4fe5.zip
Migrate to a card for popup
Diffstat (limited to 'modern/src/map/StatusCard.js')
-rw-r--r--modern/src/map/StatusCard.js136
1 files changed, 136 insertions, 0 deletions
diff --git a/modern/src/map/StatusCard.js b/modern/src/map/StatusCard.js
new file mode 100644
index 00000000..47f7724d
--- /dev/null
+++ b/modern/src/map/StatusCard.js
@@ -0,0 +1,136 @@
+import React, { useState } from 'react';
+import { useSelector } from 'react-redux';
+import { useHistory } from 'react-router-dom';
+import {
+ makeStyles, Button, Card, CardContent, Typography, CardActions, CardHeader, IconButton, Avatar, Table, TableBody, TableRow, TableCell, TableContainer,
+} from '@material-ui/core';
+import CloseIcon from '@material-ui/icons/Close';
+import ReplayIcon from '@material-ui/icons/Replay';
+import ExitToAppIcon from '@material-ui/icons/ExitToApp';
+import EditIcon from '@material-ui/icons/Edit';
+import DeleteIcon from '@material-ui/icons/Delete';
+
+import { useTranslation } from '../LocalizationProvider';
+import { formatDistance, formatPosition, formatSpeed, formatStatus } from '../common/formatter';
+import RemoveDialog from '../RemoveDialog';
+import { useAttributePreference } from '../common/preferences';
+
+const useStyles = makeStyles((theme) => ({
+ paper: {
+ width: '300px',
+ },
+ negative: {
+ color: theme.palette.colors.negative,
+ },
+ listItemContainer: {
+ maxWidth: '240px',
+ },
+ icon: {
+ width: '25px',
+ height: '25px',
+ filter: 'brightness(0) invert(1)',
+ },
+ table: {
+ '& .MuiTableCell-sizeSmall': {
+ paddingLeft: theme.spacing(0.5),
+ paddingRight: theme.spacing(0.5),
+ },
+ },
+ cell: {
+ borderBottom: 'none',
+ },
+}));
+
+const StatusRow = ({ name, value }) => {
+ const classes = useStyles();
+
+ return (
+ <TableRow>
+ <TableCell className={classes.cell}>
+ <Typography variant="body2">{name}</Typography>
+ </TableCell>
+ <TableCell className={classes.cell}>
+ <Typography variant="body2" color="textSecondary">{value}</Typography>
+ </TableCell>
+ </TableRow>
+ );
+}
+
+const StatusCard = ({ deviceId, onClose }) => {
+ const classes = useStyles();
+ const history = useHistory();
+ const t = useTranslation();
+
+ const device = useSelector((state) => state.devices.items[deviceId]);
+ const position = useSelector((state) => state.positions.items[deviceId]);
+
+ const distanceUnit = useAttributePreference('distanceUnit');
+ const speedUnit = useAttributePreference('speedUnit');
+
+ const [removeDialogShown, setRemoveDialogShown] = useState(false);
+
+ return (
+ <>
+ {device &&
+ <Card>
+ <CardHeader
+ avatar={
+ <Avatar>
+ <img className={classes.icon} src={`images/icon/${device.category || 'default'}.svg`} alt="" />
+ </Avatar>
+ }
+ action={
+ <IconButton onClick={onClose}>
+ <CloseIcon />
+ </IconButton>
+ }
+ title={device.name}
+ subheader={formatStatus(device.status, t)}
+ />
+ {position &&
+ <CardContent>
+ <TableContainer>
+ <Table size="small" classes={{ root: classes.table }}>
+ <TableBody>
+ <StatusRow name={t('positionSpeed')} value={formatSpeed(position.speed, speedUnit, t)} />
+ <StatusRow name={t('positionBattery')} value={formatSpeed(position.speed, speedUnit, t)} />
+ {position.attributes.odometer
+ ? <StatusRow name={t('positionOdometer')} value={formatDistance(position.attributes.odometer, distanceUnit, t)} />
+ : <StatusRow name={t('deviceTotalDistance')} value={formatDistance(position.attributes.totalDistance, distanceUnit, t)} />
+ }
+ <StatusRow name={t('positionCourse')} value={formatPosition(position.course, 'course', t)} />
+ </TableBody>
+ </Table>
+ </TableContainer>
+ </CardContent>
+ }
+ <CardActions disableSpacing>
+ <Button onClick={() => history.push(`/position/${position.id}`)} disabled={!position} color="secondary">
+ {t('sharedInfoTitle')}
+ </Button>
+ <IconButton onClick={() => history.push('/replay')} disabled={!position}>
+ <ReplayIcon />
+ </IconButton>
+ <IconButton>
+ <ExitToAppIcon />
+ </IconButton>
+ <IconButton onClick={() => history.push(`/device/${deviceId}`)}>
+ <EditIcon />
+ </IconButton>
+ <IconButton onClick={() => setRemoveDialogShown(true)} className={classes.negative}>
+ <DeleteIcon />
+ </IconButton>
+ </CardActions>
+ </Card>
+ }
+ <RemoveDialog
+ open={removeDialogShown}
+ endpoint="devices"
+ itemId={deviceId}
+ onResult={() => setRemoveDialogShown(false)}
+ />
+ </>
+ );
+};
+
+export default StatusCard;