Files
familysync/.planning/phases/17-ui-optimization-polish/17-05-SUMMARY.md
T
Lucas Berger caff8b4b0a docs(17-05): complete logout control + sheet centering plan
- Sign out control (D-07): LogOut icon, handleSignOut fire-and-best-effort, navigate /login
- Desktop centering (D-09): phone/desktop style branch on SettingsSheet, ChangePasswordSheet, LinkOidcSheet, CredentialSheet
- playwright-cli verified: centered modal @1280x720, bottom-sheet @390x844, Sign out redirects to /login
2026-06-18 12:54:43 -04:00

5.9 KiB

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 05 pwa-ui
logout
settings
desktop-centering
sheet-ux
d-07
d-09
requires provides affects
17-01
reachable-logout
desktop-centered-sheets
SettingsSheet
ChangePasswordSheet
LinkOidcSheet
CredentialSheet
added patterns
phone-desktop-style-branch
fire-and-best-effort-logout
react-router-useNavigate
modified
apps/pwa/src/components/SettingsSheet.tsx
apps/pwa/src/components/CredentialSheet.tsx
phone const computed at render time via window.matchMedia (not a hook) — consistent with established App.tsx / BottomTabBar.tsx project pattern
handleSignOut calls onClose() before navigate() so the sheet dismisses even if router state causes a re-render
All three sub-sheets in SettingsSheet.tsx (SettingsSheet, ChangePasswordSheet, LinkOidcSheet) received the centering branch in a single commit since they share the same file and the branch is identical
duration completed tasks_completed tasks_total files_changed
6 minutes 2026-06-18 2 2 2
complete

Phase 17 Plan 05: Logout Control + Sheet Centering Summary

Wired a reachable Sign out control into SettingsSheet (D-07) and fixed dialog centering so all four settings sheets render as centered modals on desktop and unchanged bottom-sheets on phone (D-09).

Tasks Completed

Task Name Commit Files
1 Add Sign out control and handleSignOut to SettingsSheet 132a5e4 SettingsSheet.tsx
2 Add phone/desktop centering branch to all sheets b712386 CredentialSheet.tsx

What Was Built

Task 1 — Sign out control (D-07)

Added to SettingsSheet.tsx:

  • LogOut icon imported from lucide-react (added to existing icon import)
  • fetchLocalLogout imported from ../api/client.js (added to existing import)
  • useNavigate from react-router for post-logout routing
  • handleSignOut async function: wraps fetchLocalLogout() in try/catch, calls onClose() then navigate('/login') in both success and catch branches — fire-and-best-effort per D-07 spec (server cookie is cleared or already expired; navigation must always proceed)
  • Sign out button row: 44px minHeight, var(--color-destructive) color, 16px LogOut icon, "Sign out" text, full-width, aria-label="Sign out", separated from prior sections by the project's 1px var(--color-border-subtle) divider

The button renders unconditionally at the bottom of the sheet — visible regardless of hasLocalCredential or oidcEnabled gating.

Task 2 — Phone/desktop centering branch (D-09)

Applied phone = window.matchMedia('(max-width: 767px)').matches + ternary style branch to four dialog wrappers:

Sheet File zIndex
SettingsSheet SettingsSheet.tsx 301
ChangePasswordSheet SettingsSheet.tsx 303
LinkOidcSheet SettingsSheet.tsx 303
CredentialSheet CredentialSheet.tsx 301

Phone branch (unchanged): position: fixed; bottom: 0; left: 0; right: 0; borderRadius: 12px 12px 0 0

Desktop branch (new): position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); maxWidth: 480px; width: calc(100% - 32px); maxHeight: calc(100dvh - 32px); overflowY: auto; borderRadius: 12px; boxShadow: 0 8px 32px rgba(0,0,0,0.18)

role=dialog, aria-modal, aria-label, Escape-closes, and focus-return invariants unchanged on all wrappers.

Note: AdminPage.ResetPasswordSheet centering is handled by plan 17-06 (single-file-owner constraint).

Playwright Validation

Desktop @1280x720: SettingsSheet opened centered on the page as a modal dialog. Sign out button visible with destructive red styling and LogOut icon at the bottom of the sheet. Clicking Sign out navigated to /login (confirmed URL change from http://localhost:5175/calendar to http://localhost:5175/login).

Phone @390x844: SettingsSheet rendered as a bottom-sheet anchored to the bottom of viewport with rounded top corners. Sign out button visible at bottom. Bottom-sheet behavior unchanged.

Both screenshots confirmed correct behavior for D-07 and D-09.

Verification Checks

  • grep handleSignOut in SettingsSheet.tsx: PASS
  • grep fetchLocalLogout in SettingsSheet.tsx: PASS
  • grep 'Sign out' in SettingsSheet.tsx: PASS
  • grep LogOut in SettingsSheet.tsx: PASS
  • grep 'translate(-50%, -50%)' in SettingsSheet.tsx: PASS (3 occurrences — SettingsSheet, ChangePasswordSheet, LinkOidcSheet)
  • grep 'translate(-50%, -50%)' in CredentialSheet.tsx: PASS
  • grep 'max-width: 767px' in CredentialSheet.tsx: PASS
  • pnpm --filter @familysync/pwa build: PASS (exits 0, 1858 modules)

Threat Model Compliance

Threat ID Mitigation Applied
T-17-05-01 handleSignOut calls fetchLocalLogout() (clears server-side cookie) then always navigates to /login — no stale-cookie-with-logged-out-UI state possible
T-17-05-02 Position-only CSS branch — no new input or executable content

Deviations from Plan

None — plan executed exactly as written.

Known Stubs

None — both D-07 and D-09 are fully wired. Sign out calls the real fetchLocalLogout() endpoint. Centering is CSS-only with no data source.

Threat Flags

None — no new network endpoints, auth paths, or schema changes introduced. All changes are UI-layer only.

Self-Check: PASSED

  • /home/luc/projects/familysync/.claude/worktrees/agent-a65077bbd9885bf7e/apps/pwa/src/components/SettingsSheet.tsx — FOUND, contains handleSignOut, fetchLocalLogout, Sign out, LogOut, translate(-50%, -50%)
  • /home/luc/projects/familysync/.claude/worktrees/agent-a65077bbd9885bf7e/apps/pwa/src/components/CredentialSheet.tsx — FOUND, contains translate(-50%, -50%), max-width: 767px
  • Commit 132a5e4 — FOUND (Task 1)
  • Commit b712386 — FOUND (Task 2)
  • Build: pnpm --filter @familysync/pwa build exits 0