aboutsummaryrefslogtreecommitdiff
path: root/modern/src/other
diff options
context:
space:
mode:
authorAnton Tananaev <anton@traccar.org>2024-04-06 09:22:10 -0700
committerAnton Tananaev <anton@traccar.org>2024-04-06 09:22:10 -0700
commitf418231b6b2f5e030a0d2dcc390c314602b1f740 (patch)
tree10326adf3792bc2697e06bb5f2b8ef2a8f7e55fe /modern/src/other
parentb392a4af78e01c8e0f50aad5468e9583675b24be (diff)
downloadtrackermap-web-f418231b6b2f5e030a0d2dcc390c314602b1f740.tar.gz
trackermap-web-f418231b6b2f5e030a0d2dcc390c314602b1f740.tar.bz2
trackermap-web-f418231b6b2f5e030a0d2dcc390c314602b1f740.zip
Move modern to the top
Diffstat (limited to 'modern/src/other')
-rw-r--r--modern/src/other/EventPage.jsx108
-rw-r--r--modern/src/other/GeofencesList.jsx54
-rw-r--r--modern/src/other/GeofencesPage.jsx142
-rw-r--r--modern/src/other/NetworkPage.jsx122
-rw-r--r--modern/src/other/PositionPage.jsx110
-rw-r--r--modern/src/other/ReplayPage.jsx233
6 files changed, 0 insertions, 769 deletions
diff --git a/modern/src/other/EventPage.jsx b/modern/src/other/EventPage.jsx
deleted file mode 100644
index c8d84d5e..00000000
--- a/modern/src/other/EventPage.jsx
+++ /dev/null
@@ -1,108 +0,0 @@
-import React, { useCallback, useState } from 'react';
-
-import {
- Typography, AppBar, Toolbar, IconButton,
-} from '@mui/material';
-import makeStyles from '@mui/styles/makeStyles';
-import ArrowBackIcon from '@mui/icons-material/ArrowBack';
-import { useNavigate, useParams } from 'react-router-dom';
-import { useEffectAsync } from '../reactHelper';
-import { useTranslation } from '../common/components/LocalizationProvider';
-import MapView from '../map/core/MapView';
-import MapCamera from '../map/MapCamera';
-import MapPositions from '../map/MapPositions';
-import MapGeofence from '../map/MapGeofence';
-import StatusCard from '../common/components/StatusCard';
-import { formatNotificationTitle } from '../common/util/formatter';
-
-const useStyles = makeStyles(() => ({
- root: {
- height: '100%',
- display: 'flex',
- flexDirection: 'column',
- },
- toolbar: {
- zIndex: 1,
- },
- mapContainer: {
- flexGrow: 1,
- },
-}));
-
-const EventPage = () => {
- const classes = useStyles();
- const navigate = useNavigate();
- const t = useTranslation();
-
- const { id } = useParams();
-
- const [event, setEvent] = useState();
- const [position, setPosition] = useState();
- const [showCard, setShowCard] = useState(false);
-
- const formatType = (event) => formatNotificationTitle(t, {
- type: event.type,
- attributes: {
- alarms: event.attributes.alarm,
- },
- });
-
- const onMarkerClick = useCallback((positionId) => {
- setShowCard(!!positionId);
- }, [setShowCard]);
-
- useEffectAsync(async () => {
- if (id) {
- const response = await fetch(`/api/events/${id}`);
- if (response.ok) {
- setEvent(await response.json());
- } else {
- throw Error(await response.text());
- }
- }
- }, [id]);
-
- useEffectAsync(async () => {
- if (event && event.positionId) {
- const response = await fetch(`/api/positions?id=${event.positionId}`);
- if (response.ok) {
- const positions = await response.json();
- if (positions.length > 0) {
- setPosition(positions[0]);
- }
- } else {
- throw Error(await response.text());
- }
- }
- }, [event]);
-
- return (
- <div className={classes.root}>
- <AppBar color="inherit" position="static" className={classes.toolbar}>
- <Toolbar>
- <IconButton color="inherit" edge="start" sx={{ mr: 2 }} onClick={() => navigate('/')}>
- <ArrowBackIcon />
- </IconButton>
- <Typography variant="h6">{event && formatType(event)}</Typography>
- </Toolbar>
- </AppBar>
- <div className={classes.mapContainer}>
- <MapView>
- <MapGeofence />
- {position && <MapPositions positions={[position]} onClick={onMarkerClick} titleField="fixTime" />}
- </MapView>
- {position && <MapCamera latitude={position.latitude} longitude={position.longitude} />}
- {position && showCard && (
- <StatusCard
- deviceId={position.deviceId}
- position={position}
- onClose={() => setShowCard(false)}
- disableActions
- />
- )}
- </div>
- </div>
- );
-};
-
-export default EventPage;
diff --git a/modern/src/other/GeofencesList.jsx b/modern/src/other/GeofencesList.jsx
deleted file mode 100644
index d26eff09..00000000
--- a/modern/src/other/GeofencesList.jsx
+++ /dev/null
@@ -1,54 +0,0 @@
-import React, { Fragment } from 'react';
-import { useDispatch, useSelector } from 'react-redux';
-import makeStyles from '@mui/styles/makeStyles';
-import {
- Divider, List, ListItemButton, ListItemText,
-} from '@mui/material';
-
-import { geofencesActions } from '../store';
-import CollectionActions from '../settings/components/CollectionActions';
-import { useCatchCallback } from '../reactHelper';
-
-const useStyles = makeStyles(() => ({
- list: {
- maxHeight: '100%',
- overflow: 'auto',
- },
- icon: {
- width: '25px',
- height: '25px',
- filter: 'brightness(0) invert(1)',
- },
-}));
-
-const GeofencesList = ({ onGeofenceSelected }) => {
- const classes = useStyles();
- const dispatch = useDispatch();
-
- const items = useSelector((state) => state.geofences.items);
-
- const refreshGeofences = useCatchCallback(async () => {
- const response = await fetch('/api/geofences');
- if (response.ok) {
- dispatch(geofencesActions.refresh(await response.json()));
- } else {
- throw Error(await response.text());
- }
- }, [dispatch]);
-
- return (
- <List className={classes.list}>
- {Object.values(items).map((item, index, list) => (
- <Fragment key={item.id}>
- <ListItemButton key={item.id} onClick={() => onGeofenceSelected(item.id)}>
- <ListItemText primary={item.name} />
- <CollectionActions itemId={item.id} editPath="/settings/geofence" endpoint="geofences" setTimestamp={refreshGeofences} />
- </ListItemButton>
- {index < list.length - 1 ? <Divider /> : null}
- </Fragment>
- ))}
- </List>
- );
-};
-
-export default GeofencesList;
diff --git a/modern/src/other/GeofencesPage.jsx b/modern/src/other/GeofencesPage.jsx
deleted file mode 100644
index a27a6dca..00000000
--- a/modern/src/other/GeofencesPage.jsx
+++ /dev/null
@@ -1,142 +0,0 @@
-import React, { useState } from 'react';
-import { useDispatch } from 'react-redux';
-import {
- Divider, Typography, IconButton, useMediaQuery, Toolbar,
-} from '@mui/material';
-import Tooltip from '@mui/material/Tooltip';
-import makeStyles from '@mui/styles/makeStyles';
-import { useTheme } from '@mui/material/styles';
-import Drawer from '@mui/material/Drawer';
-import ArrowBackIcon from '@mui/icons-material/ArrowBack';
-import UploadFileIcon from '@mui/icons-material/UploadFile';
-import { useNavigate } from 'react-router-dom';
-import MapView from '../map/core/MapView';
-import MapCurrentLocation from '../map/MapCurrentLocation';
-import MapGeofenceEdit from '../map/draw/MapGeofenceEdit';
-import GeofencesList from './GeofencesList';
-import { useTranslation } from '../common/components/LocalizationProvider';
-import MapGeocoder from '../map/geocoder/MapGeocoder';
-import { errorsActions } from '../store';
-
-const useStyles = makeStyles((theme) => ({
- root: {
- height: '100%',
- display: 'flex',
- flexDirection: 'column',
- },
- content: {
- flexGrow: 1,
- overflow: 'hidden',
- display: 'flex',
- flexDirection: 'row',
- [theme.breakpoints.down('sm')]: {
- flexDirection: 'column-reverse',
- },
- },
- drawer: {
- zIndex: 1,
- },
- drawerPaper: {
- position: 'relative',
- [theme.breakpoints.up('sm')]: {
- width: theme.dimensions.drawerWidthTablet,
- },
- [theme.breakpoints.down('sm')]: {
- height: theme.dimensions.drawerHeightPhone,
- },
- },
- mapContainer: {
- flexGrow: 1,
- },
- title: {
- flexGrow: 1,
- },
- fileInput: {
- display: 'none',
- },
-}));
-
-const GeofencesPage = () => {
- const theme = useTheme();
- const classes = useStyles();
- const dispatch = useDispatch();
- const navigate = useNavigate();
- const t = useTranslation();
-
- const isPhone = useMediaQuery(theme.breakpoints.down('sm'));
-
- const [selectedGeofenceId, setSelectedGeofenceId] = useState();
-
- const handleFile = (event) => {
- const files = Array.from(event.target.files);
- const [file] = files;
- const reader = new FileReader();
- reader.onload = async () => {
- const xml = new DOMParser().parseFromString(reader.result, 'text/xml');
- const segment = xml.getElementsByTagName('trkseg')[0];
- const coordinates = Array.from(segment.getElementsByTagName('trkpt'))
- .map((point) => `${point.getAttribute('lat')} ${point.getAttribute('lon')}`)
- .join(', ');
- const area = `LINESTRING (${coordinates})`;
- const newItem = { name: t('sharedGeofence'), area };
- try {
- 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();
- navigate(`/settings/geofence/${item.id}`);
- } else {
- throw Error(await response.text());
- }
- } catch (error) {
- dispatch(errorsActions.push(error.message));
- }
- };
- reader.onerror = (event) => {
- dispatch(errorsActions.push(event.target.error));
- };
- reader.readAsText(file);
- };
-
- return (
- <div className={classes.root}>
- <div className={classes.content}>
- <Drawer
- className={classes.drawer}
- anchor={isPhone ? 'bottom' : 'left'}
- variant="permanent"
- classes={{ paper: classes.drawerPaper }}
- >
- <Toolbar>
- <IconButton edge="start" sx={{ mr: 2 }} onClick={() => navigate(-1)}>
- <ArrowBackIcon />
- </IconButton>
- <Typography variant="h6" className={classes.title}>{t('sharedGeofences')}</Typography>
- <label htmlFor="upload-gpx">
- <input accept=".gpx" id="upload-gpx" type="file" className={classes.fileInput} onChange={handleFile} />
- <IconButton edge="end" component="span" onClick={() => {}}>
- <Tooltip title={t('sharedUpload')}>
- <UploadFileIcon />
- </Tooltip>
- </IconButton>
- </label>
- </Toolbar>
- <Divider />
- <GeofencesList onGeofenceSelected={setSelectedGeofenceId} />
- </Drawer>
- <div className={classes.mapContainer}>
- <MapView>
- <MapGeofenceEdit selectedGeofenceId={selectedGeofenceId} />
- </MapView>
- <MapCurrentLocation />
- <MapGeocoder />
- </div>
- </div>
- </div>
- );
-};
-
-export default GeofencesPage;
diff --git a/modern/src/other/NetworkPage.jsx b/modern/src/other/NetworkPage.jsx
deleted file mode 100644
index 9dc00c61..00000000
--- a/modern/src/other/NetworkPage.jsx
+++ /dev/null
@@ -1,122 +0,0 @@
-import React, { useState } from 'react';
-import { useSelector } from 'react-redux';
-
-import {
- Typography, Container, Paper, AppBar, Toolbar, IconButton, Table, TableHead, TableRow, TableCell, TableBody,
-} from '@mui/material';
-import makeStyles from '@mui/styles/makeStyles';
-import ArrowBackIcon from '@mui/icons-material/ArrowBack';
-import { useNavigate, useParams } from 'react-router-dom';
-import { useEffectAsync } from '../reactHelper';
-
-const useStyles = makeStyles((theme) => ({
- root: {
- height: '100%',
- display: 'flex',
- flexDirection: 'column',
- },
- content: {
- overflow: 'auto',
- paddingTop: theme.spacing(2),
- paddingBottom: theme.spacing(2),
- display: 'flex',
- flexDirection: 'column',
- gap: theme.spacing(2),
- },
-}));
-
-const NetworkPage = () => {
- const classes = useStyles();
- const navigate = useNavigate();
-
- const { positionId } = useParams();
-
- const [item, setItem] = useState({});
-
- useEffectAsync(async () => {
- if (positionId) {
- const response = await fetch(`/api/positions?id=${positionId}`);
- if (response.ok) {
- const positions = await response.json();
- if (positions.length > 0) {
- setItem(positions[0]);
- }
- } else {
- throw Error(await response.text());
- }
- }
- }, [positionId]);
-
- const deviceName = useSelector((state) => {
- if (item) {
- const device = state.devices.items[item.deviceId];
- if (device) {
- return device.name;
- }
- }
- return null;
- });
-
- return (
- <div className={classes.root}>
- <AppBar position="sticky" color="inherit">
- <Toolbar>
- <IconButton color="inherit" edge="start" sx={{ mr: 2 }} onClick={() => navigate(-1)}>
- <ArrowBackIcon />
- </IconButton>
- <Typography variant="h6">
- {deviceName}
- </Typography>
- </Toolbar>
- </AppBar>
- <div className={classes.content}>
- <Container maxWidth="sm">
- <Paper>
- <Table>
- <TableHead>
- <TableRow>
- <TableCell>MCC</TableCell>
- <TableCell>MNC</TableCell>
- <TableCell>LAC</TableCell>
- <TableCell>CID</TableCell>
- </TableRow>
- </TableHead>
- <TableBody>
- {(item.network?.cellTowers || []).map((cell) => (
- <TableRow key={cell.cellId}>
- <TableCell>{cell.mobileCountryCode}</TableCell>
- <TableCell>{cell.mobileNetworkCode}</TableCell>
- <TableCell>{cell.locationAreaCode}</TableCell>
- <TableCell>{cell.cellId}</TableCell>
- </TableRow>
- ))}
- </TableBody>
- </Table>
- </Paper>
- </Container>
- <Container maxWidth="sm">
- <Paper>
- <Table>
- <TableHead>
- <TableRow>
- <TableCell>MAC</TableCell>
- <TableCell>RSSI</TableCell>
- </TableRow>
- </TableHead>
- <TableBody>
- {(item.network?.wifiAccessPoints || []).map((wifi) => (
- <TableRow key={wifi.macAddress}>
- <TableCell>{wifi.macAddress}</TableCell>
- <TableCell>{wifi.signalStrength}</TableCell>
- </TableRow>
- ))}
- </TableBody>
- </Table>
- </Paper>
- </Container>
- </div>
- </div>
- );
-};
-
-export default NetworkPage;
diff --git a/modern/src/other/PositionPage.jsx b/modern/src/other/PositionPage.jsx
deleted file mode 100644
index f253cd2c..00000000
--- a/modern/src/other/PositionPage.jsx
+++ /dev/null
@@ -1,110 +0,0 @@
-import React, { useState } from 'react';
-import { useSelector } from 'react-redux';
-
-import {
- Typography, Container, Paper, AppBar, Toolbar, IconButton, Table, TableHead, TableRow, TableCell, TableBody,
-} from '@mui/material';
-import makeStyles from '@mui/styles/makeStyles';
-import ArrowBackIcon from '@mui/icons-material/ArrowBack';
-import { useNavigate, useParams } from 'react-router-dom';
-import { useEffectAsync } from '../reactHelper';
-import { useTranslation } from '../common/components/LocalizationProvider';
-import PositionValue from '../common/components/PositionValue';
-import usePositionAttributes from '../common/attributes/usePositionAttributes';
-
-const useStyles = makeStyles((theme) => ({
- root: {
- height: '100%',
- display: 'flex',
- flexDirection: 'column',
- },
- content: {
- overflow: 'auto',
- paddingTop: theme.spacing(2),
- paddingBottom: theme.spacing(2),
- },
-}));
-
-const PositionPage = () => {
- const classes = useStyles();
- const navigate = useNavigate();
- const t = useTranslation();
-
- const positionAttributes = usePositionAttributes(t);
-
- const { id } = useParams();
-
- const [item, setItem] = useState();
-
- useEffectAsync(async () => {
- if (id) {
- const response = await fetch(`/api/positions?id=${id}`);
- if (response.ok) {
- const positions = await response.json();
- if (positions.length > 0) {
- setItem(positions[0]);
- }
- } else {
- throw Error(await response.text());
- }
- }
- }, [id]);
-
- const deviceName = useSelector((state) => {
- if (item) {
- const device = state.devices.items[item.deviceId];
- if (device) {
- return device.name;
- }
- }
- return null;
- });
-
- return (
- <div className={classes.root}>
- <AppBar position="sticky" color="inherit">
- <Toolbar>
- <IconButton color="inherit" edge="start" sx={{ mr: 2 }} onClick={() => navigate(-1)}>
- <ArrowBackIcon />
- </IconButton>
- <Typography variant="h6">
- {deviceName}
- </Typography>
- </Toolbar>
- </AppBar>
- <div className={classes.content}>
- <Container maxWidth="sm">
- <Paper>
- <Table>
- <TableHead>
- <TableRow>
- <TableCell>{t('stateName')}</TableCell>
- <TableCell>{t('sharedName')}</TableCell>
- <TableCell>{t('stateValue')}</TableCell>
- </TableRow>
- </TableHead>
- <TableBody>
- {item && Object.getOwnPropertyNames(item).filter((it) => it !== 'attributes').map((property) => (
- <TableRow key={property}>
- <TableCell>{property}</TableCell>
- <TableCell><strong>{positionAttributes[property]?.name || property}</strong></TableCell>
- <TableCell><PositionValue position={item} property={property} /></TableCell>
- </TableRow>
- ))}
- {item && Object.getOwnPropertyNames(item.attributes).map((attribute) => (
- <TableRow key={attribute}>
- <TableCell>{attribute}</TableCell>
- <TableCell><strong>{positionAttributes[attribute]?.name || attribute}</strong></TableCell>
- <TableCell><PositionValue position={item} attribute={attribute} /></TableCell>
- </TableRow>
- ))}
- </TableBody>
- </Table>
- </Paper>
- </Container>
- </div>
- </div>
- );
-};
-
-export default PositionPage;
diff --git a/modern/src/other/ReplayPage.jsx b/modern/src/other/ReplayPage.jsx
deleted file mode 100644
index 1050b976..00000000
--- a/modern/src/other/ReplayPage.jsx
+++ /dev/null
@@ -1,233 +0,0 @@
-import React, {
- useState, useEffect, useRef, useCallback,
-} from 'react';
-import {
- IconButton, Paper, Slider, Toolbar, Typography,
-} from '@mui/material';
-import makeStyles from '@mui/styles/makeStyles';
-import ArrowBackIcon from '@mui/icons-material/ArrowBack';
-import TuneIcon from '@mui/icons-material/Tune';
-import DownloadIcon from '@mui/icons-material/Download';
-import PlayArrowIcon from '@mui/icons-material/PlayArrow';
-import PauseIcon from '@mui/icons-material/Pause';
-import FastForwardIcon from '@mui/icons-material/FastForward';
-import FastRewindIcon from '@mui/icons-material/FastRewind';
-import { useNavigate } from 'react-router-dom';
-import { useSelector } from 'react-redux';
-import MapView from '../map/core/MapView';
-import MapRoutePath from '../map/MapRoutePath';
-import MapRoutePoints from '../map/MapRoutePoints';
-import MapPositions from '../map/MapPositions';
-import { formatTime } from '../common/util/formatter';
-import ReportFilter from '../reports/components/ReportFilter';
-import { useTranslation } from '../common/components/LocalizationProvider';
-import { useCatch } from '../reactHelper';
-import MapCamera from '../map/MapCamera';
-import MapGeofence from '../map/MapGeofence';
-import StatusCard from '../common/components/StatusCard';
-import { usePreference } from '../common/util/preferences';
-
-const useStyles = makeStyles((theme) => ({
- root: {
- height: '100%',
- },
- sidebar: {
- display: 'flex',
- flexDirection: 'column',
- position: 'fixed',
- zIndex: 3,
- left: 0,
- top: 0,
- margin: theme.spacing(1.5),
- width: theme.dimensions.drawerWidthDesktop,
- [theme.breakpoints.down('md')]: {
- width: '100%',
- margin: 0,
- },
- },
- title: {
- flexGrow: 1,
- },
- slider: {
- width: '100%',
- },
- controls: {
- display: 'flex',
- justifyContent: 'space-between',
- alignItems: 'center',
- },
- formControlLabel: {
- height: '100%',
- width: '100%',
- paddingRight: theme.spacing(1),
- justifyContent: 'space-between',
- alignItems: 'center',
- },
- content: {
- display: 'flex',
- flexDirection: 'column',
- padding: theme.spacing(2),
- [theme.breakpoints.down('md')]: {
- margin: theme.spacing(1),
- },
- [theme.breakpoints.up('md')]: {
- marginTop: theme.spacing(1),
- },
- },
-}));
-
-const ReplayPage = () => {
- const t = useTranslation();
- const classes = useStyles();
- const navigate = useNavigate();
- const timerRef = useRef();
-
- const hours12 = usePreference('twelveHourFormat');
-
- const defaultDeviceId = useSelector((state) => state.devices.selectedId);
-
- const [positions, setPositions] = useState([]);
- const [index, setIndex] = useState(0);
- const [selectedDeviceId, setSelectedDeviceId] = useState(defaultDeviceId);
- const [showCard, setShowCard] = useState(false);
- const [from, setFrom] = useState();
- const [to, setTo] = useState();
- const [expanded, setExpanded] = useState(true);
- const [playing, setPlaying] = useState(false);
-
- const deviceName = useSelector((state) => {
- if (selectedDeviceId) {
- const device = state.devices.items[selectedDeviceId];
- if (device) {
- return device.name;
- }
- }
- return null;
- });
-
- useEffect(() => {
- if (playing && positions.length > 0) {
- timerRef.current = setInterval(() => {
- setIndex((index) => index + 1);
- }, 500);
- } else {
- clearInterval(timerRef.current);
- }
-
- return () => clearInterval(timerRef.current);
- }, [playing, positions]);
-
- useEffect(() => {
- if (index >= positions.length - 1) {
- clearInterval(timerRef.current);
- setPlaying(false);
- }
- }, [index, positions]);
-
- const onPointClick = useCallback((_, index) => {
- setIndex(index);
- }, [setIndex]);
-
- const onMarkerClick = useCallback((positionId) => {
- setShowCard(!!positionId);
- }, [setShowCard]);
-
- const handleSubmit = useCatch(async ({ deviceId, from, to }) => {
- setSelectedDeviceId(deviceId);
- setFrom(from);
- setTo(to);
- const query = new URLSearchParams({ deviceId, from, to });
- const response = await fetch(`/api/positions?${query.toString()}`);
- if (response.ok) {
- setIndex(0);
- const positions = await response.json();
- setPositions(positions);
- if (positions.length) {
- setExpanded(false);
- } else {
- throw Error(t('sharedNoData'));
- }
- } else {
- throw Error(await response.text());
- }
- });
-
- const handleDownload = () => {
- const query = new URLSearchParams({ deviceId: selectedDeviceId, from, to });
- window.location.assign(`/api/positions/kml?${query.toString()}`);
- };
-
- return (
- <div className={classes.root}>
- <MapView>
- <MapGeofence />
- <MapRoutePath positions={positions} />
- <MapRoutePoints positions={positions} onClick={onPointClick} />
- {index < positions.length && (
- <MapPositions positions={[positions[index]]} onClick={onMarkerClick} titleField="fixTime" />
- )}
- </MapView>
- <MapCamera positions={positions} />
- <div className={classes.sidebar}>
- <Paper elevation={3} square>
- <Toolbar>
- <IconButton edge="start" sx={{ mr: 2 }} onClick={() => navigate(-1)}>
- <ArrowBackIcon />
- </IconButton>
- <Typography variant="h6" className={classes.title}>{t('reportReplay')}</Typography>
- {!expanded && (
- <>
- <IconButton onClick={handleDownload}>
- <DownloadIcon />
- </IconButton>
- <IconButton edge="end" onClick={() => setExpanded(true)}>
- <TuneIcon />
- </IconButton>
- </>
- )}
- </Toolbar>
- </Paper>
- <Paper className={classes.content} square>
- {!expanded ? (
- <>
- <Typography variant="subtitle1" align="center">{deviceName}</Typography>
- <Slider
- className={classes.slider}
- max={positions.length - 1}
- step={null}
- marks={positions.map((_, index) => ({ value: index }))}
- value={index}
- onChange={(_, index) => setIndex(index)}
- />
- <div className={classes.controls}>
- {`${index + 1}/${positions.length}`}
- <IconButton onClick={() => setIndex((index) => index - 1)} disabled={playing || index <= 0}>
- <FastRewindIcon />
- </IconButton>
- <IconButton onClick={() => setPlaying(!playing)} disabled={index >= positions.length - 1}>
- {playing ? <PauseIcon /> : <PlayArrowIcon /> }
- </IconButton>
- <IconButton onClick={() => setIndex((index) => index + 1)} disabled={playing || index >= positions.length - 1}>
- <FastForwardIcon />
- </IconButton>
- {formatTime(positions[index].fixTime, 'seconds', hours12)}
- </div>
- </>
- ) : (
- <ReportFilter handleSubmit={handleSubmit} fullScreen showOnly />
- )}
- </Paper>
- </div>
- {showCard && index < positions.length && (
- <StatusCard
- deviceId={selectedDeviceId}
- position={positions[index]}
- onClose={() => setShowCard(false)}
- disableActions
- />
- )}
- </div>
- );
-};
-
-export default ReplayPage;