28c25c32ab
- Wire `api/geocode` and `api/bike-route` to use `GeocodingClient` and `BikeRoutingClient` instead of raw fetch calls - Move `parseHafasJourneys` from `useJourneys` to `hafas-client` - Remove dead code `src/lib/live-status-utils.ts` - Update test setup to import `@testing-library/jest-dom/vitest`
87 lines
4.3 KiB
Markdown
87 lines
4.3 KiB
Markdown
# TimeToLeave — Implementation Checklist
|
||
|
||
> **Source:** [REWRITE_PLAN.md](./REWRITE_PLAN.md)
|
||
> **Total:** 4 phases, 14 steps, ~5 hours estimated effort
|
||
|
||
---
|
||
|
||
## Phase 1 — Unblock Runtime (~45 min)
|
||
|
||
Fix bugs that crash the app or lose user data.
|
||
|
||
| Step | ✅ Implemented | ✔️ Reviewed | Notes |
|
||
|------|:--------------:|:-----------:|-------|
|
||
| **Step 1: Fix SSR Crash in `useBikeRoute`** (~10 min) | [x] | [x] | Relative URL fetch replaces `window.location.href` — SSR-safe. `isMounted` guard intact. |
|
||
| **Step 2: Wire Calendar Events into `EventsStore`** (~15 min) | [x] | [x] | `CalendarPanel.tsx` merges via `useEffect` when calendar events arrive. `mergeEvents()` converts `CalendarEvent` (string `eventTime`) → `Event` (Date `eventTime`). Bonus: localStorage persistence with rehydration. |
|
||
| **Step 3: Add Input Validation to `/api/hafas`** (~20 min) | [x] | [x] | Validates `svcReqL` array shape, method allowlist (TripSearch/LocMatch), caps `numF` at 10. Extra type guard on `svcReq.meth` (`typeof svcReq.meth !== 'string'`) exceeds spec. |
|
||
|
||
---
|
||
|
||
## Phase 2 — Deduplicate Code (~2 hours)
|
||
|
||
Eliminate duplicated logic so each integration has one source of truth.
|
||
|
||
- [x] **Step 4: Consolidate HAFAS Journey Parsing** (~40 min)
|
||
- Move `parseHafasJourneys` from `useJourneys.ts` into `hafas-client.ts` and export it; import from `useJourneys.ts` (Option A — minimal risk)
|
||
- Files: `src/lib/hafas-client.ts`, `src/hooks/useJourneys.ts`
|
||
|
||
- [x] **Step 5: Wire API Routes to Use Library Clients** (~30 min)
|
||
- Replace raw `fetch()` in `api/geocode/route.ts` with `GeocodingClient`, and in `api/bike-route/route.ts` with `BikeRoutingClient` (module-level singleton, proper error handling)
|
||
- Files: `src/app/api/geocode/route.ts`, `src/app/api/bike-route/route.ts`
|
||
|
||
- [x] **Step 6: Remove Dead Code** (~5 min)
|
||
- Delete `src/lib/live-status-utils.ts` entirely; remove its export from `src/lib/index.ts`
|
||
- File: `src/lib/live-status-utils.ts`, `src/lib/index.ts`
|
||
|
||
- [x] **Step 7: Create Missing Test Setup File** (~10 min)
|
||
- Create `src/test/setup.ts` with `import "@testing-library/jest-dom/vitest"` so jsdom matchers are registered globally
|
||
- File: `src/test/setup.ts`
|
||
|
||
---
|
||
|
||
## Phase 3 — Performance & UX (~1.5 hours)
|
||
|
||
- [ ] **Step 8: Add Debounce to Lookup Hooks** (~25 min)
|
||
- Wrap fetch in a 400 ms `setTimeout` with `AbortController` cleanup in `useGeocode.ts` and `useDestinationStation.ts` to prevent per-keystroke API calls
|
||
- Files: `src/hooks/useGeocode.ts`, `src/hooks/useDestinationStation.ts`
|
||
|
||
- [ ] **Step 9: Pre-Group Calendar Events by Date** (~20 min)
|
||
- Build a `Map<string, Event[]>` keyed by `YYYY-MM-DD` via `useMemo` in `CalendarView.tsx`; replace per-cell `filter()` with O(1) map lookup
|
||
- File: `src/app/calendar/CalendarView.tsx`
|
||
|
||
- [ ] **Step 10: Add Dark Mode Toggle** (~20 min)
|
||
- Create `useTheme.ts` hook (persist to `localStorage`, respect `prefers-color-scheme`); add sun/moon toggle button to `Header.tsx`
|
||
- Files: `src/hooks/useTheme.ts` (new), `src/app/layout/Header.tsx`
|
||
|
||
- [ ] **Step 11: Fix Bike Route Steps** (~5 min)
|
||
- Add `steps: "true"` to the query params in `BikeRoutingClient.getBikeRoute()` so OSRM returns turn-by-turn steps
|
||
- File: `src/lib/bike-routing-client.ts`
|
||
|
||
---
|
||
|
||
## Phase 4 — Monitoring & Testing (~1 hour)
|
||
|
||
- [ ] **Step 12: Add Correlation IDs to API Errors** (~15 min)
|
||
- Generate a short UUID (`randomUUID().slice(0, 8)`) in each API route's catch block; log it server-side and include it in the JSON error response
|
||
- Files: all `src/app/api/*/route.ts`
|
||
|
||
- [ ] **Step 13: Add Hook Tests** (~30 min)
|
||
- Create `useJourneys.test.ts` and `useBikeRoute.test.ts` — mock `global.fetch`, test state transitions (loading → success, loading → error)
|
||
- Files: `src/hooks/__tests__/useJourneys.test.ts`, `src/hooks/__tests__/useBikeRoute.test.ts`
|
||
|
||
- [ ] **Step 14: Add Component Tests** (~15 min)
|
||
- Create `EventCard.test.tsx` and `CalendarView.test.tsx` — render with mock data, verify key elements are in the document
|
||
- Files: `src/app/event/__tests__/EventCard.test.tsx`, `src/app/calendar/__tests__/CalendarView.test.tsx`
|
||
|
||
---
|
||
|
||
## Summary
|
||
|
||
| Phase | Steps | Est. Time |
|
||
|-------|-------|-----------|
|
||
| 1 — Unblock Runtime | 1–3 | ~45 min |
|
||
| 2 — Deduplicate Code | 4–7 | ~2 hours |
|
||
| 3 — Performance & UX | 8–11 | ~1.5 hours |
|
||
| 4 — Monitoring & Testing | 12–14 | ~1 hour |
|
||
| **Total** | **14** | **~5 hours** |
|