Propagate waypoint notes through session init, save-to-journal, and Journal display

- use-yjs: seed note from initialWaypoints on session open
- api.sessions: include note in initialWaypoints type
- SaveToJournalButton: include note in GPX waypoints on save
- Journal routes.: map and display waypoint notes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ullrich Schäfer 2026-05-18 20:50:52 +02:00
parent 353dcb2c13
commit 02f8a8be44
No known key found for this signature in database
GPG key ID: A32FF691A0F752D9
5 changed files with 14 additions and 6 deletions

View file

@ -35,7 +35,7 @@ export async function action({ params, request }: Route.ActionArgs) {
const session = (await sessionResp.json()) as { const session = (await sessionResp.json()) as {
url: string; url: string;
initialWaypoints?: Array<{ lat: number; lon: number; name?: string }>; initialWaypoints?: Array<{ lat: number; lon: number; name?: string; isDayBreak?: boolean; note?: string; osmId?: number; poiTags?: Record<string, string> }>;
initialNoGoAreas?: Array<{ points: Array<{ lat: number; lon: number }> }>; initialNoGoAreas?: Array<{ points: Array<{ lat: number; lon: number }> }>;
initialNotes?: string; initialNotes?: string;
}; };

View file

@ -32,7 +32,7 @@ export async function loader({ params, request }: Route.LoaderArgs) {
// Parse GPX once for day stats and waypoint POI data // Parse GPX once for day stats and waypoint POI data
let dayStats: Array<{ dayNumber: number; startName?: string; endName?: string; distance: number; ascent: number; descent: number }> = []; let dayStats: Array<{ dayNumber: number; startName?: string; endName?: string; distance: number; ascent: number; descent: number }> = [];
let waypoints: Array<{ lat: number; lon: number; name?: string; isDayBreak?: boolean; osmId?: number; poiTags?: Record<string, string> }> = []; let waypoints: Array<{ lat: number; lon: number; name?: string; isDayBreak?: boolean; note?: string; osmId?: number; poiTags?: Record<string, string> }> = [];
if (route.gpx) { if (route.gpx) {
try { try {
const { computeDays, parseGpxAsync } = await import("@trails-cool/gpx"); const { computeDays, parseGpxAsync } = await import("@trails-cool/gpx");
@ -42,6 +42,7 @@ export async function loader({ params, request }: Route.LoaderArgs) {
lon: w.lon, lon: w.lon,
name: w.name, name: w.name,
isDayBreak: w.isDayBreak, isDayBreak: w.isDayBreak,
note: w.note,
osmId: w.osmId, osmId: w.osmId,
poiTags: w.poiTags as Record<string, string> | undefined, poiTags: w.poiTags as Record<string, string> | undefined,
})); }));
@ -398,15 +399,18 @@ export default function RouteDetailPage({ loaderData }: Route.ComponentProps) {
</div> </div>
)} )}
{waypoints.some((w) => w.osmId || w.poiTags) && ( {waypoints.some((w) => w.osmId || w.poiTags || w.note) && (
<div className="mt-6"> <div className="mt-6">
<h2 className="text-lg font-semibold text-gray-900">{t("routes.waypoints")}</h2> <h2 className="text-lg font-semibold text-gray-900">{t("routes.waypoints")}</h2>
<ul className="mt-3 divide-y divide-gray-200 rounded-md border border-gray-200"> <ul className="mt-3 divide-y divide-gray-200 rounded-md border border-gray-200">
{waypoints.filter((w) => w.osmId || w.poiTags || w.name).map((w, i) => ( {waypoints.filter((w) => w.osmId || w.poiTags || w.note || w.name).map((w, i) => (
<li key={i} className="px-4 py-3"> <li key={i} className="px-4 py-3">
<p className="font-medium text-gray-900"> <p className="font-medium text-gray-900">
{w.name ?? `${w.lat.toFixed(5)}, ${w.lon.toFixed(5)}`} {w.name ?? `${w.lat.toFixed(5)}, ${w.lon.toFixed(5)}`}
</p> </p>
{w.note && (
<p className="mt-1 whitespace-pre-wrap text-sm text-gray-600">{w.note}</p>
)}
{w.poiTags && ( {w.poiTags && (
<dl className="mt-1 space-y-0.5 text-sm text-gray-600"> <dl className="mt-1 space-y-0.5 text-sm text-gray-600">
{w.poiTags.phone && ( {w.poiTags.phone && (

View file

@ -47,6 +47,7 @@ export function SaveToJournalButton({ yjs, callbackUrl, callbackToken, returnUrl
lon: yMap.get("lon") as number, lon: yMap.get("lon") as number,
name: yMap.get("name") as string | undefined, name: yMap.get("name") as string | undefined,
isDayBreak: yMap.get("overnight") === true ? true : undefined, isDayBreak: yMap.get("overnight") === true ? true : undefined,
note: yMap.get("note") as string | undefined,
osmId: yMap.get("osmId") as number | undefined, osmId: yMap.get("osmId") as number | undefined,
poiTags: yMap.get("poiTags") as WaypointPoiTags | undefined, poiTags: yMap.get("poiTags") as WaypointPoiTags | undefined,
})); }));

View file

@ -42,7 +42,7 @@ export interface YjsState {
export function useYjs( export function useYjs(
sessionId: string, sessionId: string,
initialWaypoints?: Array<{ lat: number; lon: number; name?: string; isDayBreak?: boolean }>, initialWaypoints?: Array<{ lat: number; lon: number; name?: string; isDayBreak?: boolean; note?: string; osmId?: number; poiTags?: Record<string, string> }>,
initialNoGoAreas?: Array<{ points: Array<{ lat: number; lon: number }> }>, initialNoGoAreas?: Array<{ points: Array<{ lat: number; lon: number }> }>,
initialNotes?: string, initialNotes?: string,
): YjsState | null { ): YjsState | null {
@ -108,6 +108,9 @@ export function useYjs(
yMap.set("lon", wp.lon); yMap.set("lon", wp.lon);
if (wp.name) yMap.set("name", wp.name); if (wp.name) yMap.set("name", wp.name);
if (wp.isDayBreak) yMap.set("overnight", true); if (wp.isDayBreak) yMap.set("overnight", true);
if (wp.note) yMap.set("note", wp.note);
if (wp.osmId !== undefined) yMap.set("osmId", wp.osmId);
if (wp.poiTags) yMap.set("poiTags", wp.poiTags);
waypoints.push([yMap]); waypoints.push([yMap]);
} }
if (initialNoGoAreas?.length && noGoAreas.length === 0) { if (initialNoGoAreas?.length && noGoAreas.length === 0) {

View file

@ -19,7 +19,7 @@ export async function action({ request }: Route.ActionArgs) {
return withDb(async () => { return withDb(async () => {
const session = await createSession({ callbackUrl, callbackToken }); const session = await createSession({ callbackUrl, callbackToken });
let initialWaypoints: Array<{ lat: number; lon: number; name?: string; isDayBreak?: boolean }> | undefined; let initialWaypoints: Array<{ lat: number; lon: number; name?: string; isDayBreak?: boolean; note?: string; osmId?: number; poiTags?: Record<string, string> }> | undefined;
let initialNoGoAreas: Array<{ points: Array<{ lat: number; lon: number }> }> | undefined; let initialNoGoAreas: Array<{ points: Array<{ lat: number; lon: number }> }> | undefined;
let initialNotes: string | undefined; let initialNotes: string | undefined;
if (gpx) { if (gpx) {