From d4c9b1a045d214ca05fb1adaf6ab28cfe444c473 Mon Sep 17 00:00:00 2001
From: cka-y <60586858+cka-y@users.noreply.github.com>
Date: Thu, 29 Aug 2024 16:20:44 -0400
Subject: [PATCH] feat: GTFS Schedule Analytics UI (#653)
---
web-app/package.json | 15 +-
web-app/src/app/App.tsx | 22 +-
web-app/src/app/components/Header.tsx | 128 ++-
web-app/src/app/constants/Navigation.ts | 2 +
web-app/src/app/interface/RemoteConfig.ts | 11 +
web-app/src/app/router/Router.tsx | 9 +
.../Analytics/GTFSFeatureAnalytics/index.tsx | 225 +++++
.../GTFSFeedAnalytics/DetailPanel.tsx | 199 +++++
.../GTFSFeedAnalyticsTable.tsx | 329 ++++++++
.../Analytics/GTFSFeedAnalytics/index.tsx | 229 +++++
.../Analytics/GTFSNoticeAnalytics/index.tsx | 263 ++++++
.../src/app/screens/Analytics/analytics.css | 32 +
web-app/src/app/screens/Analytics/types.ts | 49 ++
web-app/src/app/screens/FAQ.tsx | 7 +-
.../src/app/screens/Feed/PreviousDatasets.tsx | 72 +-
web-app/src/app/screens/Home.tsx | 7 +-
web-app/src/app/store/analytics-reducer.ts | 72 ++
.../src/app/store/gtfs-analytics-selector.ts | 10 +
web-app/src/app/store/profile-selectors.ts | 3 +
web-app/src/app/store/reducers.ts | 2 +
.../src/app/store/saga/gtfs-analytics-saga.ts | 103 +++
web-app/src/app/store/saga/root-saga.ts | 2 +
web-app/src/app/utils/analytics.ts | 62 ++
web-app/yarn.lock | 789 +++++++++++++++---
24 files changed, 2464 insertions(+), 178 deletions(-)
create mode 100644 web-app/src/app/screens/Analytics/GTFSFeatureAnalytics/index.tsx
create mode 100644 web-app/src/app/screens/Analytics/GTFSFeedAnalytics/DetailPanel.tsx
create mode 100644 web-app/src/app/screens/Analytics/GTFSFeedAnalytics/GTFSFeedAnalyticsTable.tsx
create mode 100644 web-app/src/app/screens/Analytics/GTFSFeedAnalytics/index.tsx
create mode 100644 web-app/src/app/screens/Analytics/GTFSNoticeAnalytics/index.tsx
create mode 100644 web-app/src/app/screens/Analytics/analytics.css
create mode 100644 web-app/src/app/screens/Analytics/types.ts
create mode 100644 web-app/src/app/store/analytics-reducer.ts
create mode 100644 web-app/src/app/store/gtfs-analytics-selector.ts
create mode 100644 web-app/src/app/store/saga/gtfs-analytics-saga.ts
create mode 100644 web-app/src/app/utils/analytics.ts
diff --git a/web-app/package.json b/web-app/package.json
index 2ba21c217..759f6913b 100644
--- a/web-app/package.json
+++ b/web-app/package.json
@@ -3,20 +3,22 @@
"version": "0.1.0",
"private": true,
"dependencies": {
- "@emotion/react": "^11.11.1",
- "@emotion/styled": "^11.11.0",
+ "@emotion/react": "^11.13.0",
+ "@emotion/styled": "^11.13.0",
"@fortawesome/fontawesome-svg-core": "^6.4.2",
"@fortawesome/free-brands-svg-icons": "^6.4.2",
"@fortawesome/free-regular-svg-icons": "^6.4.2",
"@fortawesome/free-solid-svg-icons": "^6.4.2",
"@fortawesome/react-fontawesome": "^0.2.0",
- "@mui/icons-material": "^5.14.9",
- "@mui/material": "^5.14.9",
+ "@mui/icons-material": "^5.16.4",
+ "@mui/material": "^5.16.4",
+ "@mui/x-date-pickers": "^7.11.0",
"@mui/x-tree-view": "^6.17.0",
"@reduxjs/toolkit": "^1.9.6",
"@turf/center": "^6.5.0",
"@types/i18next": "^13.0.0",
"@types/leaflet": "^1.9.12",
+ "axios": "^1.7.2",
"country-code-emoji": "^2.3.0",
"date-fns": "^2.30.0",
"date-fns-tz": "^2.0.0",
@@ -26,6 +28,9 @@
"i18next-browser-languagedetector": "^8.0.0",
"i18next-http-backend": "^2.5.2",
"leaflet": "^1.9.4",
+ "material-react-table": "^2.13.0",
+ "mui-datatables": "^4.3.0",
+ "mui-nested-menu": "^3.4.0",
"openapi-fetch": "^0.9.3",
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0",
@@ -38,6 +43,7 @@
"react-redux": "^8.1.3",
"react-router-dom": "^6.16.0",
"react-scripts": "5.0.1",
+ "recharts": "^2.12.7",
"redux-persist": "^6.0.0",
"redux-saga": "^1.2.3",
"typeface-muli": "^1.1.13",
@@ -95,6 +101,7 @@
"@types/cypress": "^1.1.3",
"@types/jest": "^29.5.12",
"@types/material-ui": "^0.21.12",
+ "@types/mui-datatables": "^4.3.12",
"@types/node": "^20.8.10",
"@types/react": "^18.2.25",
"@types/react-dom": "^18.2.7",
diff --git a/web-app/src/app/App.tsx b/web-app/src/app/App.tsx
index 7ec4f7fd8..35162468a 100644
--- a/web-app/src/app/App.tsx
+++ b/web-app/src/app/App.tsx
@@ -11,6 +11,8 @@ import i18n from '../i18n';
import { Suspense, useEffect, useState } from 'react';
import { I18nextProvider } from 'react-i18next';
import { app } from '../firebase';
+import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
+import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
function App(): React.ReactElement {
require('typeface-muli'); // Load font
@@ -33,15 +35,17 @@ function App(): React.ReactElement {
-
-
-
-
- {isAppReady ? : null}
-
-
-
-
+
+
+
+
+
+ {isAppReady ? : null}
+
+
+
+
+
diff --git a/web-app/src/app/components/Header.tsx b/web-app/src/app/components/Header.tsx
index d63921864..b66312274 100644
--- a/web-app/src/app/components/Header.tsx
+++ b/web-app/src/app/components/Header.tsx
@@ -31,16 +31,18 @@ import {
import type NavigationItem from '../interface/Navigation';
import { useNavigate } from 'react-router-dom';
import { useSelector } from 'react-redux';
-import { selectIsAuthenticated } from '../store/selectors';
+import { selectIsAuthenticated, selectUserEmail } from '../store/selectors';
import LogoutConfirmModal from './LogoutConfirmModal';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
import { TreeView } from '@mui/x-tree-view/TreeView';
import { TreeItem } from '@mui/x-tree-view/TreeItem';
-import { OpenInNew } from '@mui/icons-material';
+import { BikeScooterOutlined, OpenInNew } from '@mui/icons-material';
import '../styles/Header.css';
import { useRemoteConfig } from '../context/RemoteConfigProvider';
import i18n from '../../i18n';
+import { NestedMenuItem } from 'mui-nested-menu';
+import DirectionsBusIcon from '@mui/icons-material/DirectionsBus';
const drawerWidth = 240;
const websiteTile = 'Mobility Database';
@@ -95,6 +97,38 @@ const DrawerContent: React.FC<{
))}
+ }
+ defaultExpandIcon={}
+ sx={{ textAlign: 'left' }}
+ >
+
+ {
+ onNavigationClick('/metrics/gtfs/feeds');
+ }}
+ />
+ {
+ onNavigationClick('/metrics/gtfs/notices');
+ }}
+ />
+ {
+ onNavigationClick('/metrics/gtfs/features');
+ }}
+ />
+
+
{isAuthenticated ? (
}
@@ -166,6 +200,7 @@ export default function DrawerAppBar(): React.ReactElement {
const navigateTo = useNavigate();
const isAuthenticated = useSelector(selectIsAuthenticated);
+ const userEmail = useSelector(selectUserEmail);
const handleDrawerToggle = (): void => {
setMobileOpen((prevState) => !prevState);
@@ -199,7 +234,7 @@ export default function DrawerAppBar(): React.ReactElement {
setAnchorEl(null);
};
- const handleMenuItemClick = (item: NavigationItem): void => {
+ const handleMenuItemClick = (item: NavigationItem | string): void => {
handleMenuClose();
handleNavigation(item);
};
@@ -260,6 +295,87 @@ export default function DrawerAppBar(): React.ReactElement {
{item.title}
))}
+ {/* Allow users with mobilitydata.org email to access metrics */}
+ {config.enableMetrics ||
+ (userEmail?.endsWith('mobilitydata.org') === true && (
+ <>
+ }
+ onClick={handleMenuOpen}
+ sx={{ color: 'black' }}
+ id='analytics-button-menu'
+ >
+ Metrics
+
+
+ >
+ ))}
+
{isAuthenticated ? (
<>
}
+ id='account-button-menu'
>
Account