"use client"; import { useState } from "react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Badge } from "@/components/ui/badge"; import { Eye, EyeOff } from "lucide-react"; type SettingMeta = { value: string | null; isSecret: boolean; fromDb: boolean; }; type Group = { title: string; description: string; keys: readonly string[]; }; export function AdminSettingsForm({ group, settings, }: { group: Group; settings: Record; }) { const [values, setValues] = useState>(() => Object.fromEntries( group.keys.map((k) => [k, settings[k]?.isSecret && settings[k]?.value ? "" : (settings[k]?.value ?? "")]) ) ); const [showSecret, setShowSecret] = useState>({}); const [saving, setSaving] = useState(false); async function handleSave() { setSaving(true); try { const res = await fetch("/api/v1/admin/settings", { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify( Object.fromEntries(group.keys.map((k) => [k, values[k] || null])) ), }); if (!res.ok) throw new Error("Save failed"); toast.success("Settings saved"); } catch { toast.error("Failed to save settings"); } finally { setSaving(false); } } return (

{group.title}

{group.description}

{group.keys.map((key) => { const meta = settings[key]; const isSecret = meta?.isSecret ?? false; const fromDb = meta?.fromDb ?? false; const hasValue = !!meta?.value; const revealed = showSecret[key]; return (
{hasValue && ( {fromDb ? "DB override" : "from .env"} )} {!hasValue && ( not set )}
setValues((prev) => ({ ...prev, [key]: e.target.value }))} className="font-mono text-sm" /> {isSecret && ( )} {fromDb && ( )}
); })}
); }