"use client"; import React, { useEffect, useState } from "react"; import { AdminHeader, AlertBanner, Modal, ConfirmDeleteModal, getClientToken } from "../_components/AdminComponents"; import { adminGetStandardsBodies, adminCreateStandardsBody, adminUpdateStandardsBody, adminDeleteStandardsBody, adminCreateStandardDocument, adminUpdateStandardDocument, adminDeleteStandardDocument, AdminStandardsBody, AdminStandardDocument, } from "../../../lib/adminApi"; const DOC_STATUSES = ["IS", "TS", "TR", "CDV", "WDTR", "InProgress"]; export default function AdminStandardizationPage() { const [bodies, setBodies] = useState([]); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); const [successMsg, setSuccessMsg] = useState(null); // Body Modal State const [isBodyModalOpen, setIsBodyModalOpen] = useState(false); const [editingBody, setEditingBody] = useState(null); const [bodyForm, setBodyForm] = useState({ org: "", full_name: "", scope: "international" as "international" | "domestic", period: "", role: "", display_order: 0, }); // Document Modal State const [isDocModalOpen, setIsDocModalOpen] = useState(false); const [targetBodyId, setTargetBodyId] = useState(null); const [editingDoc, setEditingDoc] = useState(null); const [docForm, setDocForm] = useState({ wg: "", project_name: "", title: "", doc_ref: "", status: "IS" as "IS" | "TS" | "TR" | "CDV" | "WDTR" | "InProgress", published_at: "", }); const [isSubmitting, setIsSubmitting] = useState(false); const [deletingBodyId, setDeletingBodyId] = useState(null); const [deletingDocId, setDeletingDocId] = useState(null); const loadBodies = async () => { try { setIsLoading(true); setError(null); const data = await adminGetStandardsBodies(); setBodies(data); } catch (err: any) { setError(err?.message || "Failed to load standards bodies."); } finally { setIsLoading(false); } }; useEffect(() => { loadBodies(); }, []); // Body Actions const handleOpenBodyCreate = () => { setEditingBody(null); setBodyForm({ org: "", full_name: "", scope: "international", period: "", role: "", display_order: bodies.length + 1, }); setIsBodyModalOpen(true); }; const handleOpenBodyEdit = (b: AdminStandardsBody) => { setEditingBody(b); setBodyForm({ org: b.org, full_name: b.full_name, scope: b.scope, period: b.period, role: b.role || "", display_order: b.display_order, }); setIsBodyModalOpen(true); }; const handleBodySubmit = async (e: React.FormEvent) => { e.preventDefault(); const token = getClientToken(); if (!token) return; const payload = { org: bodyForm.org.trim(), full_name: bodyForm.full_name.trim(), scope: bodyForm.scope, period: bodyForm.period.trim(), role: bodyForm.role.trim() || undefined, display_order: Number(bodyForm.display_order) || 0, }; setIsSubmitting(true); setError(null); try { if (editingBody) { await adminUpdateStandardsBody(token, editingBody.id, payload); setSuccessMsg(`Standards Body "${payload.org}" updated.`); } else { await adminCreateStandardsBody(token, payload); setSuccessMsg(`Standards Body "${payload.org}" created.`); } setIsBodyModalOpen(false); await loadBodies(); } catch (err: any) { setError(err?.message || "Failed to save standards body."); } finally { setIsSubmitting(false); } }; const handleConfirmDeleteBody = async () => { if (!deletingBodyId) return; const token = getClientToken(); if (!token) return; setIsSubmitting(true); try { await adminDeleteStandardsBody(token, deletingBodyId); setSuccessMsg("Standards body and associated documents deleted successfully (Cascade)."); setDeletingBodyId(null); await loadBodies(); } catch (err: any) { setError(err?.message || "Failed to delete standards body."); } finally { setIsSubmitting(false); } }; // Doc Actions const handleOpenDocCreate = (bodyId: number) => { setTargetBodyId(bodyId); setEditingDoc(null); setDocForm({ wg: "", project_name: "", title: "", doc_ref: "", status: "IS", published_at: "", }); setIsDocModalOpen(true); }; const handleOpenDocEdit = (d: AdminStandardDocument) => { setTargetBodyId(d.body_id); setEditingDoc(d); setDocForm({ wg: d.wg, project_name: d.project_name, title: d.title, doc_ref: d.doc_ref, status: d.status, published_at: d.published_at || "", }); setIsDocModalOpen(true); }; const handleDocSubmit = async (e: React.FormEvent) => { e.preventDefault(); const token = getClientToken(); if (!token || !targetBodyId) return; const payload = { wg: docForm.wg.trim(), project_name: docForm.project_name.trim(), title: docForm.title.trim(), doc_ref: docForm.doc_ref.trim(), status: docForm.status, published_at: docForm.published_at.trim() || undefined, }; setIsSubmitting(true); setError(null); try { if (editingDoc) { await adminUpdateStandardDocument(token, editingDoc.id, payload); setSuccessMsg(`Document "${payload.doc_ref}" updated.`); } else { await adminCreateStandardDocument(token, targetBodyId, payload); setSuccessMsg(`Document "${payload.doc_ref}" added.`); } setIsDocModalOpen(false); await loadBodies(); } catch (err: any) { setError(err?.message || "Failed to save standard document."); } finally { setIsSubmitting(false); } }; const handleConfirmDeleteDoc = async () => { if (!deletingDocId) return; const token = getClientToken(); if (!token) return; setIsSubmitting(true); try { await adminDeleteStandardDocument(token, deletingDocId); setSuccessMsg("Standard document deleted successfully."); setDeletingDocId(null); await loadBodies(); } catch (err: any) { setError(err?.message || "Failed to delete document."); } finally { setIsSubmitting(false); } }; return (
+ Add Standards Body } /> {error && setError(null)} />} {successMsg && setSuccessMsg(null)} />} {isLoading ? (
Loading standardization records...
) : bodies.length === 0 ? (
No standards bodies recorded. Click "+ Add Standards Body" to get started.
) : (
{bodies.map((body) => { const allDocs = body.projects?.flatMap((p) => p.documents) || []; return (
{/* Body Header Bar */}
{body.org} ({body.full_name}) {body.scope}
Period: {body.period} {body.role && `· Role: ${body.role}`} · {allDocs.length} Total Documents
{/* Documents Table */} {allDocs.length === 0 ? ( ) : ( allDocs.map((d) => ( )) )}
Ref / Status Title & WG Project Group Date Actions
No documents added for this standards body.
{d.doc_ref}
{d.status}
{d.title}
{d.wg}
{d.project_name} {d.published_at || "—"}
); })}
)} {/* Body Modal */} setIsBodyModalOpen(false)} >
setBodyForm({ ...bodyForm, org: e.target.value })} placeholder="e.g. ISO/IEC" required className="w-full px-3 py-2 text-sm border border-line rounded bg-ivory text-ink focus:outline-none focus:ring-1 focus:ring-cobalt" />
setBodyForm({ ...bodyForm, full_name: e.target.value })} placeholder="e.g. International Organization for Standardization" required className="w-full px-3 py-2 text-sm border border-line rounded bg-ivory text-ink focus:outline-none focus:ring-1 focus:ring-cobalt" />
setBodyForm({ ...bodyForm, period: e.target.value })} placeholder="e.g. 2020 - Present" required className="w-full px-3 py-2 text-sm border border-line rounded bg-ivory text-ink focus:outline-none focus:ring-1 focus:ring-cobalt" />
setBodyForm({ ...bodyForm, role: e.target.value })} placeholder="e.g. Project Leader" className="w-full px-3 py-2 text-sm border border-line rounded bg-ivory text-ink focus:outline-none focus:ring-1 focus:ring-cobalt" />
{/* Doc Modal */} setIsDocModalOpen(false)} >
setDocForm({ ...docForm, doc_ref: e.target.value })} placeholder="e.g. ISO/IEC 63246-1" required className="w-full px-3 py-2 text-sm border border-line rounded bg-ivory text-ink focus:outline-none focus:ring-1 focus:ring-cobalt" />
setDocForm({ ...docForm, title: e.target.value })} placeholder="e.g. Part 1: Architecture and functional model" required className="w-full px-3 py-2 text-sm border border-line rounded bg-ivory text-ink focus:outline-none focus:ring-1 focus:ring-cobalt" />
setDocForm({ ...docForm, wg: e.target.value })} placeholder="e.g. ISO/IEC JTC 1/SC 29/WG 11" required className="w-full px-3 py-2 text-sm border border-line rounded bg-ivory text-ink focus:outline-none focus:ring-1 focus:ring-cobalt" />
setDocForm({ ...docForm, project_name: e.target.value })} placeholder="e.g. CCIS (Camera Communications)" required className="w-full px-3 py-2 text-sm border border-line rounded bg-ivory text-ink focus:outline-none focus:ring-1 focus:ring-cobalt" />
setDocForm({ ...docForm, published_at: e.target.value })} placeholder="e.g. 2023-08" className="w-full px-3 py-2 text-sm border border-line rounded bg-ivory text-ink focus:outline-none focus:ring-1 focus:ring-cobalt" />
setDeletingBodyId(null)} onConfirm={handleConfirmDeleteBody} isSubmitting={isSubmitting} title="Delete Standards Body (Cascade Warning)" description="Are you sure you want to delete this standards body? All standard documents under this body will also be permanently deleted (Database Cascade)." /> setDeletingDocId(null)} onConfirm={handleConfirmDeleteDoc} isSubmitting={isSubmitting} title="Delete Standard Document" description="Are you sure you want to delete this standard document?" />
); }