From da482a847f119e83451f372c3bf6bc1c4f3e13ff Mon Sep 17 00:00:00 2001 From: Tyrel Narciso Date: Tue, 16 Apr 2024 16:41:36 -0700 Subject: [PATCH] DBC22-1948: Added snowplow integration and tracking --- src/frontend/src/Components/Filters.js | 21 +- src/frontend/src/Components/Map.js | 239 +++++++++++------- src/frontend/src/Components/TrackEvent.js | 13 + .../Components/advisories/AdvisoriesList.js | 3 +- .../Components/advisories/AdvisoriesOnMap.js | 3 +- .../src/Components/bulletins/BulletinsList.js | 3 +- .../src/Components/cameras/CameraCard.js | 21 ++ .../src/Components/map/LocationSearch.js | 4 +- src/frontend/src/index.js | 56 +++- src/frontend/src/pages/CamerasListPage.js | 4 +- src/frontend/src/pages/EventsListPage.js | 3 +- 11 files changed, 270 insertions(+), 100 deletions(-) create mode 100644 src/frontend/src/Components/TrackEvent.js diff --git a/src/frontend/src/Components/Filters.js b/src/frontend/src/Components/Filters.js index 5890e85d1..70fd61f20 100644 --- a/src/frontend/src/Components/Filters.js +++ b/src/frontend/src/Components/Filters.js @@ -18,6 +18,7 @@ import Button from 'react-bootstrap/Button'; import Tooltip from 'react-bootstrap/Tooltip'; import OverlayTrigger from 'react-bootstrap/OverlayTrigger'; import {useMediaQuery} from '@uidotdev/usehooks'; +import trackEvent from './TrackEvent.js'; // Components and functions @@ -139,6 +140,7 @@ export default function Filters(props) { name="closures" id="filter--closures" onChange={e => { + trackEvent('click', 'map', 'Toggle closures layer') toggleHandler('closures', e.target.checked); toggleHandler('closuresLines', e.target.checked, true); setClosures(!closures) @@ -163,6 +165,7 @@ export default function Filters(props) { name="major" id="filter--major" onChange={e => { + trackEvent('click', 'map', 'Toggle major events layer') toggleHandler('majorEvents', e.target.checked); toggleHandler('majorEventsLines', e.target.checked, true); setMajorEvents(!majorEvents) @@ -188,6 +191,7 @@ export default function Filters(props) { name="minor" id="filter--minor" onChange={e => { + trackEvent('click', 'map', 'Toggle minor events layer') toggleHandler('minorEvents', e.target.checked); toggleHandler('minorEventsLines', e.target.checked, true); setMinorEvents(!minorEvents); @@ -213,6 +217,7 @@ export default function Filters(props) { name="future events" id="filter--future-events" onChange={e => { + trackEvent('click', 'map', 'Toggle future events layer') toggleHandler('futureEvents', e.target.checked); toggleHandler('futureEventsLines', e.target.checked, true); setFutureEvents(!futureEvents); @@ -241,7 +246,9 @@ export default function Filters(props) { type="checkbox" name="highway cameras" id="filter--highway-cameras" - onChange={e => {toggleHandler('highwayCams', e.target.checked); setHighwayCams(!highwayCams)}} + onChange={e => { + trackEvent('click', 'map', 'Toggle highway cameras layer') + toggleHandler('highwayCams', e.target.checked); setHighwayCams(!highwayCams)}} defaultChecked={mapContext.visible_layers.highwayCams} disabled={disableFeatures} /> @@ -262,6 +269,7 @@ export default function Filters(props) { name="road conditions" id="filter--road-conditions" onChange={e => { + trackEvent('click', 'map', 'Toggle road conditions layer') toggleHandler('roadConditions', e.target.checked); toggleHandler('roadConditionsLines', e.target.checked); setRoadConditions(!roadConditions); @@ -287,7 +295,9 @@ export default function Filters(props) { type="checkbox" name="inland ferries" id="filter--inland-ferries" - onChange={e => {toggleHandler('inlandFerries', e.target.checked); setInlandFerries(!inlandFerries)}} + onChange={e => { + trackEvent('click', 'map', 'Toggle inland ferries layer') + toggleHandler('inlandFerries', e.target.checked); setInlandFerries(!inlandFerries)}} defaultChecked={mapContext.visible_layers.inlandFerries} disabled={disableFeatures} /> @@ -308,6 +318,7 @@ export default function Filters(props) { name="weather" id="filter--weather" onChange={e => { + trackEvent('click', 'map', 'Toggle weather layer') toggleHandler('weather', e.target.checked); toggleHandler('regional', e.target.checked); setWeather(!weather)} @@ -330,7 +341,9 @@ export default function Filters(props) { type="checkbox" name="rest stops" id="filter--rest-stops" - onChange={e => {toggleHandler('restStops', e.target.checked); setRestStops(!restStops)}} + onChange={e => { + trackEvent('click', 'map', 'Toggle rest stops layer') + toggleHandler('restStops', e.target.checked); setRestStops(!restStops)}} defaultChecked={mapContext.visible_layers.restStops} disabled={disableFeatures} /> @@ -338,7 +351,7 @@ export default function Filters(props) { + Rest stops diff --git a/src/frontend/src/Components/Map.js b/src/frontend/src/Components/Map.js index c4b42e90c..5b57228ad 100644 --- a/src/frontend/src/Components/Map.js +++ b/src/frontend/src/Components/Map.js @@ -74,6 +74,7 @@ import CurrentCameraIcon from './CurrentCameraIcon'; import Filters from './Filters.js'; import RouteSearch from './map/RouteSearch.js'; import ExitSurvey from './advisories/ExitSurvey.js'; +import trackEvent from './TrackEvent.js'; // Map & geospatial imports import { applyStyle } from 'ol-mapbox-style'; @@ -103,11 +104,7 @@ import { } from './data/featureStyleDefinitions.js'; import './Map.scss'; -export default function MapWrapper({ - camera, - isPreview, - mapViewRoute, -}) { +export default function MapWrapper({ camera, isPreview, mapViewRoute }) { // Redux const dispatch = useDispatch(); const { @@ -232,10 +229,10 @@ export default function MapWrapper({ const [clickedRestStop, setClickedRestStop] = useState(); const clickedRestStopRef = useRef(); - const updateClickedRestStop = (feature) => { + const updateClickedRestStop = feature => { clickedRestStopRef.current = feature; setClickedRestStop(feature); - } + }; const [advisoriesInView, setAdvisoriesInView] = useState([]); @@ -397,27 +394,38 @@ export default function MapWrapper({ updateClickedRegional(null); } - if (clickedRestStopRef.current && targetFeature != clickedRestStopRef.current) { - if(clickedRestStopRef.current !== undefined){ - const isClosed = isRestStopClosed(clickedRestStopRef.current.values_.properties); - const isLargeVehiclesAccommodated = clickedRestStopRef.current.values_.properties.ACCOM_COMMERCIAL_TRUCKS === "Yes"? true: false; - if(isClosed){ - if(isLargeVehiclesAccommodated){ - clickedRestStopRef.current.setStyle(restStopTruckClosedStyles['static']); - } - else{ - clickedRestStopRef.current.setStyle(restStopClosedStyles['static']); - } - } - else{ - if(isLargeVehiclesAccommodated){ - clickedRestStopRef.current.setStyle(restStopTruckStyles['static']); + if ( + clickedRestStopRef.current && + targetFeature != clickedRestStopRef.current + ) { + if (clickedRestStopRef.current !== undefined) { + const isClosed = isRestStopClosed( + clickedRestStopRef.current.values_.properties, + ); + const isLargeVehiclesAccommodated = + clickedRestStopRef.current.values_.properties + .ACCOM_COMMERCIAL_TRUCKS === 'Yes' + ? true + : false; + if (isClosed) { + if (isLargeVehiclesAccommodated) { + clickedRestStopRef.current.setStyle( + restStopTruckClosedStyles['static'], + ); + } else { + clickedRestStopRef.current.setStyle( + restStopClosedStyles['static'], + ); } - else{ + } else { + if (isLargeVehiclesAccommodated) { + clickedRestStopRef.current.setStyle( + restStopTruckStyles['static'], + ); + } else { clickedRestStopRef.current.setStyle(restStopStyles['static']); } } - } updateClickedRestStop(null); } @@ -485,32 +493,32 @@ export default function MapWrapper({ updateClickedRegional(feature); }; - const restStopClickHandler = (feature) => { + const restStopClickHandler = feature => { // reset previous clicked feature resetClickedStates(feature); // set new clicked rest stop feature const isClosed = isRestStopClosed(feature.values_.properties); - const isLargeVehiclesAccommodated = feature.values_.properties.ACCOM_COMMERCIAL_TRUCKS === 'Yes'? true: false; - if(isClosed){ - if(isLargeVehiclesAccommodated){ + const isLargeVehiclesAccommodated = + feature.values_.properties.ACCOM_COMMERCIAL_TRUCKS === 'Yes' + ? true + : false; + if (isClosed) { + if (isLargeVehiclesAccommodated) { feature.setStyle(restStopTruckClosedStyles['active']); - } - else{ + } else { feature.setStyle(restStopClosedStyles['active']); } - } - else{ - if(isLargeVehiclesAccommodated){ + } else { + if (isLargeVehiclesAccommodated) { feature.setStyle(restStopTruckStyles['active']); - } - else{ + } else { feature.setStyle(restStopStyles['active']); } } feature.setProperties({ clicked: true }, true); updateClickedRestStop(feature); - } + }; mapRef.current.on('click', async e => { const features = mapRef.current.getFeaturesAtPixel(e.pixel, { @@ -521,21 +529,53 @@ export default function MapWrapper({ const clickedFeature = features[0]; switch (clickedFeature.getProperties()['type']) { case 'camera': + trackEvent( + 'click', + 'map', + 'camera', + clickedFeature.getProperties().name, + ); camClickHandler(clickedFeature); return; case 'event': + console.log(clickedFeature.getProperties()); eventClickHandler(clickedFeature); return; case 'ferry': + trackEvent( + 'click', + 'map', + 'ferry', + clickedFeature.getProperties().name, + ); ferryClickHandler(clickedFeature); return; case 'weather': + trackEvent( + 'click', + 'map', + 'weather', + clickedFeature.getProperties().weather_station_name, + ); weatherClickHandler(clickedFeature); return; case 'regional': + trackEvent( + 'click', + 'map', + 'regional weather', + clickedFeature.getProperties().name, + ); regionalClickHandler(clickedFeature); return; case 'rest': + console.log(clickedFeature.getProperties()) + trackEvent( + 'click', + 'map', + 'rest stop', + clickedFeature.getProperties().properties.REST_AREA_NAME + ); restStopClickHandler(clickedFeature); return; } @@ -577,21 +617,30 @@ export default function MapWrapper({ break; case 'rest': { - const isClosed = isRestStopClosed(hoveredFeature.current.values_.properties); - const isLargeVehiclesAccommodated = hoveredFeature.current.values_.properties.ACCOM_COMMERCIAL_TRUCKS === 'Yes'? true: false; - if(isClosed){ - if(isLargeVehiclesAccommodated){ - hoveredFeature.current.setStyle(restStopTruckClosedStyles['static']); - } - else{ - hoveredFeature.current.setStyle(restStopClosedStyles['static']); - } - } - else{ - if(isLargeVehiclesAccommodated){ - hoveredFeature.current.setStyle(restStopTruckStyles['static']); + const isClosed = isRestStopClosed( + hoveredFeature.current.values_.properties, + ); + const isLargeVehiclesAccommodated = + hoveredFeature.current.values_.properties + .ACCOM_COMMERCIAL_TRUCKS === 'Yes' + ? true + : false; + if (isClosed) { + if (isLargeVehiclesAccommodated) { + hoveredFeature.current.setStyle( + restStopTruckClosedStyles['static'], + ); + } else { + hoveredFeature.current.setStyle( + restStopClosedStyles['static'], + ); } - else{ + } else { + if (isLargeVehiclesAccommodated) { + hoveredFeature.current.setStyle( + restStopTruckStyles['static'], + ); + } else { hoveredFeature.current.setStyle(restStopStyles['static']); } } @@ -642,21 +691,24 @@ export default function MapWrapper({ return; case 'rest': if (!targetFeature.getProperties().clicked) { - const isClosed = isRestStopClosed(targetFeature.values_.properties); - const isLargeVehiclesAccommodated = targetFeature.values_.properties.ACCOM_COMMERCIAL_TRUCKS === 'Yes'? true: false; - if(isClosed){ - if(isLargeVehiclesAccommodated){ + const isClosed = isRestStopClosed( + targetFeature.values_.properties, + ); + const isLargeVehiclesAccommodated = + targetFeature.values_.properties.ACCOM_COMMERCIAL_TRUCKS === + 'Yes' + ? true + : false; + if (isClosed) { + if (isLargeVehiclesAccommodated) { targetFeature.setStyle(restStopTruckClosedStyles['hover']); - } - else{ + } else { targetFeature.setStyle(restStopClosedStyles['hover']); } - } - else{ - if(isLargeVehiclesAccommodated){ + } else { + if (isLargeVehiclesAccommodated) { targetFeature.setStyle(restStopTruckStyles['hover']); - } - else{ + } else { targetFeature.setStyle(restStopStyles['hover']); } } @@ -698,9 +750,16 @@ export default function MapWrapper({ isInitialMountLocation.current = searchLocationFrom[0].label; // only zoomPan on from location change when to location is NOT set - } else if (isInitialMountLocation.current !== searchLocationFrom[0].label && searchLocationTo.length == 0) { + } else if ( + isInitialMountLocation.current !== searchLocationFrom[0].label && + searchLocationTo.length == 0 + ) { isInitialMountLocation.current = false; - setZoomPan(mapView, 9, fromLonLat(searchLocationFrom[0].geometry.coordinates)); + setZoomPan( + mapView, + 9, + fromLonLat(searchLocationFrom[0].geometry.coordinates), + ); } } else { // initial location was set, so no need to prevent pan/zoom @@ -873,8 +932,8 @@ export default function MapWrapper({ mapLayers.current['restStops'] = getRestStopsLayer( filteredRestStops, mapRef.current.getView().getProjection().getCode(), - mapContext - ) + mapContext, + ); mapRef.current.addLayer(mapLayers.current['restStops']); mapLayers.current['restStops'].setZIndex(68); @@ -957,10 +1016,12 @@ export default function MapWrapper({ const loadAdvisories = async () => { // Fetch data if it doesn't already exist if (!advisories) { - dispatch(updateAdvisories({ - list: await getAdvisories(), - timeStamp: new Date().getTime() - })); + dispatch( + updateAdvisories({ + list: await getAdvisories(), + timeStamp: new Date().getTime(), + }), + ); } }; @@ -1129,26 +1190,27 @@ export default function MapWrapper({ // check for active rest stop icons if (clickedRestStopRef.current) { const isClosed = isRestStopClosed(clickedRestStopRef.current.properties); - const isLargeVehiclesAccommodated = clickedRestStopRef.current.properties? clickedRestStopRef.current.properties.ACCOM_COMMERCIAL_TRUCKS === 'Yes': false; - if(isClosed){ - if(isLargeVehiclesAccommodated){ - clickedRestStopRef.current.setStyle(restStopTruckClosedStyles['static']); - - } - else{ - clickedRestStopRef.current.setStyle(restStopClosedStyles['static']); - } + const isLargeVehiclesAccommodated = clickedRestStopRef.current.properties + ? clickedRestStopRef.current.properties.ACCOM_COMMERCIAL_TRUCKS === + 'Yes' + : false; + if (isClosed) { + if (isLargeVehiclesAccommodated) { + clickedRestStopRef.current.setStyle( + restStopTruckClosedStyles['static'], + ); + } else { + clickedRestStopRef.current.setStyle(restStopClosedStyles['static']); } - else{ - if(isLargeVehiclesAccommodated){ - clickedRestStopRef.current.setStyle(restStopTruckStyles['static']); - } - else{ - clickedRestStopRef.current.setStyle(restStopStyles['static']); - } + } else { + if (isLargeVehiclesAccommodated) { + clickedRestStopRef.current.setStyle(restStopTruckStyles['static']); + } else { + clickedRestStopRef.current.setStyle(restStopStyles['static']); } - clickedRestStopRef.current.set('clicked', false); - updateClickedRestStop(null); + } + clickedRestStopRef.current.set('clicked', false); + updateClickedRestStop(null); } // Reset cam popup handler lock timer @@ -1262,12 +1324,11 @@ export default function MapWrapper({ className={`side-panel ${openPanel ? 'open' : ''}`} onClick={maximizePanel} onTouchMove={maximizePanel} - onKeyDown={(keyEvent) => { + onKeyDown={keyEvent => { if (keyEvent.keyCode == 13) { maximizePanel(); } }}> -