Show POI details (phone, website, opening hours) on Journal route detail page

Waypoints snapped to OSM POIs in the Planner now carry their metadata all
the way through to the Journal:

- Extend Waypoint type with osmId and poiTags fields
- Extract osmId/poiTags from Yjs Y.Map in ExportButton and SaveToJournalButton
- Encode POI metadata as <trails:poi> extensions in GPX <wpt> elements
- Parse <trails:poi> extensions back in the GPX parser
- Display phone, website, opening hours, address on Journal route detail
- E2E test for the full roundtrip; seed endpoint now defaults to public visibility

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ullrich Schäfer 2026-05-17 23:32:38 +02:00
parent f1a314a70d
commit 861701e881
No known key found for this signature in database
GPG key ID: A32FF691A0F752D9
13 changed files with 341 additions and 9 deletions

View file

@ -4,6 +4,7 @@ import * as Y from "yjs";
import type { YjsState } from "~/lib/use-yjs";
import { generateGpx, computeDays } from "@trails-cool/gpx";
import type { TrackPoint, NoGoArea } from "@trails-cool/gpx";
import type { WaypointPoiTags } from "@trails-cool/types";
function getTracks(yjs: YjsState): TrackPoint[][] {
const geojsonStr = yjs.routeData.get("geojson") as string | undefined;
@ -24,6 +25,8 @@ function getWaypoints(yjs: YjsState) {
lon: yMap.get("lon") as number,
name: yMap.get("name") as string | undefined,
isDayBreak: yMap.get("overnight") === true ? true : undefined,
osmId: yMap.get("osmId") as number | undefined,
poiTags: yMap.get("poiTags") as WaypointPoiTags | undefined,
}));
}

View file

@ -4,6 +4,7 @@ import * as Y from "yjs";
import type { YjsState } from "~/lib/use-yjs";
import { generateGpx } from "@trails-cool/gpx";
import type { TrackPoint, NoGoArea } from "@trails-cool/gpx";
import type { WaypointPoiTags } from "@trails-cool/types";
interface SaveToJournalButtonProps {
yjs: YjsState;
@ -46,6 +47,8 @@ export function SaveToJournalButton({ yjs, callbackUrl, callbackToken, returnUrl
lon: yMap.get("lon") as number,
name: yMap.get("name") as string | undefined,
isDayBreak: yMap.get("overnight") === true ? true : undefined,
osmId: yMap.get("osmId") as number | undefined,
poiTags: yMap.get("poiTags") as WaypointPoiTags | undefined,
}));
const notes = yjs.notes.toString() || undefined;