diff options
Diffstat (limited to 'src/reports/CombinedReportPage.jsx')
-rw-r--r-- | src/reports/CombinedReportPage.jsx | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/src/reports/CombinedReportPage.jsx b/src/reports/CombinedReportPage.jsx new file mode 100644 index 00000000..a5000839 --- /dev/null +++ b/src/reports/CombinedReportPage.jsx @@ -0,0 +1,105 @@ +import React, { useState } from 'react'; +import { useSelector } from 'react-redux'; +import { + Table, TableBody, TableCell, TableHead, TableRow, +} from '@mui/material'; +import ReportFilter from './components/ReportFilter'; +import { useTranslation } from '../common/components/LocalizationProvider'; +import PageLayout from '../common/components/PageLayout'; +import ReportsMenu from './components/ReportsMenu'; +import { useCatch } from '../reactHelper'; +import MapView from '../map/core/MapView'; +import MapRoutePath from '../map/MapRoutePath'; +import useReportStyles from './common/useReportStyles'; +import TableShimmer from '../common/components/TableShimmer'; +import MapCamera from '../map/MapCamera'; +import MapGeofence from '../map/MapGeofence'; +import { formatTime } from '../common/util/formatter'; +import { usePreference } from '../common/util/preferences'; +import { prefixString } from '../common/util/stringUtils'; +import MapMarkers from '../map/MapMarkers'; + +const CombinedReportPage = () => { + const classes = useReportStyles(); + const t = useTranslation(); + + const devices = useSelector((state) => state.devices.items); + + const hours12 = usePreference('twelveHourFormat'); + + const [items, setItems] = useState([]); + const [loading, setLoading] = useState(false); + + const createMarkers = () => items.flatMap((item) => item.events + .map((event) => item.positions.find((p) => event.positionId === p.id)) + .filter((position) => position != null) + .map((position) => ({ + latitude: position.latitude, + longitude: position.longitude, + }))); + + const handleSubmit = useCatch(async ({ deviceIds, groupIds, from, to }) => { + const query = new URLSearchParams({ from, to }); + deviceIds.forEach((deviceId) => query.append('deviceId', deviceId)); + groupIds.forEach((groupId) => query.append('groupId', groupId)); + setLoading(true); + try { + const response = await fetch(`/api/reports/combined?${query.toString()}`); + if (response.ok) { + setItems(await response.json()); + } else { + throw Error(await response.text()); + } + } finally { + setLoading(false); + } + }); + + return ( + <PageLayout menu={<ReportsMenu />} breadcrumbs={['reportTitle', 'reportCombined']}> + <div className={classes.container}> + {Boolean(items.length) && ( + <div className={classes.containerMap}> + <MapView> + <MapGeofence /> + {items.map((item) => ( + <MapRoutePath + key={item.deviceId} + name={devices[item.deviceId].name} + coordinates={item.route} + /> + ))} + <MapMarkers markers={createMarkers()} /> + </MapView> + <MapCamera coordinates={items.flatMap((item) => item.route)} /> + </div> + )} + <div className={classes.containerMain}> + <div className={classes.header}> + <ReportFilter handleSubmit={handleSubmit} showOnly multiDevice includeGroups /> + </div> + <Table> + <TableHead> + <TableRow> + <TableCell>{t('sharedDevice')}</TableCell> + <TableCell>{t('positionFixTime')}</TableCell> + <TableCell>{t('sharedType')}</TableCell> + </TableRow> + </TableHead> + <TableBody> + {!loading ? items.flatMap((item) => item.events.map((event, index) => ( + <TableRow key={event.id}> + <TableCell>{index ? '' : devices[item.deviceId].name}</TableCell> + <TableCell>{formatTime(event.eventTime, 'seconds', hours12)}</TableCell> + <TableCell>{t(prefixString('event', event.type))}</TableCell> + </TableRow> + ))) : (<TableShimmer columns={3} />)} + </TableBody> + </Table> + </div> + </div> + </PageLayout> + ); +}; + +export default CombinedReportPage; |