From 267c2fb8b725916e92132ae6c5f989f9cae12cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Thu, 16 Jul 2026 23:37:31 +0200 Subject: [PATCH] fix(planner): nearby-POI lookup sends the real session (was 401) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fetchNearbyPois defaulted sessionId to the placeholder "nearby", which /api/pois's requireSession rejects (401 Unauthorized) — so the nearby-POI lookup for a selected waypoint always failed on real deployments. Thread the live planner sessionId through useNearbyPois → fetchNearbyPois → queryPois (same session the main POI markers already use), and make sessionId a required arg so the placeholder can't silently return. Co-Authored-By: Claude Opus 4.8 --- apps/planner/app/components/PlannerMap.tsx | 2 +- apps/planner/app/components/SessionView.tsx | 6 +++--- apps/planner/app/components/WaypointSidebar.tsx | 5 +++-- apps/planner/app/lib/pois.test.ts | 4 ++-- apps/planner/app/lib/pois.ts | 2 +- apps/planner/app/lib/use-nearby-pois.ts | 5 +++-- 6 files changed, 13 insertions(+), 11 deletions(-) diff --git a/apps/planner/app/components/PlannerMap.tsx b/apps/planner/app/components/PlannerMap.tsx index cffe5d4..bef0afe 100644 --- a/apps/planner/app/components/PlannerMap.tsx +++ b/apps/planner/app/components/PlannerMap.tsx @@ -185,7 +185,7 @@ export function PlannerMap({ yjs, sessionId, onRouteRequest, highlightPosition, const { draggingOver, handleDragEnter, handleDragLeave, handleDragOver, handleDrop } = useGpxDrop(yjs, onImportError); const selectedWp = selectedWaypointIndex != null ? waypoints[selectedWaypointIndex] : undefined; - const nearbyPoisState = useNearbyPois(selectedWp?.lat, selectedWp?.lon); + const nearbyPoisState = useNearbyPois(selectedWp?.lat, selectedWp?.lon, sessionId); const handleSnapToPoi = useCallback((poi: Poi) => { if (selectedWaypointIndex == null) return; diff --git a/apps/planner/app/components/SessionView.tsx b/apps/planner/app/components/SessionView.tsx index 15de670..87f65ce 100644 --- a/apps/planner/app/components/SessionView.tsx +++ b/apps/planner/app/components/SessionView.tsx @@ -114,7 +114,7 @@ function useAwarenessToasts(yjs: YjsState | null, t: TFunction, addToast: (messa } -function SidebarTabs({ yjs, routeStats, days, onWaypointHover, onWaypointSelect }: { yjs: YjsState; routeStats: ReturnType["routeStats"]; days: ReturnType; onWaypointHover: (index: number | null) => void; onWaypointSelect: (index: number | null) => void }) { +function SidebarTabs({ yjs, sessionId, routeStats, days, onWaypointHover, onWaypointSelect }: { yjs: YjsState; sessionId: string; routeStats: ReturnType["routeStats"]; days: ReturnType; onWaypointHover: (index: number | null) => void; onWaypointSelect: (index: number | null) => void }) { const { t } = useTranslation("planner"); const [tab, setTab] = useState<"waypoints" | "notes">("waypoints"); @@ -137,7 +137,7 @@ function SidebarTabs({ yjs, routeStats, days, onWaypointHover, onWaypointSelect
{tab === "waypoints" ? ( - + ) : ( @@ -292,7 +292,7 @@ export function SessionView({ sessionId, hasJournalCallback, returnUrl, initialW
- + {toasts.length > 0 && ( diff --git a/apps/planner/app/components/WaypointSidebar.tsx b/apps/planner/app/components/WaypointSidebar.tsx index d78acd0..a78cda3 100644 --- a/apps/planner/app/components/WaypointSidebar.tsx +++ b/apps/planner/app/components/WaypointSidebar.tsx @@ -19,6 +19,7 @@ const NOTE_MAX = 500; interface WaypointSidebarProps { yjs: YjsState; + sessionId: string; routeStats?: { distance?: number; elevationGain?: number; @@ -29,7 +30,7 @@ interface WaypointSidebarProps { onWaypointSelect?: (index: number | null) => void; } -export function WaypointSidebar({ yjs, routeStats, days, onWaypointHover, onWaypointSelect }: WaypointSidebarProps) { +export function WaypointSidebar({ yjs, sessionId, routeStats, days, onWaypointHover, onWaypointSelect }: WaypointSidebarProps) { const { t } = useTranslation("planner"); const [waypoints, setWaypoints] = useState([]); const [selectedIndex, setSelectedIndex] = useState(null); @@ -133,7 +134,7 @@ export function WaypointSidebar({ yjs, routeStats, days, onWaypointHover, onWayp ); const selectedWp = selectedIndex !== null ? waypoints[selectedIndex] : undefined; - const nearbyPoisState = useNearbyPois(selectedWp?.lat, selectedWp?.lon); + const nearbyPoisState = useNearbyPois(selectedWp?.lat, selectedWp?.lon, sessionId); const [showAllNearby, setShowAllNearby] = useState(false); const hasMultipleDays = days.length > 1; diff --git a/apps/planner/app/lib/pois.test.ts b/apps/planner/app/lib/pois.test.ts index cba7905..826fe3a 100644 --- a/apps/planner/app/lib/pois.test.ts +++ b/apps/planner/app/lib/pois.test.ts @@ -144,7 +144,7 @@ describe("fetchNearbyPois", () => { afterEach(() => vi.unstubAllGlobals()); it("builds a bbox around the point and calls /api/pois", async () => { - await fetchNearbyPois(50.0, 10.0, 500, drinkingWater); + await fetchNearbyPois(50.0, 10.0, 500, drinkingWater, "sess"); expect(fetch).toHaveBeenCalledOnce(); const [url] = (fetch as ReturnType).mock.calls[0] as [string]; expect(url).toMatch(/\/api\/pois\?bbox=\d+\.\d+,\d+\.\d+,\d+\.\d+,\d+\.\d+/); @@ -153,7 +153,7 @@ describe("fetchNearbyPois", () => { it("forwards the AbortSignal to fetch", async () => { const controller = new AbortController(); - await fetchNearbyPois(50.0, 10.0, 500, drinkingWater, controller.signal); + await fetchNearbyPois(50.0, 10.0, 500, drinkingWater, "sess", controller.signal); const [, opts] = (fetch as ReturnType).mock.calls[0] as [string, RequestInit]; expect(opts.signal).toBe(controller.signal); }); diff --git a/apps/planner/app/lib/pois.ts b/apps/planner/app/lib/pois.ts index 01898e8..d69cf39 100644 --- a/apps/planner/app/lib/pois.ts +++ b/apps/planner/app/lib/pois.ts @@ -133,8 +133,8 @@ export async function fetchNearbyPois( lon: number, radiusMeters: number, categories: PoiCategory[], + sessionId: string, signal?: AbortSignal, - sessionId = "nearby", ): Promise { const dLat = radiusMeters * DEG_PER_METER_LAT; const dLon = dLat / Math.cos((lat * Math.PI) / 180); diff --git a/apps/planner/app/lib/use-nearby-pois.ts b/apps/planner/app/lib/use-nearby-pois.ts index 0b08ed8..7347aea 100644 --- a/apps/planner/app/lib/use-nearby-pois.ts +++ b/apps/planner/app/lib/use-nearby-pois.ts @@ -19,6 +19,7 @@ const rateLimitedUntilRef = { current: 0 }; export function useNearbyPois( lat: number | undefined, lon: number | undefined, + sessionId: string, ): NearbyPoisState { const [state, setState] = useState({ pois: [], status: "idle" }); const abortRef = useRef(null); @@ -47,7 +48,7 @@ export function useNearbyPois( setState((prev) => ({ ...prev, status: "loading" })); try { - const pois = await fetchNearbyPois(lat, lon, NEARBY_RADIUS_METERS, poiCategories, controller.signal); + const pois = await fetchNearbyPois(lat, lon, NEARBY_RADIUS_METERS, poiCategories, sessionId, controller.signal); if (!controller.signal.aborted) { setState({ pois, status: "done" }); } @@ -68,7 +69,7 @@ export function useNearbyPois( if (timerRef.current) clearTimeout(timerRef.current); abortRef.current?.abort(); }; - }, [lat, lon]); + }, [lat, lon, sessionId]); return state; }