fix(fuel): review fixes for dismiss button
- Disable all dismiss buttons while any is in flight so rapid clicks on a second vehicle don't silently no-op. - Map API error slugs (bad_id, not_found, update_failed) to user-facing copy so window.alert shows prose, not machine tags. - Add aria-busy to the dismiss buttons. - Drop redundant e.stopPropagation(); preventDefault() is sufficient to suppress the wrapping <Link>.
This commit is contained in:
parent
1e212a7339
commit
c633681789
1 changed files with 26 additions and 6 deletions
|
|
@ -184,6 +184,12 @@ function StatusBadge({ status, variancePct }: { status: FuelStatus; variancePct:
|
|||
);
|
||||
}
|
||||
|
||||
const DISMISS_ERROR_COPY: Record<string, string> = {
|
||||
bad_id: "That vehicle id is malformed.",
|
||||
not_found: "Vehicle not found.",
|
||||
update_failed: "Server update failed. Please try again.",
|
||||
};
|
||||
|
||||
export function FuelView({
|
||||
rows,
|
||||
vehicles,
|
||||
|
|
@ -338,8 +344,16 @@ export function FuelView({
|
|||
{ method: "POST" },
|
||||
);
|
||||
if (!res.ok) {
|
||||
const data: { error?: string } = await res.json().catch(() => ({}));
|
||||
throw new Error(data.error ?? `Dismiss failed (${res.status})`);
|
||||
let slug: string | undefined;
|
||||
try {
|
||||
const data: { error?: string } = await res.json();
|
||||
slug = data.error;
|
||||
} catch {
|
||||
/* non-JSON body — fall through */
|
||||
}
|
||||
const friendly =
|
||||
(slug && DISMISS_ERROR_COPY[slug]) ?? `Dismiss failed (${res.status})`;
|
||||
throw new Error(friendly);
|
||||
}
|
||||
// Re-pull server data so the overlay becomes a no-op and any
|
||||
// other server-side state stays in sync.
|
||||
|
|
@ -540,6 +554,7 @@ export function FuelView({
|
|||
href={vehicleHref(v.id)}
|
||||
onDismiss={handleDismiss}
|
||||
busy={busyId === v.id}
|
||||
disabled={busyId !== null}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
|
|
@ -553,6 +568,7 @@ export function FuelView({
|
|||
href={vehicleHref(v.id)}
|
||||
onDismiss={handleDismiss}
|
||||
busy={busyId === v.id}
|
||||
disabled={busyId !== null}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
|
|
@ -788,11 +804,13 @@ function AlertCard({
|
|||
href,
|
||||
onDismiss,
|
||||
busy,
|
||||
disabled,
|
||||
}: {
|
||||
v: VehicleSummary;
|
||||
href: string;
|
||||
onDismiss: (id: string) => void;
|
||||
busy: boolean;
|
||||
disabled: boolean;
|
||||
}) {
|
||||
const dominant = v.alert > 0 ? "alert" : "warn";
|
||||
const toneClasses =
|
||||
|
|
@ -867,10 +885,10 @@ function AlertCard({
|
|||
type="button"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
onDismiss(v.id);
|
||||
}}
|
||||
disabled={busy}
|
||||
disabled={disabled}
|
||||
aria-busy={busy}
|
||||
aria-label={`Mark ${v.description} as seen`}
|
||||
className="inline-flex shrink-0 items-center gap-1 rounded-md border border-border/60 bg-card px-2 py-1 text-xs font-medium text-muted-foreground transition-colors hover:border-[#F2B165]/60 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#F2B165] disabled:opacity-50"
|
||||
>
|
||||
|
|
@ -887,11 +905,13 @@ function AlertListRow({
|
|||
href,
|
||||
onDismiss,
|
||||
busy,
|
||||
disabled,
|
||||
}: {
|
||||
v: VehicleSummary;
|
||||
href: string;
|
||||
onDismiss: (id: string) => void;
|
||||
busy: boolean;
|
||||
disabled: boolean;
|
||||
}) {
|
||||
const dominant = v.alert > 0 ? "alert" : "warn";
|
||||
const stripeColor =
|
||||
|
|
@ -948,10 +968,10 @@ function AlertListRow({
|
|||
type="button"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
onDismiss(v.id);
|
||||
}}
|
||||
disabled={busy}
|
||||
disabled={disabled}
|
||||
aria-busy={busy}
|
||||
aria-label={`Mark ${v.description} as seen`}
|
||||
className="ml-2 inline-flex shrink-0 items-center gap-1.5 rounded-md border border-border/60 bg-card px-2 py-1 text-xs font-medium text-muted-foreground transition-colors hover:border-[#F2B165]/60 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#F2B165] disabled:opacity-50"
|
||||
>
|
||||
|
|
|
|||
Loading…
Reference in a new issue