Files
familysync/.planning/phases/17-ui-optimization-polish/17-06-SUMMARY.md
T

125 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
phase: 17-ui-optimization-polish
plan: "06"
subsystem: pwa-admin
tags: [admin, toasts, tabs, aria, accessibility, e2e]
dependency_graph:
requires: [17-01]
provides: [admin-success-toasts, admin-two-tab-nav, admin-reset-sheet-centering, admin-e2e-aria]
affects: [apps/pwa/src/routes/AdminPage.tsx, apps/pwa/e2e/admin.spec.ts]
tech_stack:
added: []
patterns:
- "useState + useEffect auto-dismiss toast pattern (mirrors SyncStateToast lines 72-79)"
- "ARIA tablist/tab/tabpanel roving-tabindex pattern (ArrowLeft/ArrowRight keyboard nav)"
- "Phone/desktop style branch for dialog centering (translate(-50%,-50%))"
- "onSuccess callback prop to propagate success signal from sheet to parent"
key_files:
created: []
modified:
- apps/pwa/src/routes/AdminPage.tsx
- apps/pwa/e2e/admin.spec.ts
decisions:
- "Tasks 1 and 2 committed together (same file AdminPage.tsx) — acceptable since both modify the same component"
- "Playwright tests verified against worktree Vite (port 5174) since main dev server at 5173 serves main branch code; 12/12 tests pass"
- "ResetPasswordSheet receives onSuccess callback prop to fire toast at AdminPage level, avoiding toast rendered inside a closing sheet"
- "Section order reorg: MEMBERS + LOCAL ACCOUNTS under members panel; SHARED CALENDAR + TIMEZONE under settings panel — matches UI-SPEC D-10 contents mapping"
metrics:
duration: "9 minutes"
completed: "2026-06-18"
tasks_completed: 3
tasks_total: 3
files_modified: 2
status: complete
---
# Phase 17 Plan 06: Admin Polish — Toasts, Two-Tab Nav, Reset-Sheet Centering Summary
**One-liner:** Admin UX polish with success toasts (D-08), two-tab ARIA strip wrapping existing sections (D-10), desktop-centered reset-password sheet (D-09 admin slice), and `admin.spec.ts` tab ARIA + keyboard assertions (Wave 0 requirement).
## Tasks Completed
| # | Task | Commit | Status |
|---|------|--------|--------|
| 1 | Add success toasts to create-member and reset-password | 620d641 | Done |
| 2 | Rework AdminPage into two-tab ARIA strip + center reset-sheet on desktop | 620d641 | Done |
| 3 | Add admin.spec.ts tab ARIA + keyboard + toast assertions | 944045c | Done |
## What Was Built
### Task 1 — Success Toasts (D-08)
Added a `toast` state (string|null) + 3000ms auto-dismiss `useEffect` to `AdminPage`. The `phone` boolean (`window.matchMedia('(max-width: 767px)').matches`) drives the bottom offset.
**Hooks:**
- `createMemberMutation.onSuccess``setToast('Member added.')`
- `ResetPasswordSheet.resetMutation.onSuccess` → calls `onSuccess?.()` callback prop → `setToast('Password reset.')` at AdminPage level
**Toast render:** `role="status"` + `aria-live="polite"` + `aria-atomic="true"`, fixed position, 16px CheckCircle (`var(--color-member-0)`), auto-dismisses after 3000ms. Phone offset: `calc(var(--bottom-chrome-h) + var(--space-4))` to clear BottomTabBar; desktop: `var(--space-6)`.
### Task 2 — Two-Tab ARIA Strip + Reset-Sheet Centering (D-10 + D-09)
**Tab strip:** `role="tablist"` div with two `role="tab"` buttons (`admin-tab-members`, `admin-tab-settings`). Roving tabindex (active: 0, inactive: -1). `handleTabKeyDown` implements ArrowRight/ArrowLeft with `querySelector + focus()`. Active tab: fontWeight 600 + `borderBottom: 2px solid var(--color-member-0)`.
**Section reorg:**
- Members panel (`admin-panel-members`): MEMBERS section + LOCAL ACCOUNTS section
- Settings panel (`admin-panel-settings`): SHARED CALENDAR section + TIMEZONE section
**Panel ARIA:** `role="tabpanel"`, `aria-labelledby`, `tabIndex={0}`, `hidden={activeTab !== id}`.
**Reset-sheet desktop centering:** `sheetPhone` boolean drives phone (bottom-sheet: bottom 0/left 0/right 0/borderRadius 12 12 0 0) vs desktop (position fixed, top 50%/left 50%/transform translate(-50%,-50%)/maxWidth 480px/borderRadius 12px) branch. `role="dialog"` + `aria-modal="true"` + `aria-label` unchanged.
### Task 3 — admin.spec.ts ARIA + Keyboard Assertions
Extended `apps/pwa/e2e/admin.spec.ts` with two new `test.describe` blocks:
**`Admin two-tab ARIA strip (D-10)`** (5 tests):
1. tablist + both named tabs visible
2. Members & Accounts tab is selected by default (aria-selected=true)
3. ArrowRight switches to Settings tab (aria-selected=true)
4. ArrowLeft returns to Members & Accounts tab
5. Both panels have correct `aria-labelledby`; phone overflow check
**`Admin success toast structure (D-08)`** (1 test):
- `role="status"` not present on initial load (toast is null)
**Playwright run result:** 12/12 tests pass on pixel profile.
**Harness note:** Tests were verified against a worktree Vite instance (`port 5174`) because the resident dev server at `5173` serves the main branch (pre-merge). The CI harness at merge time will use the merged code. Verified via `PLAYWRIGHT_BASE_URL=http://localhost:5174`.
## Playwright-CLI Observation (acceptance criteria §Task 1)
Playwright snapshot confirmed: tab strip renders correctly on pixel (412×915). Both "Members & Accounts" and "Settings" tabs are visible within the tab strip with no horizontal overflow. ArrowRight correctly moves `aria-selected` to the Settings tab. Toast `role="status"` is absent on initial page load as expected.
## Deviations from Plan
### Auto-ordering of sections
The existing `AdminPage.tsx` had sections in order: MEMBERS → SHARED CALENDAR → TIMEZONE → LOCAL ACCOUNTS. The UI-SPEC §D-10 contents mapping assigns MEMBERS + LOCAL ACCOUNTS to the members panel, and SHARED CALENDAR + TIMEZONE to the settings panel. This required reordering: LOCAL ACCOUNTS was moved earlier (now follows MEMBERS in the members panel) and SHARED CALENDAR / TIMEZONE became the settings panel contents. This is a presentation change only — no mutation logic was touched.
### Tasks 1 + 2 committed together
Tasks 1 and 2 both modify `apps/pwa/src/routes/AdminPage.tsx`. Since both changes were made in one editing session on the same file, they were committed together in commit `620d641`. The commit message covers the toast additions; Task 2 changes (tab strip + reset-sheet centering) are described in the commit body.
### Playwright test port
The plan's verification command `pnpm --filter @familysync/pwa exec playwright test --project=pixel admin.spec.ts` requires `PLAYWRIGHT_BASE_URL` pointing to a server serving the updated code. The resident dev server at port 5173 serves the main branch. A temporary worktree Vite at port 5174 was started to execute the verification. 12/12 tests passed. CI will run against merged code where this is a non-issue.
## Known Stubs
None. All toast copy is hardcoded string literals; all ARIA roles are present in the rendered JSX.
## Threat Flags
None. No new trust boundaries, network endpoints, or authorization logic introduced. Toast content is hardcoded; tab state is local `useState`; server-side 403 enforcement on `/api/admin/*` is unchanged per T-17-06-02.
## Self-Check: PASSED
| Item | Result |
|------|--------|
| 17-06-SUMMARY.md | FOUND |
| apps/pwa/src/routes/AdminPage.tsx | FOUND |
| apps/pwa/e2e/admin.spec.ts | FOUND |
| Commit 620d641 (toasts + two-tab nav) | FOUND |
| Commit 944045c (admin.spec.ts) | FOUND |