"use client"; // Forms that run a server action and show its answer, with buttons that show when they're working. import { useActionState } from "react"; import { useFormStatus } from "react-dom"; import { Button } from "@/components/ui/button"; import type { ActionState } from "@/lib/actions"; import { cn } from "@/lib/utils"; type Action = (state: ActionState, form: FormData) => Promise; export function ActionForm({ action, fields = {}, className, children, }: { action: Action; /** Hidden fields sent with the form. */ fields?: Record; className?: string; children: React.ReactNode; }) { const [state, formAction] = useActionState(action, null); return (
{Object.entries(fields).map(([name, value]) => ( ))} {children} ); } export function FormMessage({ state }: { state: ActionState }) { if (state?.error) return {state.error}; if (state?.notice) return (

{state.notice}

); return null; } export function ErrorText({ children }: { children: React.ReactNode }) { return (

{children}

); } /** * A submit button that shows pending while its form is being sent. With name and value, it's one of several * buttons in the form, and only shows pending when it was the one pressed. With confirm, it asks first. */ export function SubmitButton({ name, value, pendingLabel, confirm, children, ...props }: Omit, "type" | "name" | "value" | "onClick"> & { name?: string; value?: string; pendingLabel?: string; confirm?: string; }) { const status = useFormStatus(); const mine = status.pending && (name === undefined || status.data?.get(name) === value); return ( ); }