From 6d82ebe127f5ddddff959b8822281c1e1172c866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sat, 11 Apr 2026 02:02:47 +0200 Subject: [PATCH] Store POI metadata (osmId, tags) on waypoints for Journal use When a waypoint is created from or snapped to a POI, the Yjs Y.Map now stores osmId (OSM node ID) and poiTags (phone, website, address, opening hours, etc.). Dragging away clears this data. This persists through the Yjs document and will be available when the route is saved to the Journal, enabling future display of campsite contact details, opening hours, etc. on route detail pages. Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/planner/app/components/PlannerMap.tsx | 13 +++++++++++-- apps/planner/app/lib/poi-snap.ts | 17 ++++++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/apps/planner/app/components/PlannerMap.tsx b/apps/planner/app/components/PlannerMap.tsx index 85e33e6..f79f359 100644 --- a/apps/planner/app/components/PlannerMap.tsx +++ b/apps/planner/app/components/PlannerMap.tsx @@ -363,13 +363,15 @@ export function PlannerMap({ yjs, onRouteRequest, highlightPosition, highlighted const addWaypoint = useCallback( (lat: number, lng: number, name?: string) => { - const snap = name ? { lat, lon: lng, name, snapped: false } : snapToPoi(lat, lng, poiState.pois); + const snap = snapToPoi(lat, lng, poiState.pois); yjs.doc.transact(() => { const yMap = new Y.Map(); yMap.set("lat", snap.lat); yMap.set("lon", snap.snapped ? snap.lon : lng); if (snap.name) yMap.set("name", snap.name); - else if (name) yMap.set("name", name); + else if (name) yMap.set("name", name); // fallback for explicit name + if (snap.osmId) yMap.set("osmId", snap.osmId); + if (snap.poiTags) yMap.set("poiTags", snap.poiTags); yjs.waypoints.push([yMap]); }, "local"); }, @@ -410,6 +412,13 @@ export function PlannerMap({ yjs, onRouteRequest, highlightPosition, highlighted } else { yMap.delete("name"); } + if (snap.osmId) { + yMap.set("osmId", snap.osmId); + if (snap.poiTags) yMap.set("poiTags", snap.poiTags); + } else { + yMap.delete("osmId"); + yMap.delete("poiTags"); + } }, "local"); } }, diff --git a/apps/planner/app/lib/poi-snap.ts b/apps/planner/app/lib/poi-snap.ts index d00424f..c702fe3 100644 --- a/apps/planner/app/lib/poi-snap.ts +++ b/apps/planner/app/lib/poi-snap.ts @@ -2,11 +2,15 @@ import type { Poi } from "./overpass.ts"; const SNAP_DISTANCE_METERS = 50; -interface SnapResult { +export interface SnapResult { lat: number; lon: number; name?: string; snapped: boolean; + /** OSM node ID if snapped */ + osmId?: number; + /** Key POI tags if snapped */ + poiTags?: Record; } /** @@ -28,11 +32,22 @@ export function snapToPoi(lat: number, lon: number, pois: Poi[]): SnapResult { } if (bestPoi && bestDist <= SNAP_DISTANCE_METERS) { + // Pick key tags worth persisting with the waypoint + const keepTags = ["phone", "contact:phone", "website", "opening_hours", + "addr:street", "addr:housenumber", "addr:postcode", "addr:city", + "description", "amenity", "tourism", "shop"]; + const poiTags: Record = {}; + for (const key of keepTags) { + if (bestPoi.tags[key]) poiTags[key] = bestPoi.tags[key]; + } + return { lat: bestPoi.lat, lon: bestPoi.lon, name: bestPoi.name, snapped: true, + osmId: bestPoi.id, + poiTags: Object.keys(poiTags).length > 0 ? poiTags : undefined, }; }