aboutsummaryrefslogtreecommitdiff
path: root/modern
diff options
context:
space:
mode:
authorAnton Tananaev <anton@traccar.org>2023-01-27 14:24:09 -0800
committerAnton Tananaev <anton@traccar.org>2023-01-27 14:24:09 -0800
commit2a1bc9710eb1005a8937dc7ec63c25975bb28f41 (patch)
treeaf414797d86b809f845562e498637a4f2f2bf9ce /modern
parentc2f20eb92f9d916df576d6fecc4063c41a089b0e (diff)
downloadtrackermap-web-2a1bc9710eb1005a8937dc7ec63c25975bb28f41.tar.gz
trackermap-web-2a1bc9710eb1005a8937dc7ec63c25975bb28f41.tar.bz2
trackermap-web-2a1bc9710eb1005a8937dc7ec63c25975bb28f41.zip
Scheduled reports page
Diffstat (limited to 'modern')
-rw-r--r--modern/src/CachingController.js13
-rw-r--r--modern/src/Navigation.js4
-rw-r--r--modern/src/reports/ScheduledPage.js91
-rw-r--r--modern/src/reports/components/ReportsMenu.js30
-rw-r--r--modern/src/resources/l10n/en.json1
-rw-r--r--modern/src/store/calendars.js16
-rw-r--r--modern/src/store/index.js3
7 files changed, 143 insertions, 15 deletions
diff --git a/modern/src/CachingController.js b/modern/src/CachingController.js
index 1c8fb43a..55a4e020 100644
--- a/modern/src/CachingController.js
+++ b/modern/src/CachingController.js
@@ -1,7 +1,7 @@
import { useDispatch, useSelector, connect } from 'react-redux';
import {
- geofencesActions, groupsActions, driversActions, maintenancesActions,
+ geofencesActions, groupsActions, driversActions, maintenancesActions, calendarsActions,
} from './store';
import { useEffectAsync } from './reactHelper';
@@ -53,6 +53,17 @@ const CachingController = () => {
}
}, [authenticated]);
+ useEffectAsync(async () => {
+ if (authenticated) {
+ const response = await fetch('/api/calendars');
+ if (response.ok) {
+ dispatch(calendarsActions.update(await response.json()));
+ } else {
+ throw Error(await response.text());
+ }
+ }
+ }, [authenticated]);
+
return null;
};
diff --git a/modern/src/Navigation.js b/modern/src/Navigation.js
index d08fc12b..1e3a37b2 100644
--- a/modern/src/Navigation.js
+++ b/modern/src/Navigation.js
@@ -48,6 +48,7 @@ import CommandSendPage from './settings/CommandSendPage';
import App from './App';
import ChangeServerPage from './other/ChangeServerPage';
import DevicesPage from './settings/DevicesPage';
+import ScheduledPage from './reports/ScheduledPage';
const Navigation = () => {
const navigate = useNavigate();
@@ -141,10 +142,11 @@ const Navigation = () => {
<Route path="chart" element={<ChartReportPage />} />
<Route path="event" element={<EventReportPage />} />
<Route path="route" element={<RouteReportPage />} />
- <Route path="statistics" element={<StatisticsPage />} />
<Route path="stop" element={<StopReportPage />} />
<Route path="summary" element={<SummaryReportPage />} />
<Route path="trip" element={<TripReportPage />} />
+ <Route path="scheduled" element={<ScheduledPage />} />
+ <Route path="statistics" element={<StatisticsPage />} />
</Route>
</Route>
</Routes>
diff --git a/modern/src/reports/ScheduledPage.js b/modern/src/reports/ScheduledPage.js
new file mode 100644
index 00000000..831588b0
--- /dev/null
+++ b/modern/src/reports/ScheduledPage.js
@@ -0,0 +1,91 @@
+import React, { useState } from 'react';
+import { useSelector } from 'react-redux';
+import {
+ Table, TableRow, TableCell, TableHead, TableBody, IconButton,
+} from '@mui/material';
+import makeStyles from '@mui/styles/makeStyles';
+import DeleteIcon from '@mui/icons-material/Delete';
+import { useEffectAsync } from '../reactHelper';
+import { useTranslation } from '../common/components/LocalizationProvider';
+import PageLayout from '../common/components/PageLayout';
+import ReportsMenu from './components/ReportsMenu';
+import TableShimmer from '../common/components/TableShimmer';
+
+const useStyles = makeStyles((theme) => ({
+ columnAction: {
+ width: '1%',
+ paddingRight: theme.spacing(1),
+ },
+}));
+
+const ScheduledPage = () => {
+ const classes = useStyles();
+ const t = useTranslation();
+
+ const calendars = useSelector((state) => state.calendars.items);
+
+ const [items, setItems] = useState([]);
+ const [loading, setLoading] = useState(false);
+
+ useEffectAsync(async () => {
+ setLoading(true);
+ try {
+ const response = await fetch('/api/reports');
+ if (response.ok) {
+ setItems(await response.json());
+ } else {
+ throw Error(await response.text());
+ }
+ } finally {
+ setLoading(false);
+ }
+ }, []);
+
+ const formatType = (type) => {
+ switch (type) {
+ case 'events':
+ return t('reportEvents');
+ case 'route':
+ return t('reportRoute');
+ case 'summary':
+ return t('reportSummary');
+ case 'trips':
+ return t('reportTrips');
+ case 'stops':
+ return t('reportStops');
+ default:
+ return type;
+ }
+ };
+
+ return (
+ <PageLayout menu={<ReportsMenu />} breadcrumbs={['settingsTitle', 'sharedDrivers']}>
+ <Table>
+ <TableHead>
+ <TableRow>
+ <TableCell>{t('sharedType')}</TableCell>
+ <TableCell>{t('sharedDescription')}</TableCell>
+ <TableCell>{t('sharedCalendar')}</TableCell>
+ <TableCell className={classes.columnAction} />
+ </TableRow>
+ </TableHead>
+ <TableBody>
+ {!loading ? items.map((item) => (
+ <TableRow key={item.id}>
+ <TableCell>{formatType(item.type)}</TableCell>
+ <TableCell>{item.description}</TableCell>
+ <TableCell>{calendars[item.calendarId].name}</TableCell>
+ <TableCell className={classes.columnAction} padding="none">
+ <IconButton size="small" onClick={() => {}}>
+ <DeleteIcon fontSize="small" />
+ </IconButton>
+ </TableCell>
+ </TableRow>
+ )) : (<TableShimmer columns={4} endAction />)}
+ </TableBody>
+ </Table>
+ </PageLayout>
+ );
+};
+
+export default ScheduledPage;
diff --git a/modern/src/reports/components/ReportsMenu.js b/modern/src/reports/components/ReportsMenu.js
index 8fa7df2d..3616f828 100644
--- a/modern/src/reports/components/ReportsMenu.js
+++ b/modern/src/reports/components/ReportsMenu.js
@@ -10,6 +10,7 @@ import FormatListBulletedIcon from '@mui/icons-material/FormatListBulleted';
import TrendingUpIcon from '@mui/icons-material/TrendingUp';
import BarChartIcon from '@mui/icons-material/BarChart';
import RouteIcon from '@mui/icons-material/Route';
+import EventRepeatIcon from '@mui/icons-material/EventRepeat';
import { Link, useLocation } from 'react-router-dom';
import { useTranslation } from '../../common/components/LocalizationProvider';
import { useAdministrator } from '../../common/util/permissions';
@@ -74,19 +75,22 @@ const ReportsMenu = () => {
icon={<RouteIcon />}
/>
</List>
- {admin && (
- <>
- <Divider />
- <List>
- <MenuItem
- title={t('statisticsTitle')}
- link="/reports/statistics"
- icon={<BarChartIcon />}
- selected={location.pathname === '/reports/statistics'}
- />
- </List>
- </>
- )}
+ <Divider />
+ <List>
+ <MenuItem
+ title={t('reportScheduled')}
+ link="/reports/scheduled"
+ icon={<EventRepeatIcon />}
+ />
+ {admin && (
+ <MenuItem
+ title={t('statisticsTitle')}
+ link="/reports/statistics"
+ icon={<BarChartIcon />}
+ selected={location.pathname === '/reports/statistics'}
+ />
+ )}
+ </List>
</>
);
};
diff --git a/modern/src/resources/l10n/en.json b/modern/src/resources/l10n/en.json
index f68f0083..d93ad5bf 100644
--- a/modern/src/resources/l10n/en.json
+++ b/modern/src/resources/l10n/en.json
@@ -220,6 +220,7 @@
"settingsAppVersion": "App Version",
"settingsConnection": "Connection",
"reportTitle": "Reports",
+ "reportScheduled": "Scheduled Reports",
"reportDevice": "Device",
"reportGroup": "Group",
"reportFrom": "From",
diff --git a/modern/src/store/calendars.js b/modern/src/store/calendars.js
new file mode 100644
index 00000000..924288e6
--- /dev/null
+++ b/modern/src/store/calendars.js
@@ -0,0 +1,16 @@
+import { createSlice } from '@reduxjs/toolkit';
+
+const { reducer, actions } = createSlice({
+ name: 'calendars',
+ initialState: {
+ items: {},
+ },
+ reducers: {
+ update(state, action) {
+ action.payload.forEach((item) => state.items[item.id] = item);
+ },
+ },
+});
+
+export { actions as calendarsActions };
+export { reducer as calendarsReducer };
diff --git a/modern/src/store/index.js b/modern/src/store/index.js
index 0cc32d38..ea685ff3 100644
--- a/modern/src/store/index.js
+++ b/modern/src/store/index.js
@@ -8,6 +8,7 @@ import { geofencesReducer as geofences } from './geofences';
import { groupsReducer as groups } from './groups';
import { driversReducer as drivers } from './drivers';
import { maintenancesReducer as maintenances } from './maintenances';
+import { calendarsReducer as calendars } from './calendars';
import { reportsReducer as reports } from './reports';
import throttleMiddleware from './throttleMiddleware';
@@ -20,6 +21,7 @@ const reducer = combineReducers({
groups,
drivers,
maintenances,
+ calendars,
reports,
});
@@ -31,6 +33,7 @@ export { geofencesActions } from './geofences';
export { groupsActions } from './groups';
export { driversActions } from './drivers';
export { maintenancesActions } from './maintenances';
+export { calendarsActions } from './calendars';
export { reportsActions } from './reports';
export default configureStore({