From db511063df3cb369164c5c8f61a6d811eb93a220 Mon Sep 17 00:00:00 2001 From: Matt Date: Thu, 21 May 2026 18:01:17 +0200 Subject: [PATCH] feat(uat-batch-10): copy polish, TTL trim, and a11y discrete fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Supplemental-info link TTL trimmed from 30 → 14 days (single constant in supplemental-forms.service). - LinkedBerthsList toggle renamed "Mark in EOI bundle" → "Include in EOI"; tooltip aria-label updated to match. - Icon-only row-action triggers on the interest / client / berth list tables gain aria-label (Row actions for ) so SR users hear the row context. - Table / Board view toggle on interest list gains aria-label + aria-pressed on each variant; wrapper gets role="group". - Upcoming-milestones disclosure on interest-tabs gains aria-expanded + aria-controls; recommender Hide/Add filters button matches. - BrandedAuthShell logo alt no longer defaults to "Sign in" — uses the configured `appName` when known, empty string otherwise so screen readers don't announce "Sign in" on password-reset / set-password pages. tsc clean. 1419/1419 vitest pass. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/components/berths/berth-columns.tsx | 1 + src/components/clients/client-columns.tsx | 1 + src/components/interests/berth-recommender-panel.tsx | 6 +++++- src/components/interests/interest-columns.tsx | 1 + src/components/interests/interest-list.tsx | 10 +++++++++- src/components/interests/interest-tabs.tsx | 3 +++ src/components/interests/linked-berths-list.tsx | 4 ++-- src/components/shared/branded-auth-shell.tsx | 6 +++++- src/lib/services/supplemental-forms.service.ts | 2 +- 9 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/components/berths/berth-columns.tsx b/src/components/berths/berth-columns.tsx index 42da94ca..2f700d9b 100644 --- a/src/components/berths/berth-columns.tsx +++ b/src/components/berths/berth-columns.tsx @@ -176,6 +176,7 @@ function ActionsCell({ row }: { row: { original: BerthRow } }) { variant="ghost" size="icon" className="h-8 w-8" + aria-label={`Row actions for berth ${berth.mooringNumber ?? ''}`.trim()} onClick={(e) => e.stopPropagation()} > diff --git a/src/components/clients/client-columns.tsx b/src/components/clients/client-columns.tsx index 02bbe610..c7512de3 100644 --- a/src/components/clients/client-columns.tsx +++ b/src/components/clients/client-columns.tsx @@ -302,6 +302,7 @@ export function getClientColumns({ variant="ghost" size="icon" className="h-7 w-7" + aria-label={`Row actions for ${row.original.fullName ?? 'client'}`} onClick={(e) => e.stopPropagation()} > diff --git a/src/components/interests/berth-recommender-panel.tsx b/src/components/interests/berth-recommender-panel.tsx index 86d9aced..5b0a53e9 100644 --- a/src/components/interests/berth-recommender-panel.tsx +++ b/src/components/interests/berth-recommender-panel.tsx @@ -503,6 +503,8 @@ export function BerthRecommenderPanel({ variant="outline" onClick={() => setFiltersOpen((v) => !v)} disabled={!hasDimensions} + aria-expanded={filtersOpen} + aria-controls="recommender-filters-body" > {filtersOpen ? 'Hide filters' : 'Add filters'} @@ -542,7 +544,9 @@ export function BerthRecommenderPanel({ {!collapsed && filtersOpen && hasDimensions ? ( - +
+ +
) : null} {!collapsed && hasDimensions && areaChips.length > 1 ? (
diff --git a/src/components/interests/interest-columns.tsx b/src/components/interests/interest-columns.tsx index 074e240a..fb756f93 100644 --- a/src/components/interests/interest-columns.tsx +++ b/src/components/interests/interest-columns.tsx @@ -297,6 +297,7 @@ export function getInterestColumns({ variant="ghost" size="icon" className="h-7 w-7" + aria-label={`Row actions for ${row.original.clientName ?? 'interest'}`} onClick={(e) => e.stopPropagation()} > diff --git a/src/components/interests/interest-list.tsx b/src/components/interests/interest-list.tsx index 1b24b127..c6009427 100644 --- a/src/components/interests/interest-list.tsx +++ b/src/components/interests/interest-list.tsx @@ -183,11 +183,17 @@ export function InterestList() { {/* Kanban view is desktop-only — mobile drops the toggle and falls back to the list/cards view (the board's column horizontal-scroll model is unusable at phone widths). */} -
+
{expanded && (
- Mark in EOI bundle + Include in EOI diff --git a/src/components/shared/branded-auth-shell.tsx b/src/components/shared/branded-auth-shell.tsx index 8d892ce2..5be7aec1 100644 --- a/src/components/shared/branded-auth-shell.tsx +++ b/src/components/shared/branded-auth-shell.tsx @@ -29,7 +29,11 @@ export function BrandedAuthShell({ children, branding }: BrandedAuthShellProps) const ctx = useAuthBranding(); const logoUrl = branding?.logoUrl ?? ctx?.logoUrl ?? null; const backgroundUrl = branding?.backgroundUrl ?? ctx?.backgroundUrl ?? null; - const altText = branding?.appName ?? ctx?.appName ?? 'Sign in'; + // When no port name is known, treat the logo as decorative — "Sign in" + // as alt text was being read on every auth page even when the page + // itself isn't a sign-in surface (e.g. password reset, set-password). + const appName = branding?.appName ?? ctx?.appName ?? null; + const altText = appName ?? ''; // fixed inset-0 anchors the auth surface to the viewport directly — // iOS Safari ignores overflow-hidden on inner divs for body-level // scrolling, so a regular `h-dvh overflow-hidden` wrapper doesn't diff --git a/src/lib/services/supplemental-forms.service.ts b/src/lib/services/supplemental-forms.service.ts index 52b554c2..4e0e7e50 100644 --- a/src/lib/services/supplemental-forms.service.ts +++ b/src/lib/services/supplemental-forms.service.ts @@ -22,7 +22,7 @@ import { } from '@/lib/db/schema'; import { ConflictError, NotFoundError, ValidationError } from '@/lib/errors'; -const TOKEN_TTL_DAYS = 30; +const TOKEN_TTL_DAYS = 14; const TOKEN_BYTES = 32; // 256-bit → ~43 base64url chars; brute-force infeasible. function generateToken(): string {