60 lines
1.9 KiB
TypeScript
60 lines
1.9 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useTransition } from "react";
|
|
import { useRouter } from "next/navigation";
|
|
|
|
type ActionResult = { ok: true } | { error: string };
|
|
|
|
export function ConfirmDeleteButton({
|
|
onDelete,
|
|
label,
|
|
}: {
|
|
onDelete: () => Promise<ActionResult>;
|
|
label: string;
|
|
}) {
|
|
const router = useRouter();
|
|
const [confirming, setConfirming] = useState(false);
|
|
const [error, setError] = useState("");
|
|
const [isPending, startTransition] = useTransition();
|
|
|
|
if (confirming) {
|
|
return (
|
|
<span className="inline-flex items-center gap-1.5 flex-wrap">
|
|
<span className="text-xs text-neutral-500 whitespace-nowrap">Delete {label}?</span>
|
|
<button
|
|
onClick={() =>
|
|
startTransition(async () => {
|
|
const result = await onDelete();
|
|
if ("error" in result) {
|
|
setError(result.error);
|
|
setConfirming(false);
|
|
} else {
|
|
router.refresh();
|
|
}
|
|
})
|
|
}
|
|
disabled={isPending}
|
|
className="rounded border border-danger-400 bg-danger-600 px-2 py-0.5 text-xs font-semibold text-white hover:bg-danger-700 disabled:opacity-50 whitespace-nowrap transition-colors"
|
|
>
|
|
{isPending ? "Deleting…" : "Confirm"}
|
|
</button>
|
|
<button
|
|
onClick={() => { setConfirming(false); setError(""); }}
|
|
className="rounded border border-neutral-300 bg-white px-2 py-0.5 text-xs text-neutral-600 hover:bg-neutral-50 whitespace-nowrap transition-colors"
|
|
>
|
|
Cancel
|
|
</button>
|
|
{error && <span className="text-xs text-danger-600 block w-full">{error}</span>}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<button
|
|
onClick={() => setConfirming(true)}
|
|
className="rounded border border-danger-200 bg-white px-2.5 py-1 text-xs font-medium text-danger-600 hover:bg-danger-50 hover:border-danger-300 transition-colors"
|
|
>
|
|
Delete
|
|
</button>
|
|
);
|
|
}
|