From 84966404694f93d46e860386f1533e4834e66951 Mon Sep 17 00:00:00 2001 From: ray Date: Wed, 25 Sep 2024 17:00:14 -0700 Subject: [PATCH] DBC22-2794: added web worker and polling component to event list page --- .../src/Components/shared/PollingComponent.js | 27 +++++++++ src/frontend/src/pages/EventsListPage.js | 60 +++++++++++++------ src/frontend/src/pages/EventsListPage.scss | 10 +++- 3 files changed, 77 insertions(+), 20 deletions(-) create mode 100644 src/frontend/src/Components/shared/PollingComponent.js diff --git a/src/frontend/src/Components/shared/PollingComponent.js b/src/frontend/src/Components/shared/PollingComponent.js new file mode 100644 index 000000000..e8708b825 --- /dev/null +++ b/src/frontend/src/Components/shared/PollingComponent.js @@ -0,0 +1,27 @@ +// React +import React, { useEffect } from 'react'; + +export default function PollingComponent(props) { + /* Setup */ + // Props + const { interval, runnable } = props; + + // Effects + useEffect(() => { + // Set up reoccuring calls with interval + const intervalId = setInterval(() => { + runnable(); + }, interval); + + // Clean up intervals on component unmount + return () => { + clearInterval(intervalId); + }; + }, []); + + /* Rendering */ + // Main component + return ( + <> + ); +} diff --git a/src/frontend/src/pages/EventsListPage.js b/src/frontend/src/pages/EventsListPage.js index 0f3eddfec..ff3096a47 100644 --- a/src/frontend/src/pages/EventsListPage.js +++ b/src/frontend/src/pages/EventsListPage.js @@ -6,7 +6,7 @@ import { createSearchParams, useNavigate } from 'react-router-dom'; import { useSelector, useDispatch } from 'react-redux'; import { memoize } from 'proxy-memoize'; import { updateAdvisories } from '../slices/cmsSlice'; -import { updateEvents } from '../slices/feedsSlice'; +import * as slices from '../slices'; // External imports import { booleanIntersects, point, lineString, multiPolygon } from '@turf/turf'; @@ -25,10 +25,7 @@ import Dropdown from 'react-bootstrap/Dropdown'; import Button from 'react-bootstrap/Button'; // Internal imports -import { - compareRoutePoints, - filterByRoute, -} from '../Components/map/helpers'; +import { compareRoutePoints } from '../Components/map/helpers'; import { getAdvisories } from '../Components/data/advisories'; import { getEvents } from '../Components/data/events'; import { MapContext } from '../App.js'; @@ -42,6 +39,7 @@ import EventsTable from '../Components/events/EventsTable'; import Filters from '../Components/shared/Filters.js'; import Footer from '../Footer.js'; import PageHeader from '../PageHeader'; +import PollingComponent from '../Components/shared/PollingCountdown'; import RouteSearch from '../Components/routing/RouteSearch'; import trackEvent from '../Components/shared/TrackEvent.js'; import AdvisoriesPanel from '../Components/map/panels/AdvisoriesPanel'; @@ -80,9 +78,12 @@ const sortEvents = (events, key) => { } export default function EventsListPage() { - const navigate = useNavigate(); + /* Setup */ document.title = 'DriveBC - Delays'; + // Navigation + const navigate = useNavigate(); + // Redux const dispatch = useDispatch(); const { advisories, events, filteredEvents, eventFilterPoints, selectedRoute } = useSelector(useCallback(memoize(state => ({ @@ -126,6 +127,7 @@ export default function EventsListPage() { // Refs const isInitialMount = useRef(true); + const workerRef = useRef(); // Data functions const getAdvisoriesData = async (eventsData) => { @@ -143,7 +145,7 @@ export default function EventsListPage() { // load all advisories if no route selected const resAdvisories = selectedRoute && selectedRoute.routeFound ? [] : advData; - // Route selected, load advisories that intersect with at least one event on route + // Route selected, load advisories that intersect with at least one event on route if (selectedRoute && selectedRoute.routeFound && advData && advData.length > 0 && eventsData && eventsData.length > 0) { for (const adv of advData) { const advPoly = multiPolygon(adv.geometry.coordinates); @@ -171,17 +173,7 @@ export default function EventsListPage() { // Fetch data if it doesn't already exist const eventData = events ? events : await getEvents().catch((error) => displayError(error)); - // Filter data by route - const filteredEventData = route && route.routeFound ? filterByRoute(eventData, route, null, true) : eventData; - - dispatch( - updateEvents({ - list: eventData, - filteredList: filteredEventData, - filterPoints: route && route.routeFound ? route.points : null, - timeStamp: new Date().getTime() - }) - ); + workerRef.current.postMessage({data: eventData, route: (route && route.routeFound ? route : null), action: 'updateEvents'}); // Stop loader if data already exists } else { @@ -224,6 +216,36 @@ export default function EventsListPage() { }; // useEffect hooks + useEffect(() => { + // Create a new worker if it doesn't exist + if (!workerRef.current) { + workerRef.current = new Worker(new URL('../Components/map/filterRouteWorker.js', import.meta.url)); + + // Set up event listener for messages from the worker + workerRef.current.onmessage = function (event) { + const { data, filteredData, route, action } = event.data; + + dispatch( + slices[action]({ + list: data, + filteredList: filteredData, + filterPoints: route ? route.points : null, + timeStamp: new Date().getTime() + }) + ); + + setShowLoader(false); + }; + } + + // Cleanup function to terminate the worker when the component unmounts + return () => { + if (workerRef.current) { + workerRef.current.terminate(); + } + }; + }, []); + useEffect(() => { setShowLoader(true); @@ -396,6 +418,8 @@ export default function EventsListPage() { /> + setShowLoader(true)} interval={30000} /> +
{ largeScreen && !!processedEvents.length && diff --git a/src/frontend/src/pages/EventsListPage.scss b/src/frontend/src/pages/EventsListPage.scss index 9eef5cd2c..5979b5a21 100644 --- a/src/frontend/src/pages/EventsListPage.scss +++ b/src/frontend/src/pages/EventsListPage.scss @@ -19,8 +19,14 @@ justify-content: space-between; } + .polling-filters-container { + display: flex; + align-items: flex-end; + justify-content: space-between; + } + .dropdown.sorting { - margin-left: auto; + margin-left: auto; margin-right: 16px; @media (min-width: 1200px) { @@ -142,4 +148,4 @@ .minor .eventType { background: #FEF0D8; color: $Gold110; -} \ No newline at end of file +}