"use client"; import { useCallback, useEffect, useState } from "react"; import { useRouter } from "next/navigation"; import { formatMessage } from "@/lib/i18n/shared"; import { DEFAULT_COLORS, faviconUrl, logoUrl } from "@/lib/types"; import { useDict } from "@/components/i18n/LocaleProvider"; type AssetKind = "logo" | "favicon"; export default function DesignEditor() { const router = useRouter(); const dict = useDict(); const colorLabels: Record = { primary: dict.designEditor.colorPrimary, primaryDark: dict.designEditor.colorPrimaryDark, accent: dict.designEditor.colorAccent, headerText: dict.designEditor.colorHeaderText, rowBg: dict.designEditor.colorRowBg, rowBgAlt: dict.designEditor.colorRowBgAlt, addBtn: dict.designEditor.colorAddBtn, deleteBtn: dict.designEditor.colorDeleteBtn, }; const [colors, setColors] = useState>(DEFAULT_COLORS); const [logoPath, setLogoPath] = useState(null); const [faviconPath, setFaviconPath] = useState(null); const [error, setError] = useState(null); const [info, setInfo] = useState(null); const [busy, setBusy] = useState(false); const load = useCallback(async () => { const res = await fetch("/api/settings"); if (!res.ok) { setError(formatMessage(dict.designEditor.loadError, { message: String(res.status) })); return; } const data = await res.json(); setColors({ ...DEFAULT_COLORS, ...(data?.colors ?? {}) }); setLogoPath(data?.logo_path ?? null); setFaviconPath(data?.favicon_path ?? null); }, [dict]); useEffect(() => { load(); }, [load]); async function saveColors() { setBusy(true); setError(null); setInfo(null); const res = await fetch("/api/settings", { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ colors }), }); if (!res.ok) setError(formatMessage(dict.designEditor.saveError, { message: String(res.status) })); else { setInfo(dict.designEditor.colorsSaved); router.refresh(); } setBusy(false); } async function resetColors() { setColors(DEFAULT_COLORS); } async function uploadAsset(kind: AssetKind, e: React.ChangeEvent) { const file = e.target.files?.[0]; e.target.value = ""; if (!file) return; if (!/^image\//.test(file.type)) { setError(dict.designEditor.invalidImage); return; } setBusy(true); setError(null); setInfo(null); const formData = new FormData(); formData.append("kind", kind); formData.append("file", file); const res = await fetch("/api/admin/branding", { method: "POST", body: formData }); if (!res.ok) { const data = await res.json().catch(() => ({})); setError( formatMessage(dict.designEditor.uploadError, { message: data.error ?? String(res.status), }) ); setBusy(false); return; } const { path } = await res.json(); if (kind === "logo") setLogoPath(path); else setFaviconPath(path); setInfo(kind === "logo" ? dict.designEditor.logoUpdated : dict.designEditor.faviconUpdated); router.refresh(); setBusy(false); } async function removeAsset(kind: AssetKind) { const path = kind === "logo" ? logoPath : faviconPath; if (!path) return; if ( !window.confirm( kind === "logo" ? dict.designEditor.confirmRemoveLogo : dict.designEditor.confirmRemoveFavicon ) ) return; setBusy(true); setError(null); const res = await fetch("/api/admin/branding", { method: "DELETE", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ kind }), }); if (!res.ok) { setError(formatMessage(dict.designEditor.saveError, { message: String(res.status) })); } else { if (kind === "logo") setLogoPath(null); else setFaviconPath(null); setInfo(kind === "logo" ? dict.designEditor.logoRemoved : dict.designEditor.faviconRemoved); router.refresh(); } setBusy(false); } const currentLogo = logoUrl(logoPath); const currentFavicon = faviconUrl(faviconPath); return (

{dict.designEditor.title}

{error && (

{error}

)} {info &&

{info}

}

{dict.designEditor.logoTitle}

{dict.designEditor.logoHint}

{currentLogo ? ( // eslint-disable-next-line @next/next/no-img-element Logo ) : (

{dict.designEditor.logoNone}

)}
{currentLogo && ( )}

{dict.designEditor.faviconTitle}

{dict.designEditor.faviconHint}

{currentFavicon ? ( // eslint-disable-next-line @next/next/no-img-element Favicon ) : (

{dict.designEditor.faviconNone}

)}
{currentFavicon && ( )}

{dict.designEditor.colorsTitle}

{Object.entries(colorLabels).map(([key, label]) => ( ))}
); }