From 4da6dddbe1ca3f933a92184a9e4bfffe4f189978 Mon Sep 17 00:00:00 2001 From: Steve Tarter Date: Sat, 5 Sep 2026 08:48:06 -0500 Subject: [PATCH] feat(roadrunner-view): localize Google Maps to Canada and enhance map interactions - Configure region="CA" on Google Maps APIProvider instances in App.tsx. - Add fallback handling to google.maps.Marker in PointPicker when AdvancedMarkerElement is unavailable. - Update default map provider fallback to 'google' in CreateVehiclePanel. - Add navigation to vehicle driver view when clicking "Jump to" in SimulationTable. - Refine historical session lookup error handling and timeout redirect logic in GoogleDriverViewPage. --- apps/roadrunner-view/src/App.tsx | 6 +-- .../GoogleDriverViewPage.tsx | 17 +++++-- .../HomePage/CreateVehiclePanel.tsx | 2 +- .../components/HomePage/SimulationTable.tsx | 9 +++- .../src/components/Shared/PointPicker.tsx | 50 +++++++++++++------ 5 files changed, 61 insertions(+), 23 deletions(-) diff --git a/apps/roadrunner-view/src/App.tsx b/apps/roadrunner-view/src/App.tsx index 3c4d32b..304a9a9 100644 --- a/apps/roadrunner-view/src/App.tsx +++ b/apps/roadrunner-view/src/App.tsx @@ -52,19 +52,19 @@ const ProviderEnforcedRoute = ({ requiredProvider, component: Component }: { req }; const WrappedGoogleHomePage = () => ( - + ); const WrappedGoogleVehicle3DMapPage = () => ( - + ); const WrappedGoogleDriverViewPage = () => ( - + ); diff --git a/apps/roadrunner-view/src/components/GoogleDriverViewPage/GoogleDriverViewPage.tsx b/apps/roadrunner-view/src/components/GoogleDriverViewPage/GoogleDriverViewPage.tsx index 6088044..e7d6cdc 100644 --- a/apps/roadrunner-view/src/components/GoogleDriverViewPage/GoogleDriverViewPage.tsx +++ b/apps/roadrunner-view/src/components/GoogleDriverViewPage/GoogleDriverViewPage.tsx @@ -261,8 +261,7 @@ export const GoogleDriverViewPage = () => { } } } catch (error) { - console.error("Historical session lookup failed, exiting to home:", error); - gotoHomePage(); + console.error("Historical session lookup failed:", error); } finally { setIsSearchingSession(false); setHasCheckedHistory(true); @@ -274,6 +273,17 @@ export const GoogleDriverViewPage = () => { // Handle Auto-Redirects useEffect(() => { + if (goingHome) return; + + if (isDataLoaded && version > 0 && !isSearchingSession && hasCheckedHistory && !vehicleStateMap.has(vehicleId) && !lastState) { + if (missingTimestampRef.current === null) { + missingTimestampRef.current = Date.now(); + } else if (Date.now() - missingTimestampRef.current > 10000) { + gotoHomePage(); + } + return; + } + const msCurrentTime = Date.now() - playbackOffset; if ((playbackOffset === 0) && lastState && (lastState.msEpochLastRun < msCurrentTime - (30 * 1000))) { @@ -283,8 +293,9 @@ export const GoogleDriverViewPage = () => { const currentState = vehicleStateMap.get(vehicleId); if (currentState && (lastState?.msEpochLastRun !== currentState.msEpochLastRun)) { setLastState(currentState); + missingTimestampRef.current = null; } - }, [vehicleStateMap, vehicleId, lastState, playbackOffset, gotoHomePage]); + }, [vehicleStateMap, vehicleId, lastState, playbackOffset, gotoHomePage, isDataLoaded, version, isSearchingSession, hasCheckedHistory, goingHome]); const getCoordinateAtBearingAndRange = useCallback((degLatitude: number, degLongitude: number, degBearing: number, mRange: number) => { const KM_EARTH_RADIUS = 6378.14; diff --git a/apps/roadrunner-view/src/components/HomePage/CreateVehiclePanel.tsx b/apps/roadrunner-view/src/components/HomePage/CreateVehiclePanel.tsx index 358fe41..39e0c66 100644 --- a/apps/roadrunner-view/src/components/HomePage/CreateVehiclePanel.tsx +++ b/apps/roadrunner-view/src/components/HomePage/CreateVehiclePanel.tsx @@ -99,7 +99,7 @@ export const CreateVehiclePanel = (props: { const data = await response.json(); // Hop into the vehicle. - const provider = localStorage.getItem('roadrunner_map_provider') || 'mapbox'; + const provider = localStorage.getItem('roadrunner_map_provider') || 'google'; navigate(provider === 'google' ? `/google/driver-view/${data.id}` : `/driver-view/${data.id}`); } catch (error) { console.error(error); diff --git a/apps/roadrunner-view/src/components/HomePage/SimulationTable.tsx b/apps/roadrunner-view/src/components/HomePage/SimulationTable.tsx index e2184a8..bcf7c13 100644 --- a/apps/roadrunner-view/src/components/HomePage/SimulationTable.tsx +++ b/apps/roadrunner-view/src/components/HomePage/SimulationTable.tsx @@ -1,4 +1,5 @@ import { useMemo, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; import { MaterialReactTable } from 'material-react-table'; import { usePlayback } from "../../context/PlaybackContext"; import { useSimulationSessionData } from "../../hooks/useSimulationSessionData"; @@ -20,6 +21,7 @@ export const SimulationTable = (props: { toggleSimTable: any, returnToNow: any, }) => { + const navigate = useNavigate(); const { playbackOffset, setPlaybackSession } = usePlayback(); const { simulationSessionMap, activeCountData } = useSimulationSessionData(); @@ -91,8 +93,13 @@ export const SimulationTable = (props: { variant="primary" size="sm" onClick={() => { + const vehicleId = row.original.vehicleId || row.original.id; setPlaybackSession(row.original.start); props.toggleSimTable(); + if (vehicleId) { + const provider = localStorage.getItem('roadrunner_map_provider') || 'google'; + navigate(provider === 'google' ? `/google/driver-view/${vehicleId}` : `/driver-view/${vehicleId}`); + } }} > Jump to @@ -100,7 +107,7 @@ export const SimulationTable = (props: { ), }, ], - [props, setPlaybackSession] + [props, setPlaybackSession, navigate] ); return ( diff --git a/apps/roadrunner-view/src/components/Shared/PointPicker.tsx b/apps/roadrunner-view/src/components/Shared/PointPicker.tsx index ae0e90b..888ee0f 100644 --- a/apps/roadrunner-view/src/components/Shared/PointPicker.tsx +++ b/apps/roadrunner-view/src/components/Shared/PointPicker.tsx @@ -148,31 +148,51 @@ export const PointPicker = ({ markerRef.current = null; } - // Reuse/update Google AdvancedMarkerElement - if (typeof google !== 'undefined' && google.maps && google.maps.marker?.AdvancedMarkerElement) { + // Reuse/update Google Marker (AdvancedMarkerElement or standard Marker) + if (typeof google !== 'undefined' && google.maps) { const position = { lat: selectedLat, lng: selectedLng }; if (googleMarkerRef.current) { - googleMarkerRef.current.position = position; + if (typeof googleMarkerRef.current.setPosition === 'function') { + googleMarkerRef.current.setPosition(position); + } else { + googleMarkerRef.current.position = position; + } if (googleInfoWindowRef.current) { googleInfoWindowRef.current.setPosition(position); } } else { - const marker = new google.maps.marker.AdvancedMarkerElement({ - position: position, - map: map, - title: label - }); + let marker: any = null; + if (google.maps.marker?.AdvancedMarkerElement) { + try { + marker = new google.maps.marker.AdvancedMarkerElement({ + position: position, + map: map, + title: label + }); + } catch (err) { + console.warn("AdvancedMarkerElement initialization failed, falling back to google.maps.Marker", err); + } + } + if (!marker && google.maps.Marker) { + marker = new google.maps.Marker({ + position: position, + map: map, + title: label + }); + } - const infoWindow = new google.maps.InfoWindow({ - content: `
${label}
`, - disableAutoPan: true - }); + if (marker) { + const infoWindow = new google.maps.InfoWindow({ + content: `
${label}
`, + disableAutoPan: true + }); - infoWindow.open(map, marker); + infoWindow.open(map, marker); - googleMarkerRef.current = marker; - googleInfoWindowRef.current = infoWindow; + googleMarkerRef.current = marker; + googleInfoWindowRef.current = infoWindow; + } } } }