diff options
author | Anton Tananaev <anton@traccar.org> | 2022-10-16 16:50:37 -0700 |
---|---|---|
committer | Anton Tananaev <anton@traccar.org> | 2022-10-16 16:50:37 -0700 |
commit | 16600db340dbdaa7f4b941e8e1bd6c6282d6a557 (patch) | |
tree | c09a285e3ff33dd16ae5b22380161c4763619d10 /modern/src/main | |
parent | ac8adb34066745322297ae5a63feb00724d503a6 (diff) | |
download | trackermap-web-16600db340dbdaa7f4b941e8e1bd6c6282d6a557.tar.gz trackermap-web-16600db340dbdaa7f4b941e8e1bd6c6282d6a557.tar.bz2 trackermap-web-16600db340dbdaa7f4b941e8e1bd6c6282d6a557.zip |
Move status card
Diffstat (limited to 'modern/src/main')
-rw-r--r-- | modern/src/main/MainPage.js | 3 | ||||
-rw-r--r-- | modern/src/main/StatusCard.js | 267 |
2 files changed, 2 insertions, 268 deletions
diff --git a/modern/src/main/MainPage.js b/modern/src/main/MainPage.js index 90e1b920..a174096e 100644 --- a/modern/src/main/MainPage.js +++ b/modern/src/main/MainPage.js @@ -25,7 +25,7 @@ import BottomMenu from '../common/components/BottomMenu'; import { useTranslation } from '../common/components/LocalizationProvider'; import PoiMap from '../map/main/PoiMap'; import MapPadding from '../map/MapPadding'; -import StatusCard from './StatusCard'; +import StatusCard from '../common/components/StatusCard'; import { devicesActions } from '../store'; import MapDefaultCamera from '../map/main/MapDefaultCamera'; import usePersistedState from '../common/util/usePersistedState'; @@ -370,6 +370,7 @@ const MainPage = () => { <div className={classes.statusCard}> <StatusCard deviceId={selectedDeviceId} + position={positions[selectedDeviceId]} onClose={() => dispatch(devicesActions.select(null))} /> </div> diff --git a/modern/src/main/StatusCard.js b/modern/src/main/StatusCard.js deleted file mode 100644 index 5ca45066..00000000 --- a/modern/src/main/StatusCard.js +++ /dev/null @@ -1,267 +0,0 @@ -import React, { useState } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import { useNavigate } from 'react-router-dom'; -import Draggable from 'react-draggable'; -import { - Card, - CardContent, - Typography, - CardActions, - IconButton, - Table, - TableBody, - TableRow, - TableCell, - Menu, - MenuItem, - CardMedia, -} from '@mui/material'; -import makeStyles from '@mui/styles/makeStyles'; -import CloseIcon from '@mui/icons-material/Close'; -import ReplayIcon from '@mui/icons-material/Replay'; -import PublishIcon from '@mui/icons-material/Publish'; -import EditIcon from '@mui/icons-material/Edit'; -import DeleteIcon from '@mui/icons-material/Delete'; -import PendingIcon from '@mui/icons-material/Pending'; - -import { useTranslation } from '../common/components/LocalizationProvider'; -import RemoveDialog from '../common/components/RemoveDialog'; -import PositionValue from '../common/components/PositionValue'; -import { useDeviceReadonly, useRestriction } from '../common/util/permissions'; -import usePersistedState from '../common/util/usePersistedState'; -import usePositionAttributes from '../common/attributes/usePositionAttributes'; -import { devicesActions } from '../store'; -import { useCatch, useCatchCallback } from '../reactHelper'; - -const useStyles = makeStyles((theme) => ({ - card: { - width: theme.dimensions.popupMaxWidth, - }, - media: { - height: theme.dimensions.popupImageHeight, - display: 'flex', - justifyContent: 'flex-end', - alignItems: 'flex-start', - }, - mediaButton: { - color: theme.palette.colors.white, - mixBlendMode: 'difference', - }, - header: { - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - padding: theme.spacing(1, 1, 0, 2), - }, - content: { - paddingTop: theme.spacing(1), - paddingBottom: theme.spacing(1), - }, - negative: { - color: theme.palette.colors.negative, - }, - icon: { - width: '25px', - height: '25px', - filter: 'brightness(0) invert(1)', - }, - table: { - '& .MuiTableCell-sizeSmall': { - paddingLeft: 0, - paddingRight: 0, - }, - }, - cell: { - borderBottom: 'none', - }, - actions: { - justifyContent: 'space-between', - }, -})); - -const StatusRow = ({ name, content }) => { - const classes = useStyles(); - - return ( - <TableRow> - <TableCell className={classes.cell}> - <Typography variant="body2">{name}</Typography> - </TableCell> - <TableCell className={classes.cell}> - <Typography variant="body2" color="textSecondary">{content}</Typography> - </TableCell> - </TableRow> - ); -}; - -const StatusCard = ({ deviceId, onClose }) => { - const classes = useStyles(); - const navigate = useNavigate(); - const dispatch = useDispatch(); - const t = useTranslation(); - - const readonly = useRestriction('readonly'); - const deviceReadonly = useDeviceReadonly(); - - const device = useSelector((state) => state.devices.items[deviceId]); - const position = useSelector((state) => state.positions.items[deviceId]); - - const deviceImage = device?.attributes?.deviceImage; - - const positionAttributes = usePositionAttributes(t); - const [positionItems] = usePersistedState('positionItems', ['speed', 'address', 'totalDistance', 'course']); - - const [anchorEl, setAnchorEl] = useState(null); - - const [removing, setRemoving] = useState(false); - - const handleRemove = useCatch(async (removed) => { - if (removed) { - const response = await fetch('/api/devices'); - if (response.ok) { - dispatch(devicesActions.refresh(await response.json())); - } else { - throw Error(await response.text()); - } - } - setRemoving(false); - }); - - const handleGeofence = useCatchCallback(async () => { - const newItem = { - name: '', - area: `CIRCLE (${position.latitude} ${position.longitude}, 50)`, - }; - const response = await fetch('/api/geofences', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(newItem), - }); - if (response.ok) { - const item = await response.json(); - const permissionResponse = await fetch('/api/permissions', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ deviceId: position.deviceId, geofenceId: item.id }), - }); - if (!permissionResponse.ok) { - throw Error(await permissionResponse.text()); - } - navigate(`/settings/geofence/${item.id}`); - } else { - throw Error(await response.text()); - } - }, [navigate]); - - return ( - <> - {device && ( - <Draggable - handle={`.${classes.media}, .${classes.header}`} - > - <Card elevation={3} className={classes.card}> - {deviceImage ? ( - <CardMedia - className={classes.media} - image={`/api/media/${device.uniqueId}/${deviceImage}`} - > - <IconButton - size="small" - onClick={onClose} - onTouchStart={onClose} - > - <CloseIcon fontSize="small" className={classes.mediaButton} /> - </IconButton> - </CardMedia> - ) : ( - <div className={classes.header}> - <Typography variant="body2" color="textSecondary"> - {device.name} - </Typography> - <IconButton - size="small" - onClick={onClose} - onTouchStart={onClose} - > - <CloseIcon fontSize="small" /> - </IconButton> - </div> - )} - {position && ( - <CardContent className={classes.content}> - <Table size="small" classes={{ root: classes.table }}> - <TableBody> - {positionItems.filter((key) => position.hasOwnProperty(key) || position.attributes.hasOwnProperty(key)).map((key) => ( - <StatusRow - key={key} - name={positionAttributes[key].name} - content={( - <PositionValue - position={position} - property={position.hasOwnProperty(key) ? key : null} - attribute={position.hasOwnProperty(key) ? null : key} - /> - )} - /> - ))} - </TableBody> - </Table> - </CardContent> - )} - <CardActions classes={{ root: classes.actions }} disableSpacing> - <IconButton - color="secondary" - onClick={(e) => setAnchorEl(e.currentTarget)} - disabled={!position} - > - <PendingIcon /> - </IconButton> - <IconButton - onClick={() => navigate('/replay')} - disabled={!position} - > - <ReplayIcon /> - </IconButton> - <IconButton - onClick={() => navigate(`/settings/command-send/${deviceId}`)} - disabled={readonly} - > - <PublishIcon /> - </IconButton> - <IconButton - onClick={() => navigate(`/settings/device/${deviceId}`)} - disabled={deviceReadonly} - > - <EditIcon /> - </IconButton> - <IconButton - onClick={() => setRemoving(true)} - disabled={deviceReadonly} - className={classes.negative} - > - <DeleteIcon /> - </IconButton> - </CardActions> - </Card> - </Draggable> - )} - {position && ( - <Menu anchorEl={anchorEl} open={Boolean(anchorEl)} onClose={() => setAnchorEl(null)}> - <MenuItem onClick={() => navigate(`/position/${position.id}`)}><Typography color="secondary">{t('sharedShowDetails')}</Typography></MenuItem> - <MenuItem onClick={handleGeofence}>{t('sharedCreateGeofence')}</MenuItem> - <MenuItem component="a" target="_blank" href={`https://www.google.com/maps/search/?api=1&query=${position.latitude}%2C${position.longitude}`}>{t('linkGoogleMaps')}</MenuItem> - <MenuItem component="a" target="_blank" href={`http://maps.apple.com/?ll=${position.latitude},${position.longitude}`}>{t('linkAppleMaps')}</MenuItem> - <MenuItem component="a" target="_blank" href={`https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=${position.latitude}%2C${position.longitude}&heading=${position.course}`}>{t('linkStreetView')}</MenuItem> - </Menu> - )} - <RemoveDialog - open={removing} - endpoint="devices" - itemId={deviceId} - onResult={(removed) => handleRemove(removed)} - /> - </> - ); -}; - -export default StatusCard; |