'use client'; import React, { useEffect, useMemo, useState } from 'react'; import useContractManagement from '../hooks/useContractManagement'; import ConfirmActionModal from '../../../components/modals/ConfirmActionModal'; type Props = { refreshKey?: number; onEdit?: (id: string) => void; }; type ContractTemplate = { id: string; name: string; type?: string; contract_type?: string | null; user_type?: string | null; version: number; status: 'draft' | 'published' | 'archived' | string; updatedAt?: string; }; function Pill({ children, className }: { children: React.ReactNode; className: string }) { return {children}; } function StatusBadge({ status }: { status: string }) { const map: Record = { draft: 'bg-gray-100 text-gray-800 border border-gray-300', published: 'bg-green-100 text-green-800 border border-green-300', archived: 'bg-yellow-100 text-yellow-800 border border-yellow-300', }; const cls = map[status] || 'bg-blue-100 text-blue-800 border border-blue-300'; return {status}; } export default function ContractTemplateList({ refreshKey = 0, onEdit }: Props) { const [items, setItems] = useState([]); const [loading, setLoading] = useState(false); const [q, setQ] = useState(''); const [pendingToggle, setPendingToggle] = useState<{ id: string; target: 'active' | 'inactive'; message?: string; requiresConfirm: boolean } | null>(null) const { listTemplates, openPreviewInNewTab, generatePdf, downloadPdf, updateTemplateState, downloadBlobFile, } = useContractManagement(); const filtered = useMemo(() => { const term = q.trim().toLowerCase(); if (!term) return items; return items.filter((i) => i.name.toLowerCase().includes(term) || String(i.version).includes(term) || i.status.toLowerCase().includes(term)); }, [items, q]); const load = async () => { setLoading(true); try { const data = await listTemplates(); const mapped: ContractTemplate[] = data.map((x: any) => ({ id: x.id ?? x._id ?? x.uuid, name: x.name ?? 'Untitled', type: x.type, contract_type: x.contract_type ?? x.contractType ?? null, user_type: x.user_type ?? x.userType ?? null, version: Number(x.version ?? 1), status: (x.state === 'active') ? 'published' : 'draft', updatedAt: x.updatedAt ?? x.modifiedAt ?? x.updated_at, })); setItems(mapped); } catch { setItems((prev) => prev.length ? prev : [ { id: 'ex1', name: 'Sample Contract A', version: 1, status: 'draft', updatedAt: new Date().toISOString() }, { id: 'ex2', name: 'NDA Template', version: 3, status: 'published', updatedAt: new Date().toISOString() }, ]); } finally { setLoading(false); } }; useEffect(() => { load(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [refreshKey]); const executeToggleState = async (id: string, target: 'active' | 'inactive') => { try { const updated = await updateTemplateState(id, target as 'active' | 'inactive'); // Update clicked item immediately, then refresh list to reflect any auto-deactivations. setItems((prev) => prev.map((i) => i.id === id ? { ...i, status: updated.state === 'active' ? 'published' : 'draft' } : i)); await load(); } catch {} } const onToggleState = async (id: string, current: string) => { const target = current === 'published' ? 'inactive' : 'active'; if (target === 'active') { const tpl = items.find((i) => i.id === id); if (tpl) { const kind = tpl.type === 'contract' ? (tpl.contract_type === 'gdpr' ? 'GDPR' : tpl.contract_type === 'abo' ? 'ABO' : 'Contract') : tpl.type === 'invoice' ? 'Invoice' : 'Other'; setPendingToggle({ id, target, requiresConfirm: true, message: `This will deactivate other active ${kind} templates that apply to the same user type and language.`, }); return; } } await executeToggleState(id, target); }; const confirmToggleState = async () => { if (!pendingToggle) return await executeToggleState(pendingToggle.id, pendingToggle.target) setPendingToggle(null) } const onPreview = (id: string) => openPreviewInNewTab(id); const onGenPdf = async (id: string) => { try { const blob = await generatePdf(id, { preview: true }); downloadBlobFile(blob, `${id}-preview.pdf`); } catch {} }; const onDownloadPdf = async (id: string) => { try { const blob = await downloadPdf(id); downloadBlobFile(blob, `${id}.pdf`); } catch {} }; return ( Invoice templates always use user type "Both". Provide templates for each language (en/de). If no active invoice template matches, backend falls back to a text-only invoice. setQ(e.target.value)} className="w-full rounded-lg border border-gray-300 bg-white px-4 py-2 text-sm text-gray-900 outline-none focus:ring-2 focus:ring-indigo-500/50 shadow" /> {loading ? 'Loading…' : 'Refresh'} {filtered.map((c) => ( {c.name} {c.type && ( {c.type === 'contract' ? 'Contract' : c.type === 'invoice' ? 'Invoice' : 'Other'} )} {c.type === 'contract' && ( {c.contract_type === 'gdpr' ? 'GDPR' : c.contract_type === 'abo' ? 'ABO' : 'Contract'} )} {c.user_type && c.type !== 'invoice' && ( {c.user_type === 'personal' ? 'Personal' : c.user_type === 'company' ? 'Company' : 'Both'} )} Version {c.version}{c.updatedAt ? ` • Updated ${new Date(c.updatedAt).toLocaleString()}` : ''} {onEdit && ( onEdit(c.id)} className="px-3 py-1 text-xs rounded-lg bg-indigo-50 hover:bg-indigo-100 text-indigo-700 border border-indigo-200 transition" > Edit )} onPreview(c.id)} className="px-3 py-1 text-xs rounded-lg bg-gray-100 hover:bg-gray-200 text-gray-800 border border-gray-200 transition">Preview onGenPdf(c.id)} className="px-3 py-1 text-xs rounded-lg bg-gray-100 hover:bg-gray-200 text-gray-800 border border-gray-200 transition">PDF onDownloadPdf(c.id)} className="px-3 py-1 text-xs rounded-lg bg-gray-100 hover:bg-gray-200 text-gray-800 border border-gray-200 transition">Download onToggleState(c.id, c.status)} className={`px-3 py-1 text-xs rounded-lg font-semibold transition ${c.status === 'published' ? 'bg-red-100 hover:bg-red-200 text-red-700 border border-red-200' : 'bg-indigo-600 hover:bg-indigo-500 text-white border border-indigo-600'}`}> {c.status === 'published' ? 'Deactivate' : 'Activate'} ))} {!filtered.length && ( No contracts found. )} setPendingToggle(null)} onConfirm={confirmToggleState} /> ); }
{c.name}
Version {c.version}{c.updatedAt ? ` • Updated ${new Date(c.updatedAt).toLocaleString()}` : ''}