Add per-waypoint notes and nearby POI snap to Planner
- `note` field on Waypoint type, stored in Yjs Y.Map and exported as `<desc>` inside `<wpt>` in GPX - Inline textarea note editing in WaypointSidebar with auto-resize, character counter (500 max), save-on-blur, Escape cancel - Note indicator dot on map markers; note tooltip on hover - `useNearbyPois` hook: fetches POIs within 500m of selected waypoint via Overpass proxy, 500ms debounce, AbortController, 60s rate-limit suppression - NearbyPoiMarkers component: renders POI markers on map for selected waypoint with snap-to-POI on click - Nearby section in WaypointSidebar: list with snap buttons, spinner, empty/rate-limited states, "Show more" toggle (5 → all) - Unit tests for fetchNearbyPois bbox geometry and snap-to-POI Yjs transaction behaviour Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
bcf551cd27
commit
c2abb64ee0
16 changed files with 665 additions and 58 deletions
|
|
@ -1,64 +1,65 @@
|
|||
## 1. Data Model
|
||||
|
||||
- [ ] 1.1 Add optional `note?: string` field to `Waypoint` interface in `packages/types/src/index.ts`
|
||||
- [ ] 1.2 Update `WaypointData` interface and `getWaypointsFromYjs` in `apps/planner/app/components/WaypointSidebar.tsx` to read `note` from Y.Map
|
||||
- [ ] 1.3 Update `moveWaypoint` in WaypointSidebar to preserve the `note` field when reconstructing the Y.Map
|
||||
- [x] 1.1 Add optional `note?: string` field to `Waypoint` interface in `packages/types/src/index.ts`
|
||||
- [x] 1.2 Read `note` from Y.Map in `WaypointSidebar.tsx` (add to `WaypointData` interface and the mapping loop)
|
||||
- [x] 1.3 Preserve `note` when reconstructing the Y.Map in `moveWaypoint` (WaypointSidebar)
|
||||
|
||||
## 2. Sidebar Note Display
|
||||
|
||||
- [ ] 2.1 Add note display below waypoint name in sidebar list item (italic, muted text, truncated to 2 lines)
|
||||
- [ ] 2.2 Show "Add a note..." placeholder when note is empty (i18n key: `planner.waypoint.notePlaceholder`)
|
||||
- [ ] 2.3 Add inline `<textarea>` editing: click to edit, auto-focus, auto-resize, save on blur, cancel on Escape
|
||||
- [ ] 2.4 Add character counter (e.g., "127 / 500") visible during editing
|
||||
- [x] 2.1 Add note display below waypoint name in sidebar list item (italic, muted text, truncated to 2 lines)
|
||||
- [x] 2.2 Show "Add a note..." placeholder when note is empty (i18n key: `planner.waypoint.notePlaceholder`)
|
||||
- [x] 2.3 Add inline `<textarea>` editing: click to edit, auto-focus, auto-resize, save on blur, cancel on Escape
|
||||
- [x] 2.4 Add character counter (e.g., "127 / 500") visible during editing
|
||||
|
||||
## 3. Map Markers
|
||||
|
||||
- [ ] 3.1 Add note indicator icon on waypoint markers that have a non-empty note
|
||||
- [ ] 3.2 Show note text in Leaflet tooltip on hover/tap for markers with notes
|
||||
- [x] 3.1 Add note indicator icon on waypoint markers that have a non-empty note
|
||||
- [x] 3.2 Show note text in Leaflet tooltip on hover/tap for markers with notes
|
||||
|
||||
## 4. GPX Export & Import
|
||||
|
||||
- [ ] 4.1 Update `generateGpx` in `packages/gpx/src/generate.ts` to emit `<desc>` element when waypoint has a note
|
||||
- [ ] 4.2 Update `parseGpx` in `packages/gpx/src/parse.ts` to read `<desc>` into waypoint `note` field
|
||||
- [x] 4.1 Emit `<desc>` on `<wpt>` in `generateGpx` when waypoint has a note (note: route-level `<desc>` already exists in `<metadata>`, this is per-waypoint)
|
||||
- [x] 4.2 Read `<desc>` inside `<wpt>` into waypoint `note` field in `parseWaypoints` (note: `metadata > desc` is already parsed separately)
|
||||
|
||||
## 5. i18n
|
||||
|
||||
- [ ] 5.1 Add translation keys for note UI strings (en + de): placeholder, character counter label, tooltip "more" link
|
||||
- [ ] 5.2 Add translation keys for POI types, snap action labels, and POI status messages (en + de)
|
||||
- [x] 5.1 Add translation keys for note UI strings (en + de): `planner.waypoint.notePlaceholder`, character counter label, Escape cancel hint
|
||||
- [x] 5.2 Add translation keys for POI snap action labels and nearby POI status messages (en + de) — POI type labels already exist in `@trails-cool/map-core`
|
||||
|
||||
## 6. Testing (Notes)
|
||||
|
||||
- [ ] 6.1 Unit tests: GPX generation with notes (`<desc>` output), GPX parsing with `<desc>`, character counter logic
|
||||
- [ ] 6.2 E2E test: add a waypoint, type a note in sidebar, verify note persists after page interaction, verify GPX export contains note
|
||||
- [x] 6.1 Unit tests: per-waypoint `<desc>` in GPX generation; `<desc>` inside `<wpt>` parsed into `note`; verify no collision with `metadata > desc`
|
||||
- [ ] 6.2 E2E test: type a note in sidebar, blur, verify note persists; verify GPX export contains `<desc>` inside `<wpt>`
|
||||
|
||||
## 7. POI Data Layer
|
||||
## 7. POI Data Layer (per-waypoint)
|
||||
|
||||
- [ ] 7.1 Create Overpass API client in `apps/planner/app/lib/overpass.ts`: `fetchNearbyPOIs(lat, lon, radius)` function that builds an Overpass QL query, fetches from `https://overpass-api.de/api/interpreter`, and parses the JSON response into a typed `POI[]` array
|
||||
- [ ] 7.2 Define `POI` interface and `POI_TYPES` constant: category (water, shelter, camping, food, viewpoint, bicycle), OSM tag mapping, icon, i18n label key. Place in `apps/planner/app/lib/poi-types.ts`
|
||||
- [ ] 7.3 Build Overpass query per routing profile: filter `POI_TYPES` by the active profile (e.g., bicycle categories only for trekking/fastbike profiles) and generate the corresponding Overpass QL
|
||||
- [ ] 7.4 Implement POI cache in `apps/planner/app/lib/poi-cache.ts`: `Map<string, { data: POI[]; timestamp: number }>` keyed by quantized bounding box tile, 1-hour TTL, max 50 entries, expired-on-access eviction
|
||||
- [x] 7.1 Overpass client (`overpass.ts`), proxy endpoint, `buildQuery`, `parseResponse` — already shipped
|
||||
- [x] 7.2 `Poi` interface and category definitions — in `overpass.ts` + `@trails-cool/map-core`
|
||||
- [x] 7.3 Overpass query building per routing profile — already in `buildQuery`
|
||||
- [x] 7.4 POI cache (`poi-cache.ts`) with quantized bbox, TTL, eviction — already shipped
|
||||
- [x] 7.5 Add `fetchNearbyPois(lat, lon, radiusMeters, categories)` to `overpass.ts`: constructs a ~500m bbox from a single coordinate and reuses `buildQuery` + the existing `/api/overpass` proxy
|
||||
|
||||
## 8. POI Map Display
|
||||
|
||||
- [ ] 8.1 Add `selectedWaypointIndex` state to PlannerMap (set when a waypoint marker is clicked or selected in sidebar)
|
||||
- [ ] 8.2 Create `POIMarkers` component: receives `POI[]` and renders small circle markers colored by category, with tooltip showing POI name and type
|
||||
- [ ] 8.3 Add click handler on POI markers to trigger snap (calls snap handler that updates waypoint Y.Map in a single transaction)
|
||||
- [x] 8.1 Add `selectedWaypointIndex` state lifted to `SessionView` (or passed via callback from `WaypointSidebar` → `PlannerMap`)
|
||||
- [x] 8.2 Create `NearbyPoiMarkers` component: receives `Poi[]` for the selected waypoint + renders small circle markers by category with name tooltip — distinct from the overlay `PoiLayer` markers
|
||||
- [x] 8.3 Wire click on `NearbyPoiMarkers` to call snap handler
|
||||
|
||||
## 9. POI Sidebar
|
||||
|
||||
- [ ] 9.1 Add "Nearby" section below note area in WaypointSidebar for the selected waypoint: grouped by category, sorted by distance, max 15 items with "Show more" toggle
|
||||
- [ ] 9.2 Add snap button per POI item: clicking snaps waypoint to POI coordinates, sets name, prepends note prefix (icon + type label), all in one Yjs transaction
|
||||
- [ ] 9.3 Show POI loading state (spinner) and empty state ("No nearby POIs found") with appropriate i18n strings
|
||||
- [x] 9.1 Add "Nearby" section in `WaypointSidebar` for the selected waypoint: call `fetchNearbyPois`, show spinner / empty state, list POIs sorted by distance (max 15, "Show more" toggle)
|
||||
- [x] 9.2 Snap button per POI: move waypoint coords, set name from POI (if waypoint unnamed), prepend `"<icon> <type>"` to note — all in one Yjs transaction via `use-waypoint-manager`
|
||||
- [x] 9.3 Debounce POI fetch 500ms after waypoint selection; cancel in-flight fetch via `AbortController` when selection changes
|
||||
|
||||
## 10. POI Rate Limiting & Error Handling
|
||||
|
||||
- [ ] 10.1 Implement debounce (500ms) on waypoint selection before triggering Overpass query; abort in-flight requests via `AbortController` when selection changes
|
||||
- [ ] 10.2 Handle HTTP 429 from Overpass: disable POI queries for 60 seconds, show subtle "POI lookup unavailable" message
|
||||
- [ ] 10.3 Handle network errors and timeouts (10s) gracefully: fail silently, show empty POI list, no error modals
|
||||
- [x] 10.1 Handle HTTP 429 from nearby-POI fetch: suppress for 60s, show subtle "POI lookup unavailable" notice in the Nearby section
|
||||
- [x] 10.2 Handle network errors and 10s timeout: fail silently, show empty Nearby list — no error modals
|
||||
|
||||
## 11. Testing (POI)
|
||||
|
||||
- [ ] 11.1 Unit tests for Overpass client: query construction, response parsing, error handling (mock `fetch`)
|
||||
- [ ] 11.2 Unit tests for POI cache: cache hit, cache miss, TTL expiry, eviction at max entries
|
||||
- [ ] 11.3 Unit tests for snap behavior: waypoint coordinates updated, name set from POI, note prefix prepended, existing note preserved
|
||||
- [ ] 11.4 E2E test: select a waypoint, verify POI list appears in sidebar (mock Overpass response), click snap, verify waypoint moved and note updated
|
||||
- [x] 11.1 Overpass client unit tests (query construction, response parsing) — `overpass.test.ts` already covers this
|
||||
- [x] 11.2 POI cache unit tests — `poi-cache.test.ts` already covers this
|
||||
- [x] 11.3 Unit tests for `fetchNearbyPois`: correct bbox from lat/lon/radius, category filtering
|
||||
- [x] 11.4 Unit tests for snap: coords updated, name set, note prefix prepended, existing note preserved, all in one Yjs transaction
|
||||
- [ ] 11.5 E2E test: mock Overpass via route handler, select a waypoint, verify Nearby list appears, click snap, verify waypoint moved and note prefixed
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue