From f5e0b9606ef106aade3285ab1e85ea5783b11a99 Mon Sep 17 00:00:00 2001 From: Matt Date: Sun, 26 Apr 2026 21:43:58 +0000 Subject: [PATCH] fix: search viewport init, theme-clears-route bug, preview-during-route Three regressions fixed: 1. mapCenter is now initialized on map 'load' event, not just 'moveend'. Searches immediately after page load now correctly include viewport bias instead of falling back to default Twin Falls coords. 2. setThemeOverride had stray code from startDirections that wiped stops and added undefined place data. Toggling theme cleared the active route. Restored setThemeOverride to its correct theme-only implementation. 3. usePanelState returned ROUTE_CALCULATED before checking selectedPlace, so preview cards could never appear alongside a calculated route. Refactored to decouple preview state from route state - preview renders whenever selectedPlace exists, independent of route state. --- src/components/MapView.jsx | 7 +++++++ src/components/Panel.jsx | 12 ++++++------ src/store.js | 20 ++++++++------------ 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/components/MapView.jsx b/src/components/MapView.jsx index 9cc0498..31eb6cb 100644 --- a/src/components/MapView.jsx +++ b/src/components/MapView.jsx @@ -964,6 +964,13 @@ const MapView = forwardRef(function MapView(_, ref) { } } }) + // Initialize mapCenter immediately when map loads (Fix 1: search viewport) + map.once('load', () => { + const center = map.getCenter() + const zoom = map.getZoom() + setMapCenter({ lat: center.lat, lon: center.lng, zoom }) + }) + map.on('load', () => { map.addSource(ROUTE_SOURCE, { type: 'geojson', diff --git a/src/components/Panel.jsx b/src/components/Panel.jsx index d06c1de..9cc28da 100644 --- a/src/components/Panel.jsx +++ b/src/components/Panel.jsx @@ -32,7 +32,7 @@ export default function Panel({ onManeuverClick }) { const activeTab = useStore((s) => s.activeTab) const setActiveTab = useStore((s) => s.setActiveTab) - const panelState = usePanelState() + const { hasPreview, routeState } = usePanelState() const [isMobile, setIsMobile] = useState(false) const [optimizing, setOptimizing] = useState(false) @@ -126,11 +126,11 @@ export default function Panel({ onManeuverClick }) { const showOptimize = effectiveCount >= 3 - // Determine what to show based on panel state - const showPreviewCard = panelState === 'PREVIEW' || panelState === 'PREVIEW_ROUTING' - const showRouteSection = panelState === 'ROUTING' || panelState === 'PREVIEW_ROUTING' || panelState === 'ROUTE_CALCULATED' - const showManeuvers = panelState === 'ROUTE_CALCULATED' - const showEmptyState = panelState === 'IDLE' + // Determine what to show based on panel state (preview and route are now orthogonal) + const showPreviewCard = hasPreview + const showRouteSection = routeState === 'ROUTING' || routeState === 'CALCULATED' + const showManeuvers = routeState === 'CALCULATED' + const showEmptyState = !hasPreview && routeState === 'NONE' // Routes tab content - now state-driven const routesContent = ( diff --git a/src/store.js b/src/store.js index 8ce6fcc..dcc84cd 100644 --- a/src/store.js +++ b/src/store.js @@ -1,4 +1,5 @@ import { create } from 'zustand' +import { shallow } from 'zustand/shallow' export const useStore = create((set, get) => ({ // ── Search state ── @@ -108,9 +109,6 @@ export const useStore = create((set, get) => ({ if (override) { localStorage.setItem('navi-theme-override', override) } else { - // GPS denied, no stops: add destination, show empty origin slot - clearStops() - addStop({ lat: place.lat, lon: place.lon, name: place.name, source: place.source, matchCode: place.matchCode }) localStorage.removeItem('navi-theme-override') } }, @@ -124,16 +122,14 @@ export const useStore = create((set, get) => ({ setActiveTab: (tab) => set({ activeTab: tab }), setEditingContact: (c) => set({ editingContact: c }), clearEditingContact: () => set({ editingContact: null }), -})) +}), shallow) // ── Panel state selector ── -// IDLE | PREVIEW | ROUTING | PREVIEW_ROUTING | ROUTE_CALCULATED +// Returns { hasPreview: boolean, routeState: 'NONE' | 'ROUTING' | 'CALCULATED' } +// Preview and route states are now orthogonal - preview can show alongside any route state export const usePanelState = () => { - return useStore((s) => { - if (s.route) return "ROUTE_CALCULATED" - if (s.selectedPlace && s.stops.length >= 1) return "PREVIEW_ROUTING" - if (s.selectedPlace) return "PREVIEW" - if (s.stops.length >= 1) return "ROUTING" - return "IDLE" - }) + return useStore((s) => ({ + hasPreview: !!s.selectedPlace, + routeState: s.route ? "CALCULATED" : (s.stops.length >= 1 ? "ROUTING" : "NONE") + }), shallow) }