Mechanical reformat — no logic changes. 398 files changed, 19125 insertions(+), 16457 deletions(-). Prettier 3.8.4 with .prettierrc (singleQuote:true, semi:true, tabWidth:2, trailingComma:all, printWidth:100). Isolated per D-13-08 for reviewability.
8.3 KiB
phase, plan, subsystem, tags, dependency_graph, tech_stack, key_files, decisions, metrics
| phase | plan | subsystem | tags | dependency_graph | tech_stack | key_files | decisions | metrics | |||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 03-event-write-back-pwa-install | 12 | pwa/EventForm |
|
|
|
|
|
|
Phase 03 Plan 12: EventForm Gap Closure — Edit Mode, Focus Trap, PWA Assets Summary
EventForm edit mode now pre-populates correctly from TanStack cache (even when occurrence arrives after form opens), preserves recurrence presets on edit, uses zone-consistent date extraction, and implements a real Tab/Shift+Tab focus trap. PWA install assets confirmed present.
Tasks Completed
| Task | Type | Description | Commit |
|---|---|---|---|
| 1 RED | test | WR-03 blank/recurrence, WR-05 zone, IN-03 export — failing tests | 02e312a |
| 1 GREEN | feat | WR-03 deps fix, WR-05 parseDateTime fix, IN-03 todayIso export | f0f1361 |
| 2 RED | test | WR-07 focus trap Tab/Shift+Tab cycle — failing tests | 4244e8c |
| 2 GREEN | feat | WR-07 inline focus trap on dialogRef + onKeyDown | e971e16 |
What Was Built
WR-03: Edit form re-populates when occurrence arrives after open
The reset effect previously depended on [eventFormOpen, eventFormMode, eventFormUid] — not on occurrence. If the form opened before the ['events'] TanStack cache held the occurrence, the form stayed blank forever.
Fix: Added occurrence?.uid to the reset effect dep array. The effect re-runs when the occurrence resolves in the cache, populating title/allDay/start/end/recurrence/location/description.
Recurrence fix (WR-03): The effect previously hard-coded setRecurrence('none'). Now derives occurrence?.recurrence (cast via any since the CalendarOccurrence type doesn't expose it yet in v1). Defaults to 'none' only when absent, with a comment documenting the v1 limitation.
WR-05: Zone-consistent parseDateTime
The old implementation mixed toISOString().slice(0,10) (UTC date) with getHours() (local time) — the UTC date and local time can be in different day-boundaries at the edges.
Fix: Replaced with consistent local-accessor family: getFullYear/getMonth/getDate/getHours/getMinutes. No toISOString() call in the timed branch. The all-day ^\d{4}-\d{2}-\d{2}$ branch is unchanged.
TZ=UTC pinned in vitest.config.ts via env: { TZ: 'UTC' } so WR-05 assertions are deterministic on any CI runner. In UTC environment, a timed occurrence '2026-06-10T23:30:00-04:00' (UTC instant 2026-06-11T03:30:00Z) renders date=2026-06-11 and time=03:30 — both consistent local-accessor values under UTC.
IN-03: todayIso exported from calendarStore
getDefaultStartDate() and getDefaultEndDate() in EventForm.tsx had identical bodies duplicating the todayIso() function already in calendarStore. Exported todayIso from calendarStore (added export keyword) and imported it into EventForm, collapsing both helpers to todayIso() calls.
WR-07: Real focus trap on EventForm dialog
The docblock claimed "Focus trap while open" but the implementation only called .focus() once on open. Tab escaped the modal to background content.
Fix: Added dialogRef and handleDialogKeyDown handler on the dialog div. On Tab/Shift+Tab, queries all focusable elements inside dialogRef.current and wraps focus at the boundaries:
- Tab on last element →
first.focus()+preventDefault() - Shift+Tab on first element →
last.focus()+preventDefault()
No external library added. Existing focus-on-open (titleRef) and Escape-to-close unchanged. Docblock updated to accurately describe the focus trap.
PWA-01/PWA-02: Install assets confirmed present (IN-04)
All three required PWA install assets exist in apps/pwa/public/:
icon-192.png— 192×192 manifest iconicon-512.png— 512×512 manifest icon (+ maskable)apple-touch-icon.png— iOS Add-to-Home-Screen icon
Referenced in index.html and vite.config.ts manifest. No code change needed; confirmed present for Gate 2.
TDD Gate Compliance
| Gate | Commit | Status |
|---|---|---|
| Task 1 RED | 02e312a |
test(03-12): failing tests added (3 failed) |
| Task 1 GREEN | f0f1361 |
feat(03-12): 27 tests passing |
| Task 2 RED | 4244e8c |
test(03-12): 2 failing focus trap tests |
| Task 2 GREEN | e971e16 |
feat(03-12): 29 tests passing |
Deviations from Plan
Auto-fixed Issues
1. [Rule 2 - Missing] Add todayIso to calendarStore vi.mock() in test file
- Found during: Task 1 GREEN
- Issue: EventForm now imports
todayIsofrom calendarStore, but thevi.mock('../store/calendarStore.js')factory in EventForm.test.tsx only exporteduseCalendarStore. Tests crashed with "No todayIso export is defined on the mock." - Fix: Added
todayIso: () => new Date().toISOString().slice(0, 10)to the mock factory so the mocked module matches the real module's export surface. - Files modified:
apps/pwa/src/components/EventForm.test.tsx
2. [Rule 2 - Missing] Use vi.importActual for IN-03 test
- Found during: Task 1 GREEN
- Issue: The IN-03 test used
await import('../store/calendarStore.js')which returns the mock (not the real module), soactualModule.todayIsowas undefined. - Fix: Changed to
await vi.importActual('../store/calendarStore.js')to bypass the mock and test the real module export. - Files modified:
apps/pwa/src/components/EventForm.test.tsx
Verification
cd apps/pwa && npx vitest run src/components/EventForm.test.tsx
Result: 29 passed (29)
cd apps/pwa && npm run build
Result: Built successfully — 509.67 kB bundle, PWA service worker generated.
Issues Closed
| ID | Description | Status |
|---|---|---|
| WR-03 | Edit form blank when occurrence resolves after open | CLOSED |
| WR-03 | Editing recurring event resets recurrence to 'none' | CLOSED |
| WR-05 | parseDateTime mixes UTC date and local time | CLOSED |
| WR-07 | Focus trap claim without real trap implementation | CLOSED |
| IN-03 | Duplicate todayIso helpers | CLOSED |
| IN-04 | PWA install assets not verified | CLOSED (assets confirmed present) |
Self-Check: PASSED
Files exist:
- apps/pwa/src/components/EventForm.tsx — modified
- apps/pwa/src/components/EventForm.test.tsx — modified
- apps/pwa/src/store/calendarStore.ts — modified (todayIso exported)
- apps/pwa/vitest.config.ts — modified (TZ=UTC)
- apps/pwa/public/icon-192.png
- apps/pwa/public/icon-512.png
- apps/pwa/public/apple-touch-icon.png
Commits exist: