"use client"; import Image from "next/image"; import { useRef, useState, type ChangeEvent } from "react"; import { useI18n } from "@/i18n/i18n-provider"; interface AdminImageListFieldProps { /** Formularfeld-Name, unter dem JEDES Bild als eigenes verstecktes Feld * mit demselben Namen mitgeschickt wird — der Server liest sie per * formData.getAll(name) (siehe strArray() in admin/actions/_shared.ts). */ name: string; label: string; initialValues: string[]; } /** * Mehrbild-Upload-Feld fuer Produkt-/Erntenfotos (admin/produkte, * admin/ernten). Laedt jede ausgewaehlte Datei sofort per fetch() an * app/api/admin/upload hoch und haengt den zurueckgegebenen Pfad ans lokale * Bilder-Array an; einzelne Bilder lassen sich per Knopfdruck wieder * entfernen. Das eigentliche Speichern passiert weiterhin ganz normal ueber * das umgebende
, dieses Feld reicht nur die fertigen Upload-Pfade * als wiederholte Hidden-Inputs hindurch. */ export function AdminImageListField({ name, label, initialValues }: AdminImageListFieldProps) { const { t } = useI18n(); const [images, setImages] = useState(initialValues); const [status, setStatus] = useState<"idle" | "uploading" | "error">("idle"); const [errorMessage, setErrorMessage] = useState(""); const inputRef = useRef(null); async function handleFileChange(event: ChangeEvent) { const file = event.target.files?.[0]; if (!file) return; setStatus("uploading"); setErrorMessage(""); try { const body = new FormData(); body.append("file", file); const response = await fetch("/api/admin/upload", { method: "POST", body }); const data: { path?: string; error?: string } = await response.json(); if (!response.ok || !data.path) { throw new Error(data.error ?? t.adminImageField.uploadError); } setImages((prev) => [...prev, data.path!]); setStatus("idle"); } catch (error: unknown) { setStatus("error"); setErrorMessage(error instanceof Error ? error.message : t.adminImageField.uploadError); } finally { if (inputRef.current) inputRef.current.value = ""; } } function removeAt(index: number) { setImages((prev) => prev.filter((_, i) => i !== index)); } return (
{label} {images.map((src, i) => ( // key bewusst ueber Index+Wert: Reihenfolge/Inhalt aendert sich nur // durch Hinzufuegen (ans Ende) oder Entfernen, beides hier stabil. ))} {images.length > 0 ? (
{images.map((src, i) => (
{/* Ueber next/image statt als rohes — siehe Begruendung in admin-image-field.tsx. Hier wiegt es schwerer, weil ein Produkt mehrere Bilder tragen kann und sonst JEDES davon in voller Groesse fuer eine Miniatur geladen wuerde. */}
))}
) : null}
{status === "uploading" ? (

{t.adminImageField.uploading}

) : null} {status === "error" ?

{errorMessage}

: null}
); }