--- phase: 06-ux-polish plan: "06" subsystem: pwa/event-form tags: [event-form, recurrence, all-day, d-04, d-06, d-08, 999.6] dependency_graph: requires: - Plan 06-01 (computeNewTimedEnd/computeNewAllDayEnd) - Plan 06-02 (RRULE UNTIL/COUNT serialization) - Plan 06-03 (hasRrule on CalendarOccurrence server source-of-truth) - Plan 06-05 (recurrenceUntil/recurrenceCount on CreateEventPayload; hasRrule client mirror) provides: - End-tracking start onChange handlers in EventForm (apps/pwa/src/components/EventForm.tsx) - Recurrence-bound "Ends" control in EventForm - SeriesEditPrompt component (apps/pwa/src/components/SeriesEditPrompt.tsx) - Schedule-X all-day pill override (apps/pwa/src/styles/index.css) affects: [] tech_stack: added: [] patterns: - Schedule-X CSS override via real v4.6.0 classes (.sx__date-grid-event, .sx__month-grid-event) - Confirmation sheet/dialog mirroring DeleteConfirmationDialog (focus trap, Escape=cancel) - Conditional payload spread for recurrence bound fields (never/until/count) key_files: created: - apps/pwa/src/components/SeriesEditPrompt.tsx modified: - apps/pwa/src/components/EventForm.tsx - apps/pwa/src/components/EventForm.test.tsx - apps/pwa/src/styles/index.css decisions: - Schedule-X all-day CSS: the PLAN assumed `.sx__all-day-event` selector but Schedule-X v4.6.0 does not emit that class; the real selectors are `.sx__date-grid-event` (week/day view) and `.sx__month-grid-event:not(:has(.sx__month-grid-event-time))` (month view); `--sx-color-primary-container` CSS variable also remapped as fallback (follow-up fix 6dbb166 + 5620261) - Event create via real form not exercised: the dev-bypass user (id 1) has no CalDAV credential/calendars — those belong to user 2; server logic + form UI verified via route-mocks and direct DB occurrence inserts (dev-seed gap, not a code defect) metrics: duration_minutes: 45 completed_date: "2026-06-10" tasks_completed: 4 files_changed: 5 --- # Phase 06 Plan 06: EventForm Integration Slice (999.6/7/8/9) Summary **One-liner:** Wired `computeNewTimedEnd`/`computeNewAllDayEnd` into EventForm start handlers, added recurrence-bound "Ends" control, built `SeriesEditPrompt` for whole-series edits, and fixed all-day Schedule-X CSS to target real v4.6.0 classes. ## Tasks Completed | Task | Name | Commit | Files | |------|------|--------|-------| | 1 | End-tracking wiring + recurrence-bound control in EventForm | `9aa15c4` (RED), `cbf5f98` (GREEN) | EventForm.tsx, EventForm.test.tsx | | 2 | Series-edit confirmation prompt, gated on hasRrule | `96ef0b4` | SeriesEditPrompt.tsx, EventForm.tsx | | 3 | All-day visual distinction — Schedule-X override | `883b00b` | index.css | | 4 (checkpoint) | playwright-cli — all six event-form behaviors | (verification only) | — | | Follow-up fix | Target real Schedule-X all-day class for filled pills | `6dbb166` | index.css | | Follow-up fix | Remap primary-family container var for fallback all-day solid | `5620261` | index.css | | Integration fix | Set hasRrule on EventDetailPopover test fixtures | `69e5ae8` | EventDetailPopover.test.tsx | ## What Was Built ### Task 1: End-Tracking + Recurrence-Bound Control (D-04, D-06, D-07, D-05 verify) `EventForm.tsx` updated: - Start date `onChange`: calls `computeNewAllDayEnd` (all-day mode) or `computeNewTimedEnd` (timed mode) to recompute end before setting start — end never strands behind start. - Start time `onChange`: calls `computeNewTimedEnd` to recompute end preserving the delta. - `recurrenceBound: 'never' | 'until' | 'count'`, `recurrenceUntil: string`, `recurrenceCount: number` state added alongside the existing state block; reset `useEffect` extended to reset them. - "Ends" control rendered below the recurrence `