90 lines
3.3 KiB
TypeScript
90 lines
3.3 KiB
TypeScript
"use client";
|
|
import { useState } from "react";
|
|
import { useRouter } from "next/navigation";
|
|
import { validateVoucher } from "@/lib/vouchers";
|
|
|
|
// Erweiterbar für Task 5 (Kontakte): zusätzliches Feld contactIds + <ContactSelect />
|
|
// ohne bestehende Felder anzufassen — Felder als Konfiguration belassen.
|
|
const FIELDS = [
|
|
{ name: "name", label: "Name", type: "text" },
|
|
{ name: "anbieter", label: "Anbieter", type: "text" },
|
|
{ name: "wertCents", label: "Wert (Cent)", type: "number" },
|
|
{ name: "restCents", label: "Rest (Cent, leer = Wert)", type: "number" },
|
|
{ name: "ablaufdatum", label: "Ablaufdatum", type: "date" },
|
|
{ name: "codeText", label: "Code", type: "text" },
|
|
{ name: "kategorie", label: "Kategorie", type: "text" },
|
|
{ name: "notiz", label: "Notiz", type: "text" },
|
|
] as const;
|
|
|
|
export default function NewVoucherPage() {
|
|
const router = useRouter();
|
|
const [values, setValues] = useState<Record<string, string>>({});
|
|
const [errors, setErrors] = useState<string[]>([]);
|
|
const [serverError, setServerError] = useState("");
|
|
|
|
function set(name: string, value: string) {
|
|
setValues((v) => ({ ...v, [name]: value }));
|
|
}
|
|
|
|
async function onSubmit(e: React.FormEvent) {
|
|
e.preventDefault();
|
|
const wertCents = Number(values.wertCents);
|
|
const restRaw = values.restCents;
|
|
const input = {
|
|
name: values.name ?? "",
|
|
anbieter: values.anbieter ?? "",
|
|
wertCents,
|
|
restCents: restRaw === undefined || restRaw === "" ? wertCents : Number(restRaw),
|
|
ablaufdatum: values.ablaufdatum || null,
|
|
codeText: values.codeText || null,
|
|
kategorie: values.kategorie || null,
|
|
notiz: values.notiz || null,
|
|
};
|
|
const errs = validateVoucher(input);
|
|
setErrors(errs);
|
|
if (errs.length) return;
|
|
const res = await fetch("/api/vouchers", {
|
|
method: "POST",
|
|
headers: { "content-type": "application/json" },
|
|
body: JSON.stringify(input),
|
|
});
|
|
if (!res.ok) {
|
|
const data = await res.json().catch(() => ({}));
|
|
setErrors(data.errors ?? []);
|
|
setServerError(data.errors ? "" : "Speichern fehlgeschlagen");
|
|
return;
|
|
}
|
|
const created = await res.json();
|
|
router.push(`/vouchers/${created.id}`);
|
|
}
|
|
|
|
return (
|
|
<main className="mx-auto max-w-xl space-y-4 p-6">
|
|
<h1 className="text-xl font-bold">Gutschein anlegen</h1>
|
|
<form onSubmit={onSubmit} className="space-y-3" noValidate>
|
|
{FIELDS.map((f) => (
|
|
<div key={f.name}>
|
|
<label htmlFor={f.name} className="block text-sm font-medium">
|
|
{f.label}
|
|
</label>
|
|
<input
|
|
id={f.name}
|
|
name={f.name}
|
|
type={f.type}
|
|
value={values[f.name] ?? ""}
|
|
onChange={(e) => set(f.name, e.target.value)}
|
|
className="mt-1 w-full rounded border px-3 py-2"
|
|
/>
|
|
{errors.includes(f.name) && <p className="mt-1 text-sm text-red-600">Ungültig: {f.name}</p>}
|
|
</div>
|
|
))}
|
|
{/* Task 5 hook: <section id="kontakte">…ContactSelect…</section> */}
|
|
{serverError && <p className="text-sm text-red-600">{serverError}</p>}
|
|
<button type="submit" className="rounded bg-black px-4 py-2 text-white">
|
|
Speichern
|
|
</button>
|
|
</form>
|
|
</main>
|
|
);
|
|
}
|