--- phase: 06-ux-polish plan: 06 type: execute wave: 2 depends_on: ["06-01", "06-02", "06-03", "06-05"] files_modified: - apps/pwa/src/components/EventForm.tsx - apps/pwa/src/components/SeriesEditPrompt.tsx - apps/pwa/src/styles/index.css autonomous: false requirements: [] must_haves: truths: - "Scope fence (D-01/D-02): this phase delivers only the six promoted polish items (999.2/3/6/7/8/9); 999.4 reminders/VALARM, 999.5 provider setup, and 999.1 provider abstraction are NOT built here (deferred to milestone 1.1)" - "Moving an event's start moves its end with it, preserving duration; the end never strands behind the start (D-03/D-04, success criterion 2)" - "A recurring event can be bounded in the form via 'Ends: Never / On date / After N times' (D-06, success criterion 2)" - "Editing a recurring occurrence prompts 'Edit recurring series' before saving the whole-series change (D-08/D-09, success criterion 3)" - "The all-day-edit off-by-one stays fixed — re-editing an all-day event does not grow it by a day (D-05 verify, success criterion 2)" - "All-day events are visually distinct from timed events at a glance (999.6/D-12, success criterion 1)" artifacts: - path: "apps/pwa/src/components/EventForm.tsx" provides: "start onChange handlers that call computeNewTimedEnd/computeNewAllDayEnd; recurrence-bound control; hasRrule-gated series-edit confirmation" contains: "computeNewTimedEnd" - path: "apps/pwa/src/components/SeriesEditPrompt.tsx" provides: "whole-series edit confirmation sheet/dialog (focus trap, Escape=cancel)" contains: "Update series" - path: "apps/pwa/src/styles/index.css" provides: "Schedule-X all-day chip override (full-width filled pill)" contains: "sx__all-day-event" key_links: - from: "apps/pwa/src/components/EventForm.tsx" to: "apps/pwa/src/lib/eventDateTime.ts" via: "start onChange → computeNewTimedEnd / computeNewAllDayEnd" pattern: "computeNewTimedEnd|computeNewAllDayEnd" - from: "apps/pwa/src/components/EventForm.tsx" to: "apps/pwa/src/api/client.ts" via: "payload carries recurrenceUntil/recurrenceCount; occurrence.hasRrule gates the prompt" pattern: "recurrenceUntil|recurrenceCount|hasRrule" --- Wire the prepared logic into the event form so the user-facing 999.7/999.8/999.9 fixes are live, and give all-day events their distinct look (999.6). After this plan a real user can: move a start and watch the end follow (D-04), bound a recurring series with "Ends: On date / After N times" (D-06), edit a recurring series behind a confirming prompt (D-08/D-09), and tell all-day from timed events at a glance (999.6) — with the all-day-edit off-by-one staying fixed (D-05). This is the Wave-2 integration slice. It consumes (does NOT redefine) artifacts from earlier plans: `computeNewTimedEnd`/`computeNewAllDayEnd` (Plan 01), the `recurrenceUntil`/`recurrenceCount` payload fields + `hasRrule` on `CalendarOccurrence` (Plan 05 client types, backed by Plan 02 API contract + Plan 03 server expansion). Purpose: This is glue + UI (form wiring, a confirmation component, a CSS override) — standard tasks, verified with playwright-cli per CLAUDE.md. The deterministic math/serialization it depends on is already unit-tested in Plans 01–03. Output: EventForm end-tracking handlers + recurrence-bound control + series-edit prompt trigger; `SeriesEditPrompt.tsx`; all-day Schedule-X override in `index.css`. @$HOME/.claude/gsd-core/workflows/execute-plan.md @$HOME/.claude/gsd-core/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/06-ux-polish/06-RESEARCH.md @.planning/phases/06-ux-polish/06-PATTERNS.md @.planning/phases/06-ux-polish/06-UI-SPEC.md @apps/pwa/src/components/DeleteConfirmationDialog.tsx @.planning/phases/06-ux-polish/06-01-SUMMARY.md @.planning/phases/06-ux-polish/06-05-SUMMARY.md NEW symbols introduced here (exclude from drift/convergence checks): - Start `onChange` handlers in `EventForm.tsx` that call `computeNewTimedEnd`/`computeNewAllDayEnd` - `recurrenceBound: 'never'|'until'|'count'`, `recurrenceUntil: string`, `recurrenceCount: number` state + the "Ends" control in `EventForm.tsx` - `SeriesEditPrompt` component (`apps/pwa/src/components/SeriesEditPrompt.tsx`) - `.sx__all-day-event` CSS override block in `apps/pwa/src/styles/index.css` NOTE: `computeNewTimedEnd`, `computeNewAllDayEnd`, `recurrenceUntil`/`recurrenceCount` payload fields, and `hasRrule` are NOT new here — they are consumed from Plans 01/05. Task 1: End-tracking wiring + recurrence-bound control in EventForm (D-04, D-06, D-07, D-05 verify) apps/pwa/src/components/EventForm.tsx, apps/pwa/src/components/EventForm.test.tsx - apps/pwa/src/components/EventForm.tsx — start date input `onChange` (~line 671) and start time input `onChange` (~line 684); state block (199–210); the reset `useEffect` (~232–262); the submit handler payload construction (~355–370, the `...(isEdit ? {} : { recurrence })` pattern); the recurrence ``, shown only when `recurrence !== 'none'`, using the exact UI-SPEC Surface 5 labels/options and 44px touch targets, with inline `--color-destructive` validation messages. Extend the submit payload to conditionally include `recurrenceUntil` (bound==='until') or `recurrenceCount` (bound==='count') only when `recurrence !== 'none'` — mirror the existing spread-conditional pattern. Do NOT re-implement the D-05 `exclusiveEndToInclusiveDate` pre-fill — leave line ~199 intact and add/keep a test asserting the all-day edit round-trip does not drift. For D-07, confirm the recurrence `