"use client"; import { FormEvent, useCallback, useEffect, useMemo, useState } from "react"; import Link from "next/link"; import { AdminPageHeader, Banner, Button, EmptyState, Modal, StatusBadge, TextareaField, } from "@/components/admin/controls"; import type { CommercialAdminResourceDef } from "../admin/resources"; import { createAdminRegistryItem, deleteAdminRegistryItem, listAdminRegistry, type RegistryRecord, updateAdminRegistryItem, } from "../adapters/admin"; import type { AdapterResult } from "../types"; function recordLabel(item: RegistryRecord, resource: CommercialAdminResourceDef): string { const name = item[resource.nameField]; if (typeof name === "string" && name) return name; const code = item[resource.codeField]; if (typeof code === "string" || typeof code === "number") return String(code); return "—"; } function recordCode(item: RegistryRecord, resource: CommercialAdminResourceDef): string { const code = item[resource.codeField]; return code == null ? "" : String(code); } function defaultCreateJson(resource: CommercialAdminResourceDef): string { const seed: RegistryRecord = { [resource.codeField]: "", [resource.nameField]: "", status: "draft", }; if (resource.key === "products") { seed.visibility = "public"; seed.launch_strategy = "route"; seed.default_route = ""; seed.product_slug = ""; seed.display_order = 0; } if (resource.key === "trial-rules") { seed.duration_days = 14; seed.grace_period_days = 3; seed.usage_limits = {}; seed.feature_limits = {}; seed.expiration_behavior = "lock"; seed.auto_disable = true; } if (resource.key === "policies") { seed.policy_kind = "domain"; seed.effect = "deny"; seed.parameters = { custom_domain_allowed: false, subdomain_only: true, ssl_ready: false, dns_instructions: [], }; } return JSON.stringify(seed, null, 2); } export function AdminRegistryManager({ resource }: { resource: CommercialAdminResourceDef }) { const [result, setResult] = useState | null>(null); const [error, setError] = useState(""); const [msg, setMsg] = useState(""); const [loading, setLoading] = useState(true); const [createOpen, setCreateOpen] = useState(false); const [editItem, setEditItem] = useState(null); const [jsonBody, setJsonBody] = useState(""); const [busy, setBusy] = useState(false); const load = useCallback(async () => { setLoading(true); setError(""); const r = await listAdminRegistry(resource); setResult(r); if (r.availability === "unavailable" || r.availability === "permission_denied" || r.availability === "error") { setError(r.message || "رجیستری در دسترس نیست"); } setLoading(false); }, [resource]); useEffect(() => { void load(); }, [load]); const items = result?.data ?? []; const openCreate = () => { setJsonBody(defaultCreateJson(resource)); setCreateOpen(true); setMsg(""); setError(""); }; const openEdit = (item: RegistryRecord) => { setEditItem(item); setJsonBody(JSON.stringify(item, null, 2)); setMsg(""); setError(""); }; const submitCreate = async (e: FormEvent) => { e.preventDefault(); setBusy(true); setError(""); try { const body = JSON.parse(jsonBody) as RegistryRecord; const res = await createAdminRegistryItem(resource, body); if (!res.ok) { setError(res.message); return; } setCreateOpen(false); setMsg("ثبت شد — tenant UI از همین رجیستری می‌خواند."); await load(); } catch { setError("JSON نامعتبر است"); } finally { setBusy(false); } }; const submitEdit = async (e: FormEvent) => { e.preventDefault(); if (!editItem) return; setBusy(true); setError(""); try { const body = JSON.parse(jsonBody) as RegistryRecord; const code = recordCode(editItem, resource) || String(body[resource.codeField] ?? ""); if (!code) { setError("کد رکورد مشخص نیست"); return; } const res = await updateAdminRegistryItem(resource, code, body); if (!res.ok) { setError(res.message); return; } setEditItem(null); setMsg("به‌روزرسانی شد — تغییرات بلافاصله در tenant قابل مشاهده است."); await load(); } catch { setError("JSON نامعتبر است"); } finally { setBusy(false); } }; const onDelete = async (item: RegistryRecord) => { const code = recordCode(item, resource); if (!code) return; if (!window.confirm(`حذف ${code}؟`)) return; setBusy(true); const res = await deleteAdminRegistryItem(resource, code); if (!res.ok) setError(res.message); else { setMsg("حذف شد"); await load(); } setBusy(false); }; const availabilityHint = useMemo(() => { if (!result) return null; if (result.availability === "unavailable") { return "Core Commercial API هنوز در دسترس نیست — بدون داده جعلی."; } if (result.availability === "empty") return "رجیستری خالی است."; if (result.availability === "permission_denied") return "دسترسی تجاری ندارید."; return null; }, [result]); return (
} /> {error ? {error} : null} {msg ? {msg} : null} {availabilityHint ? {availabilityHint} : null}

{resource.listPath}

{loading ? ( ) : items.length === 0 ? ( ) : (
{items.map((item, idx) => { const code = recordCode(item, resource) || String(idx); const status = typeof item.status === "string" ? item.status : "—"; return ( ); })}
نام کد وضعیت عملیات
{recordLabel(item, resource)} {code}
)}
setCreateOpen(false)} title={`ثبت ${resource.label}`}>
void submitCreate(e)} className="space-y-4">

بدنه JSON مستقیم به API رجیستری ارسال می‌شود — هیچ کاتالوگ ثابتی در frontend نیست.

setEditItem(null)} title={`ویرایش ${resource.label}`} >
void submitEdit(e)} className="space-y-4">
); }