Files
gutscheintracker/app/vouchers/new/page.tsx
T

113 lines
4.0 KiB
TypeScript

"use client";
import { useEffect, 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("");
const [contacts, setContacts] = useState<{ id: number; name: string }[]>([]);
const [contactIds, setContactIds] = useState<number[]>([]);
useEffect(() => {
fetch("/api/contacts")
.then((r) => (r.ok ? r.json() : []))
.then(setContacts)
.catch(() => {});
}, []);
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, contactIds }),
});
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>
))}
<section id="kontakte">
<h2 className="text-sm font-medium">Empfänger</h2>
{contacts.map((c) => (
<label key={c.id} className="flex items-center gap-2 text-sm">
<input
type="checkbox"
checked={contactIds.includes(c.id)}
onChange={(e) =>
setContactIds((ids) => (e.target.checked ? [...ids, c.id] : ids.filter((x) => x !== c.id)))
}
/>
{c.name}
</label>
))}
</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>
);
}