Files
craftvia/src/components/emergency/review-form.tsx
T
msolarczekandClaude Opus 5 dece70c129 L8 Notdienst: Backoffice-Nachbearbeitung /work-orders/emergency-review
Liste und Detail mit fünf Prüfschritten (Kunde, Objekt, Auftrag, Bericht,
Abrechnung), Navigationseintrag, Dashboard-Kachel verlinkt auf die Prüfung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 13:12:33 +02:00

58 lines
2.0 KiB
TypeScript

"use client";
import { useActionState } from "react";
import { useTranslations } from "next-intl";
import { AlertCircle, CheckCircle2 } from "lucide-react";
import type { ActionState } from "@/server/api/action-state";
import { buttonCls } from "@/components/work-orders/action-form";
import { cn } from "@/lib/utils";
type Action = (prev: ActionState, fd: FormData) => Promise<ActionState>;
/** Form bound to an emergency review server action; errors are translated codes (emergency.review.errors.*). */
export function ReviewForm({
action,
children,
submitLabel,
successText,
variant = "default",
className,
}: {
action: Action;
children?: React.ReactNode;
submitLabel: string;
successText?: string;
variant?: "primary" | "default" | "outline" | "danger";
className?: string;
}) {
const [state, formAction, pending] = useActionState(action, { status: "idle" } as ActionState);
const t = useTranslations("emergency.review");
let errorText = "";
if (state.status === "error") {
const reasonKey = state.reason ? `errors.${state.reason}` : "";
errorText = reasonKey && t.has(reasonKey) ? t(reasonKey) : t.has(`errors.${state.code}`) ? t(`errors.${state.code}`) : t("errors.generic");
}
return (
<form action={formAction} className={cn("space-y-3", className)}>
{children}
{state.status === "error" && (
<p role="alert" className="flex items-center gap-2 rounded-lg border border-[var(--risk)] bg-card px-3 py-2 text-sm font-semibold text-[var(--risk)]">
<AlertCircle className="size-4 shrink-0" aria-hidden />
{errorText}
</p>
)}
{state.status === "ok" && successText && (
<p role="status" className="flex items-center gap-2 text-sm text-[var(--ok)]">
<CheckCircle2 className="size-4" aria-hidden />
{successText}
</p>
)}
<button type="submit" disabled={pending} className={buttonCls(variant)}>
{submitLabel}
</button>
</form>
);
}