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>
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
"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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user