"use client"; import { useEffect, useState } from "react"; import { useRouter } from "next/navigation"; import Link from "next/link"; import Shell from "../../components/shell"; import LogoImg from "../../components/logo-img"; import { validateVoucher } from "@/lib/vouchers"; import { ALLOWED_REMINDER_DAYS, DEFAULT_REMINDER_DAYS } from "@/lib/reminders"; import type { LogoCandidate } from "@/lib/logo"; // Erweiterbar für Task 5 (Kontakte): zusätzliches Feld contactIds + // ohne bestehende Felder anzufassen — Felder als Konfiguration belassen. const FIELDS = [ { name: "name", label: "Name", type: "text", placeholder: "z. B. Therme Erding" }, { name: "anbieter", label: "Anbieter", type: "text", placeholder: "z. B. Therme Erding" }, { name: "wertCents", label: "Wert (Cent)", type: "number", placeholder: "5000" }, { name: "restCents", label: "Rest (Cent, leer = Wert)", type: "number", placeholder: "" }, { name: "ablaufdatum", label: "Ablaufdatum", type: "date", placeholder: "" }, { name: "codeText", label: "Code", type: "text", placeholder: "Code oder Nummer" }, { name: "kategorie", label: "Kategorie", type: "text", placeholder: "z. B. Erlebnis" }, { name: "notiz", label: "Notiz", type: "text", placeholder: "Optionale Notiz" }, ] as const; const inputClass = "mt-1.5 h-11 w-full rounded-field border border-line bg-white px-3.5 text-sm text-ink placeholder:text-muted/60"; export default function NewVoucherPage() { const router = useRouter(); const [values, setValues] = useState>({}); const [errors, setErrors] = useState([]); const [serverError, setServerError] = useState(""); const [contacts, setContacts] = useState<{ id: number; name: string }[]>([]); const [contactIds, setContactIds] = useState([]); const [members, setMembers] = useState<{ id: number; name: string }[]>([]); const [memberId, setMemberId] = useState(""); const [reminderDays, setReminderDays] = useState([...DEFAULT_REMINDER_DAYS]); const [candidates, setCandidates] = useState([]); const [logoSearching, setLogoSearching] = useState(false); const [logoError, setLogoError] = useState(""); const [logoSearched, setLogoSearched] = useState(false); const [selectedLogo, setSelectedLogo] = useState(null); useEffect(() => { fetch("/api/contacts") .then((r) => (r.ok ? r.json() : [])) .then(setContacts) .catch(() => {}); fetch("/api/members") .then((r) => (r.ok ? r.json() : [])) .then(setMembers) .catch(() => {}); }, []); function set(name: string, value: string) { setValues((v) => ({ ...v, [name]: value })); } function toggleDay(day: number) { setReminderDays((days) => (days.includes(day) ? days.filter((d) => d !== day) : [...days, day].sort((a, b) => b - a))); } async function searchLogos() { const q = (values.anbieter ?? "").trim(); if (!q) { setLogoError("Bitte zuerst einen Anbieter eintragen."); return; } setLogoSearching(true); setLogoError(""); setLogoSearched(false); try { const res = await fetch(`/api/logos/search?q=${encodeURIComponent(q)}`); const data = await res.json().catch(() => null); if (!res.ok) { setLogoError(data?.error ?? "Suche fehlgeschlagen"); setCandidates([]); } else { setCandidates(Array.isArray(data) ? data : []); if (!Array.isArray(data) || data.length === 0) setLogoError("Kein Logo gefunden."); } } catch { setLogoError("Suche fehlgeschlagen"); setCandidates([]); } finally { setLogoSearching(false); setLogoSearched(true); } } 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, reminderDays, providerDomain: selectedLogo?.domain ?? null, memberId: memberId === "" ? null : Number(memberId) }), }); 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 ( ← Zurück

Gutschein anlegen

Alle Angaben lassen sich später noch ändern.

{members.length === 0 ? (

Noch keine Haushaltsmitglieder. Lege sie unter Einstellungen an.

) : ( )}
{FIELDS.map((f) => (
set(f.name, e.target.value)} aria-invalid={errors.includes(f.name)} className={`${inputClass} ${errors.includes(f.name) ? "border-danger" : ""}`} /> {errors.includes(f.name) && (

Bitte prüfe dieses Feld.

)}
))}

Anbieterlogo

{selectedLogo ? (

{selectedLogo.name}

{selectedLogo.domain}

) : ( <>

Logo anhand des Anbieternamens suchen und bestätigen.

{logoError &&

{logoError}

} {logoSearched && !logoError && candidates.length > 0 && (
    {candidates.map((c) => (
  • ))}
)} )}
Erinnerung (Tage vorher)

Nichts ausgewählt bedeutet keine Erinnerung.

{ALLOWED_REMINDER_DAYS.map((day) => { const checked = reminderDays.includes(day); return ( ); })}

Empfänger

Wer soll an diesen Gutschein erinnert werden?

{contacts.length === 0 ? (

Noch keine Kontakte. Lege sie unter Kontakte an.

) : (
    {contacts.map((c) => (
  • ))}
)}
{serverError && (

{serverError}

)}
); }