mirror of
https://github.com/zvx-echo6/navi.git
synced 2026-05-20 14:44:51 +02:00
fix: usePanelState returns string, preview decoupled from route
Fixes React error #185 (infinite re-render loop) caused by returning object from Zustand selector without shallow comparison. Changed usePanelState to return string states that encode both preview and route status: - PREVIEW_CALCULATED: preview + calculated route - PREVIEW_ROUTING: preview + stops (no route yet) - PREVIEW: preview only - ROUTE_CALCULATED: calculated route only - ROUTING: stops only - IDLE: nothing Panel.jsx updated to derive show flags from string states using startsWith and includes checks.
This commit is contained in:
parent
f5e0b9606e
commit
721bc2c9f5
2 changed files with 20 additions and 14 deletions
|
|
@ -32,7 +32,7 @@ export default function Panel({ onManeuverClick }) {
|
|||
const activeTab = useStore((s) => s.activeTab)
|
||||
const setActiveTab = useStore((s) => s.setActiveTab)
|
||||
|
||||
const { hasPreview, routeState } = usePanelState()
|
||||
const panelState = 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 (preview and route are now orthogonal)
|
||||
const showPreviewCard = hasPreview
|
||||
const showRouteSection = routeState === 'ROUTING' || routeState === 'CALCULATED'
|
||||
const showManeuvers = routeState === 'CALCULATED'
|
||||
const showEmptyState = !hasPreview && routeState === 'NONE'
|
||||
// Determine what to show based on panel state
|
||||
const showPreviewCard = panelState.startsWith('PREVIEW')
|
||||
const showRouteSection = ['ROUTING', 'ROUTE_CALCULATED', 'PREVIEW_ROUTING', 'PREVIEW_CALCULATED'].includes(panelState)
|
||||
const showManeuvers = panelState === 'ROUTE_CALCULATED' || panelState === 'PREVIEW_CALCULATED'
|
||||
const showEmptyState = panelState === 'IDLE'
|
||||
|
||||
// Routes tab content - now state-driven
|
||||
const routesContent = (
|
||||
|
|
|
|||
22
src/store.js
22
src/store.js
|
|
@ -1,5 +1,4 @@
|
|||
import { create } from 'zustand'
|
||||
import { shallow } from 'zustand/shallow'
|
||||
|
||||
export const useStore = create((set, get) => ({
|
||||
// ── Search state ──
|
||||
|
|
@ -122,14 +121,21 @@ export const useStore = create((set, get) => ({
|
|||
setActiveTab: (tab) => set({ activeTab: tab }),
|
||||
setEditingContact: (c) => set({ editingContact: c }),
|
||||
clearEditingContact: () => set({ editingContact: null }),
|
||||
}), shallow)
|
||||
}))
|
||||
|
||||
// ── Panel state selector ──
|
||||
// Returns { hasPreview: boolean, routeState: 'NONE' | 'ROUTING' | 'CALCULATED' }
|
||||
// Preview and route states are now orthogonal - preview can show alongside any route state
|
||||
// Returns string state, prioritizing preview to allow it alongside any route state
|
||||
export const usePanelState = () => {
|
||||
return useStore((s) => ({
|
||||
hasPreview: !!s.selectedPlace,
|
||||
routeState: s.route ? "CALCULATED" : (s.stops.length >= 1 ? "ROUTING" : "NONE")
|
||||
}), shallow)
|
||||
return useStore((s) => {
|
||||
const hasPreview = !!s.selectedPlace
|
||||
const hasRoute = !!s.route
|
||||
const hasStops = s.stops.length >= 1
|
||||
|
||||
if (hasPreview && hasRoute) return "PREVIEW_CALCULATED"
|
||||
if (hasPreview && hasStops) return "PREVIEW_ROUTING"
|
||||
if (hasPreview) return "PREVIEW"
|
||||
if (hasRoute) return "ROUTE_CALCULATED"
|
||||
if (hasStops) return "ROUTING"
|
||||
return "IDLE"
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue