"use client"; import { useActionState, useRef, useState, type ReactNode } from "react"; import { AlertDialog, Spinner, useToast } from "@unlocalhosted/metalui"; import type { FormState } from "@/app/actions/types"; import { Button, type ButtonVariant } from "./ui"; /** * One button that runs a server action, with its outcome on the toast deck: for actions that fail * for reasons worth reading (a conflict, a branch rule). With `confirm`, it asks first, like * ConfirmButton. */ export function ActionButton({ action, children, icon, variant = "default", className = "", confirm, }: { action: (prev: FormState, formData: FormData) => Promise; children: ReactNode; icon?: ReactNode; variant?: ButtonVariant; className?: string; confirm?: { title: string; description: ReactNode; label: ReactNode; destructive?: boolean }; }) { const toast = useToast(); const form = useRef(null); const [open, setOpen] = useState(false); const [, formAction, pending] = useActionState(async (prev: FormState, formData: FormData) => { const result = await action(prev, formData); if (result?.error) toast.show({ title: result.error, tone: "error" }); else if (result?.success) toast.show({ title: result.success, tone: "success" }); return result; }, undefined); return (
{confirm && ( {confirm.title} {confirm.description} form.current?.requestSubmit()}> {confirm.label} )}
); }