The routeData Y.Map's ~15 string keys (geojson, coordinates, segmentBoundaries, road metadata, profile, colorMode, baseLayer, overlays, poiCategories) were read and written raw at ~30 call sites, each with its own JSON parsing and casts; parseJsonArray existed twice and waypoint extraction four times. GPX assembly was duplicated between SaveToJournalButton and ExportButton, so the saved plan and the exported file could silently diverge. - new lib/route-data.ts owns the routeData (+ noGoAreas) schema: typed read/write, JSON encoding internal, ColorMode moves here (re-exported from ColoredRoute for existing importers) - new lib/gpx-export.ts owns GPX assembly: buildRouteGpx / buildPlanGpx / buildDayGpxFiles / hasDayBreaks; multi-day splitting becomes a pure, tested function - waypoint-ymap.ts gains extractWaypoints / extractWaypointData; the four hand-rolled copies (use-routing, use-waypoint-manager, WaypointSidebar, use-days) now share it, and WaypointSidebar's moveWaypoint reuses the round-trip helpers instead of re-listing every waypoint field - all hooks/components consume the seam; no raw routeData key strings remain outside route-data.ts Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
53 lines
1.4 KiB
TypeScript
53 lines
1.4 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
import { computeDays, type DayStage } from "@trails-cool/gpx";
|
|
import type { TrackPoint } from "@trails-cool/gpx";
|
|
import type { YjsState } from "./use-yjs.ts";
|
|
import { extractWaypoints } from "./waypoint-ymap.ts";
|
|
import { getCoordinates } from "./route-data.ts";
|
|
|
|
/**
|
|
* Reactive hook that computes day stages from Yjs waypoints and route data.
|
|
* Returns an empty array for single-day routes (no overnight waypoints).
|
|
*/
|
|
export function useDays(yjs: YjsState | null): DayStage[] {
|
|
const [days, setDays] = useState<DayStage[]>([]);
|
|
|
|
useEffect(() => {
|
|
if (!yjs) return;
|
|
|
|
const recompute = () => {
|
|
const waypoints = extractWaypoints(yjs.waypoints);
|
|
|
|
// Check if any waypoint has isDayBreak
|
|
const hasBreaks = waypoints.some((w) => w.isDayBreak);
|
|
if (!hasBreaks) {
|
|
setDays([]);
|
|
return;
|
|
}
|
|
|
|
const coords = getCoordinates(yjs.routeData);
|
|
if (!coords) {
|
|
setDays([]);
|
|
return;
|
|
}
|
|
|
|
const trackPoints: TrackPoint[] = coords.map((c) => ({
|
|
lat: c[1],
|
|
lon: c[0],
|
|
ele: c[2],
|
|
}));
|
|
setDays(computeDays(waypoints, [trackPoints]));
|
|
};
|
|
|
|
yjs.waypoints.observeDeep(recompute);
|
|
yjs.routeData.observe(recompute);
|
|
recompute();
|
|
|
|
return () => {
|
|
yjs.waypoints.unobserveDeep(recompute);
|
|
yjs.routeData.unobserve(recompute);
|
|
};
|
|
}, [yjs]);
|
|
|
|
return days;
|
|
}
|