From 16600db340dbdaa7f4b941e8e1bd6c6282d6a557 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 16 Oct 2022 16:50:37 -0700 Subject: Move status card --- modern/src/common/components/StatusCard.js | 266 +++++++++++++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 modern/src/common/components/StatusCard.js (limited to 'modern/src/common') diff --git a/modern/src/common/components/StatusCard.js b/modern/src/common/components/StatusCard.js new file mode 100644 index 00000000..b8d7ffc4 --- /dev/null +++ b/modern/src/common/components/StatusCard.js @@ -0,0 +1,266 @@ +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 './LocalizationProvider'; +import RemoveDialog from './RemoveDialog'; +import PositionValue from './PositionValue'; +import { useDeviceReadonly, useRestriction } from '../util/permissions'; +import usePersistedState from '../util/usePersistedState'; +import usePositionAttributes from '../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 ( + + + {name} + + + {content} + + + ); +}; + +const StatusCard = ({ deviceId, position, 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 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 && ( + + + {deviceImage ? ( + + + + + + ) : ( +
+ + {device.name} + + + + +
+ )} + {position && ( + + + + {positionItems.filter((key) => position.hasOwnProperty(key) || position.attributes.hasOwnProperty(key)).map((key) => ( + + )} + /> + ))} + +
+
+ )} + + setAnchorEl(e.currentTarget)} + disabled={!position} + > + + + navigate('/replay')} + disabled={!position} + > + + + navigate(`/settings/command-send/${deviceId}`)} + disabled={readonly} + > + + + navigate(`/settings/device/${deviceId}`)} + disabled={deviceReadonly} + > + + + setRemoving(true)} + disabled={deviceReadonly} + className={classes.negative} + > + + + +
+
+ )} + {position && ( + setAnchorEl(null)}> + navigate(`/position/${position.id}`)}>{t('sharedShowDetails')} + {t('sharedCreateGeofence')} + {t('linkGoogleMaps')} + {t('linkAppleMaps')} + {t('linkStreetView')} + + )} + handleRemove(removed)} + /> + + ); +}; + +export default StatusCard; -- cgit v1.2.3