"use client"; // Pflege der globalen Allergen-/Zusatzstofflisten, die unterhalb // der öffentlichen Speisekarte angezeigt werden. import { useCallback, useEffect, useMemo, useState } from "react"; import { createClient } from "@/lib/supabase/client"; import { formatMessage } from "@/lib/i18n/shared"; import { localized } from "@/lib/types"; import type { CodeItem } from "@/lib/types"; import { useDict, useLocale } from "@/components/i18n/LocaleProvider"; export default function CodeListManager({ table, }: { table: "allergens" | "additives"; }) { const supabase = useMemo(() => createClient(), []); const dict = useDict(); const locale = useLocale(); const title = table === "allergens" ? dict.codeList.allergensTitle : dict.codeList.additivesTitle; const codeLabel = table === "allergens" ? dict.codeList.allergenCodeLabel : dict.codeList.additiveCodeLabel; const [items, setItems] = useState([]); const [editing, setEditing] = useState<{ original: string | null; // code vor der Bearbeitung, null = neu code: string; name: string; nameEn: string; namePl: string; } | null>(null); const [error, setError] = useState(null); const [translateState, setTranslateState] = useState< "idle" | "busy" | "done" | "unavailable" >("idle"); const load = useCallback(async () => { const { data, error } = await supabase.from(table).select("*").order("sort"); if (error) setError(formatMessage(dict.codeList.loadError, { message: error.message })); else setItems(data as CodeItem[]); }, [supabase, table, dict]); useEffect(() => { load(); }, [load]); async function save(e: React.FormEvent) { e.preventDefault(); if (!editing) return; setError(null); const code = editing.code.trim(); const name = editing.name.trim(); if (!code || !name) return; const payload = { code, name, name_en: editing.nameEn.trim() || null, name_pl: editing.namePl.trim() || null, }; let dbError; if (editing.original) { ({ error: dbError } = await supabase .from(table) .update(payload) .eq("code", editing.original)); } else { const maxSort = items.reduce((m, i) => Math.max(m, i.sort), 0); ({ error: dbError } = await supabase .from(table) .insert({ ...payload, sort: maxSort + 1 })); } if (dbError) { setError( /duplicate key/i.test(dbError.message) ? formatMessage(dict.codeList.duplicateCode, { code }) : formatMessage(dict.codeList.saveError, { message: dbError.message }) ); return; } setEditing(null); await load(); } async function remove(item: CodeItem) { if ( !window.confirm( formatMessage(dict.codeList.confirmDelete, { code: item.code, name: item.name }) ) ) return; const { error } = await supabase.from(table).delete().eq("code", item.code); if (error) setError(formatMessage(dict.codeList.deleteError, { message: error.message })); await load(); } async function autoTranslate() { if (!editing || !editing.name.trim()) return; setTranslateState("busy"); setError(null); try { const res = await fetch("/api/translate", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ table, id: editing.original, text: editing.name.trim(), }), }); const data = await res.json(); if (!res.ok) throw new Error(data?.error ?? `Fehler (${res.status})`); if (data.configured === false) { setTranslateState("unavailable"); return; } setEditing((prev) => prev ? { ...prev, nameEn: data.en ?? prev.nameEn, namePl: data.pl ?? prev.namePl } : prev ); setTranslateState("done"); } catch (err) { setError(err instanceof Error ? err.message : String(err)); setTranslateState("idle"); } } return (

{title}

{error && (

{error}

)} {editing && (
setEditing({ ...editing, code: e.target.value })} required />
setEditing({ ...editing, name: e.target.value })} required />
setEditing({ ...editing, nameEn: e.target.value })} />
setEditing({ ...editing, namePl: e.target.value })} />
{translateState === "done" && ( {dict.dishManager.translated} )} {translateState === "unavailable" && ( {dict.dishManager.translateUnavailable} )}
)}
    {items.map((item) => (
  • {item.code} –{" "} {localized(item, locale)}
  • ))} {items.length === 0 && (
  • {dict.codeList.empty}
  • )}
); }