Adds a small top-centered <Toast> that fires only when the Server
Action returns { ok: true } (i.e., the DB write actually succeeded).
Auto-dismisses after 3s.
Wires both create dialogs (CreateAccountDialog, CreateUserDialog) with
an onSuccess callback that the table parent uses to push the toast,
and the delete confirm-flow does the same. Inline-edit success stays
quiet (no toast) — only add/delete trigger it, per the requested
scope.
58 lines
1.5 KiB
TypeScript
58 lines
1.5 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect } from "react";
|
|
|
|
export type ToastMessage = {
|
|
type: "success" | "error";
|
|
message: string;
|
|
};
|
|
|
|
/**
|
|
* Simple top-centered toast. Auto-dismisses after `durationMs` (default
|
|
* 3s). Owners hold the ToastMessage state; this component reads it and
|
|
* calls onDismiss when the timer fires (or when the toast object
|
|
* changes — useEffect's cleanup clears any in-flight timer).
|
|
*/
|
|
export default function Toast({
|
|
toast,
|
|
onDismiss,
|
|
durationMs = 3000,
|
|
}: {
|
|
toast: ToastMessage | null;
|
|
onDismiss: () => void;
|
|
durationMs?: number;
|
|
}) {
|
|
useEffect(() => {
|
|
if (!toast) return;
|
|
const id = setTimeout(onDismiss, durationMs);
|
|
return () => clearTimeout(id);
|
|
}, [toast, onDismiss, durationMs]);
|
|
|
|
if (!toast) return null;
|
|
|
|
const styles =
|
|
toast.type === "success"
|
|
? "bg-emerald-50 text-emerald-800 ring-emerald-200"
|
|
: "bg-red-50 text-red-800 ring-red-200";
|
|
|
|
return (
|
|
<div
|
|
role="status"
|
|
aria-live="polite"
|
|
className="fixed left-1/2 top-4 z-50 -translate-x-1/2 transform px-4"
|
|
>
|
|
<div
|
|
className={`flex items-center gap-2 rounded-full px-4 py-2 shadow-sm ring-1 ${styles}`}
|
|
>
|
|
<span
|
|
aria-hidden="true"
|
|
className="inline-flex h-5 w-5 items-center justify-center rounded-full bg-current/10 text-xs font-bold"
|
|
>
|
|
{toast.type === "success" ? "✓" : "!"}
|
|
</span>
|
|
<span className="text-sm font-medium">{toast.message}</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|