feat(uat-batch-19): a11y th scopes + legend styling + i18n locale fixes
- Raw `<th>` cells gain `scope="col"` so SR users get proper column association: berth-interests-tab, bulk-add-berths-wizard, clients/bulk-hard-delete-dialog. shadcn `<TableHead>` migration would be cleaner but the scope attribute is the minimum-effort fix the queue's a11y entry asks for. - supplemental-info form `<legend>` elements styled with `mb-2 px-1 font-semibold` so they read as section headings rather than blending into the surrounding fieldset border (default browser legend rendering is barely visible). - payments-section: invalid `'en-EU'` BCP-47 locale → `undefined` to honour browser locale. - ui/calendar: literal `'default'` → `undefined` on the month dropdown formatter, same reason. tsc clean. 1419/1419 vitest pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -195,7 +195,7 @@ export default function SupplementalInfoPage({ params }: PageProps) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<fieldset className="space-y-4">
|
<fieldset className="space-y-4">
|
||||||
<legend className="text-sm font-semibold">Your details</legend>
|
<legend className="mb-2 px-1 text-sm font-semibold text-foreground">Your details</legend>
|
||||||
<div className="space-y-1.5">
|
<div className="space-y-1.5">
|
||||||
<Label htmlFor="fullName">Full name</Label>
|
<Label htmlFor="fullName">Full name</Label>
|
||||||
<Input
|
<Input
|
||||||
@@ -244,7 +244,9 @@ export default function SupplementalInfoPage({ params }: PageProps) {
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset className="space-y-4">
|
<fieldset className="space-y-4">
|
||||||
<legend className="text-sm font-semibold">Your yacht (optional)</legend>
|
<legend className="mb-2 px-1 text-sm font-semibold text-foreground">
|
||||||
|
Your yacht (optional)
|
||||||
|
</legend>
|
||||||
<div className="space-y-1.5">
|
<div className="space-y-1.5">
|
||||||
<Label htmlFor="yachtName">Yacht name</Label>
|
<Label htmlFor="yachtName">Yacht name</Label>
|
||||||
<Input
|
<Input
|
||||||
|
|||||||
@@ -227,14 +227,28 @@ export function BulkAddBerthsWizard() {
|
|||||||
<table className="w-full text-xs">
|
<table className="w-full text-xs">
|
||||||
<thead>
|
<thead>
|
||||||
<tr className="border-b text-left text-muted-foreground">
|
<tr className="border-b text-left text-muted-foreground">
|
||||||
<th className="py-2 pr-2">Mooring</th>
|
<th scope="col" className="py-2 pr-2">
|
||||||
<th className="py-2 pr-2">Length (ft)</th>
|
Mooring
|
||||||
<th className="py-2 pr-2">Width (ft)</th>
|
</th>
|
||||||
<th className="py-2 pr-2">Draft (ft)</th>
|
<th scope="col" className="py-2 pr-2">
|
||||||
<th className="py-2 pr-2">Side pontoon</th>
|
Length (ft)
|
||||||
<th className="py-2 pr-2">Price</th>
|
</th>
|
||||||
<th className="py-2 pr-2">Currency</th>
|
<th scope="col" className="py-2 pr-2">
|
||||||
<th className="py-2 pr-2" />
|
Width (ft)
|
||||||
|
</th>
|
||||||
|
<th scope="col" className="py-2 pr-2">
|
||||||
|
Draft (ft)
|
||||||
|
</th>
|
||||||
|
<th scope="col" className="py-2 pr-2">
|
||||||
|
Side pontoon
|
||||||
|
</th>
|
||||||
|
<th scope="col" className="py-2 pr-2">
|
||||||
|
Price
|
||||||
|
</th>
|
||||||
|
<th scope="col" className="py-2 pr-2">
|
||||||
|
Currency
|
||||||
|
</th>
|
||||||
|
<th scope="col" className="py-2 pr-2" />
|
||||||
</tr>
|
</tr>
|
||||||
<tr className="border-b bg-muted/30">
|
<tr className="border-b bg-muted/30">
|
||||||
<td className="py-1 pr-2 text-[10px] text-muted-foreground">apply to all →</td>
|
<td className="py-1 pr-2 text-[10px] text-muted-foreground">apply to all →</td>
|
||||||
|
|||||||
@@ -146,12 +146,22 @@ export function BerthInterestsTab({ berthId }: BerthInterestsTabProps) {
|
|||||||
<table className="w-full text-sm" data-testid="berth-interests-table">
|
<table className="w-full text-sm" data-testid="berth-interests-table">
|
||||||
<thead className="bg-muted/40 text-left text-xs font-medium text-muted-foreground">
|
<thead className="bg-muted/40 text-left text-xs font-medium text-muted-foreground">
|
||||||
<tr>
|
<tr>
|
||||||
<th className="px-3 py-2">Client</th>
|
<th scope="col" className="px-3 py-2">
|
||||||
<th className="px-3 py-2">Stage</th>
|
Client
|
||||||
<th className="px-3 py-2">Category</th>
|
</th>
|
||||||
<th className="px-3 py-2">Source</th>
|
<th scope="col" className="px-3 py-2">
|
||||||
<th className="px-3 py-2">Last activity</th>
|
Stage
|
||||||
<th className="px-3 py-2 text-right" />
|
</th>
|
||||||
|
<th scope="col" className="px-3 py-2">
|
||||||
|
Category
|
||||||
|
</th>
|
||||||
|
<th scope="col" className="px-3 py-2">
|
||||||
|
Source
|
||||||
|
</th>
|
||||||
|
<th scope="col" className="px-3 py-2">
|
||||||
|
Last activity
|
||||||
|
</th>
|
||||||
|
<th scope="col" className="px-3 py-2 text-right" />
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|||||||
@@ -182,8 +182,12 @@ function BulkHardDeleteDialogBody({ onOpenChange, clientIds, onDeleted }: Props)
|
|||||||
<table className="w-full text-xs">
|
<table className="w-full text-xs">
|
||||||
<thead className="bg-muted/50 sticky top-0">
|
<thead className="bg-muted/50 sticky top-0">
|
||||||
<tr>
|
<tr>
|
||||||
<th className="text-left px-2 py-1.5 font-medium">Client ID</th>
|
<th scope="col" className="text-left px-2 py-1.5 font-medium">
|
||||||
<th className="text-left px-2 py-1.5 font-medium">Reason</th>
|
Client ID
|
||||||
|
</th>
|
||||||
|
<th scope="col" className="text-left px-2 py-1.5 font-medium">
|
||||||
|
Reason
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|||||||
@@ -64,7 +64,10 @@ function formatMoney(amount: string, currency: string): string {
|
|||||||
const n = Number(amount);
|
const n = Number(amount);
|
||||||
if (!Number.isFinite(n)) return `${amount} ${currency}`;
|
if (!Number.isFinite(n)) return `${amount} ${currency}`;
|
||||||
try {
|
try {
|
||||||
return new Intl.NumberFormat('en-EU', { style: 'currency', currency }).format(n);
|
// `undefined` locale honours the user's browser locale. The
|
||||||
|
// previous `'en-EU'` literal is not a valid BCP-47 tag — every
|
||||||
|
// implementation falls back to the default anyway.
|
||||||
|
return new Intl.NumberFormat(undefined, { style: 'currency', currency }).format(n);
|
||||||
} catch {
|
} catch {
|
||||||
return `${n.toFixed(2)} ${currency}`;
|
return `${n.toFixed(2)} ${currency}`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,10 @@ function Calendar({
|
|||||||
)}
|
)}
|
||||||
captionLayout={captionLayout}
|
captionLayout={captionLayout}
|
||||||
formatters={{
|
formatters={{
|
||||||
formatMonthDropdown: (date) => date.toLocaleString('default', { month: 'short' }),
|
// `undefined` honours the browser locale. The previous
|
||||||
|
// `'default'` literal is treated as undefined by every modern
|
||||||
|
// engine but reads as if a specific locale were intended.
|
||||||
|
formatMonthDropdown: (date) => date.toLocaleString(undefined, { month: 'short' }),
|
||||||
...formatters,
|
...formatters,
|
||||||
}}
|
}}
|
||||||
classNames={{
|
classNames={{
|
||||||
|
|||||||
Reference in New Issue
Block a user