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

7.0 KiB
Raw Blame History

phase, plan, subsystem, tags, dependency_graph, tech_stack, key_files, decisions, metrics, status
phase plan subsystem tags dependency_graph tech_stack key_files decisions metrics status
17-ui-optimization-polish 06 pwa-admin
admin
toasts
tabs
aria
accessibility
e2e
requires provides affects
17-01
admin-success-toasts
admin-two-tab-nav
admin-reset-sheet-centering
admin-e2e-aria
apps/pwa/src/routes/AdminPage.tsx
apps/pwa/e2e/admin.spec.ts
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
created modified
apps/pwa/src/routes/AdminPage.tsx
apps/pwa/e2e/admin.spec.ts
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
duration completed tasks_completed tasks_total files_modified
9 minutes 2026-06-18 3 3 2
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.onSuccesssetToast('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