'use client'; import { useMemo, useState } from 'react'; import Link from 'next/link'; import { useQuery } from '@tanstack/react-query'; import { ChevronDown, ChevronRight, FileText, Plus } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { StatusPill, type StatusPillStatus } from '@/components/ui/status-pill'; import { EmptyState } from '@/components/ui/empty-state'; import { PageHeader } from '@/components/shared/page-header'; import { usePaginatedQuery } from '@/hooks/use-paginated-query'; import { useRealtimeInvalidation } from '@/hooks/use-realtime-invalidation'; import { apiFetch } from '@/lib/api/client'; import { cn } from '@/lib/utils'; import { documentsHubTabs, type DocumentsHubTab } from '@/lib/validators/documents'; interface HubDoc { id: string; documentType: string; title: string; status: string; createdAt: string; signers?: Array<{ id: string; signerEmail: string; signerName: string; status: string }>; } interface HubCounts { all: number; eoi_queue: number; awaiting_them: number; awaiting_me: number; completed: number; expired: number; } const TAB_LABELS: Record = { all: 'All', eoi_queue: 'EOI queue', awaiting_them: 'Awaiting them', awaiting_me: 'Awaiting me', completed: 'Completed', expired: 'Expired', }; const TYPE_LABELS: Record = { eoi: 'EOI', contract: 'Contract', nda: 'NDA', reservation_agreement: 'Reservation Agreement', welcome_letter: 'Welcome Letter', handover_checklist: 'Handover', acknowledgment: 'Acknowledgment', correspondence: 'Correspondence', other: 'Other', }; const STATUS_PILL_MAP: Record = { draft: 'draft', sent: 'sent', partially_signed: 'partial', completed: 'completed', signed: 'signed', expired: 'expired', cancelled: 'cancelled', rejected: 'rejected', }; interface DocumentsHubProps { portSlug: string; } export function DocumentsHub({ portSlug }: DocumentsHubProps) { const [tab, setTab] = useState('all'); const [search, setSearch] = useState(''); const [typeFilter, setTypeFilter] = useState('all'); const [signatureOnly, setSignatureOnly] = useState(true); const [expandedDocId, setExpandedDocId] = useState(null); const queryParams = useMemo(() => { const params = new URLSearchParams(); params.set('tab', tab); if (search) params.set('search', search); if (typeFilter && typeFilter !== 'all') params.set('documentType', typeFilter); if (signatureOnly) params.set('signatureOnly', 'true'); return params; }, [tab, search, typeFilter, signatureOnly]); const { data: documents, isLoading } = usePaginatedQuery({ queryKey: ['documents', 'hub', queryParams.toString()], endpoint: `/api/v1/documents?${queryParams.toString()}`, filterDefinitions: [], }); const { data: countsResp } = useQuery<{ data: HubCounts }>({ queryKey: ['documents', 'hub-counts'], queryFn: () => apiFetch<{ data: HubCounts }>('/api/v1/documents/hub-counts'), staleTime: 30_000, }); useRealtimeInvalidation({ 'document:created': [['documents']], 'document:updated': [['documents']], 'document:deleted': [['documents']], 'document:sent': [['documents']], 'document:completed': [['documents']], 'document:expired': [['documents']], 'document:cancelled': [['documents']], 'document:rejected': [['documents']], 'document:signer:signed': [['documents']], }); const counts: HubCounts = countsResp?.data ?? { all: 0, eoi_queue: 0, awaiting_them: 0, awaiting_me: 0, completed: 0, expired: 0, }; const renderRow = (doc: HubDoc) => { const expanded = expandedDocId === doc.id; const totalSigners = doc.signers?.length ?? 0; const signedCount = doc.signers?.filter((s) => s.status === 'signed').length ?? 0; const pillStatus = STATUS_PILL_MAP[doc.status] ?? 'pending'; const isNonSignature = [ 'welcome_letter', 'handover_checklist', 'acknowledgment', 'correspondence', ].includes(doc.documentType); return (
  • {doc.title} {TYPE_LABELS[doc.documentType] ?? doc.documentType} {isNonSignature && doc.status === 'sent' ? 'Delivered' : doc.status.replace(/_/g, ' ')} {totalSigners > 0 ? `${signedCount}/${totalSigners} signed` : '—'} {new Date(doc.createdAt).toLocaleDateString('en-GB')}
    {expanded && doc.signers && doc.signers.length > 0 ? (
      {doc.signers.map((signer) => (
    • {signer.signerName} {signer.signerEmail}
      {signer.status}
    • ))}
    ) : null}
  • ); }; return (
    {counts.all}{' '} total {counts.awaiting_them} {' '} awaiting signers {counts.awaiting_me} {' '} awaiting you } actions={ } variant="gradient" /> setTab(v as DocumentsHubTab)}> {documentsHubTabs.map((t) => ( {TAB_LABELS[t]} {t !== 'all' && counts[t] > 0 ? ( {counts[t]} ) : null} ))}
    setSearch(e.target.value)} className="max-w-xs" />
    {isLoading ? (
      {[0, 1, 2, 3, 4].map((i) => (
    • ))}
    ) : documents.length === 0 ? ( } title={tab === 'all' ? 'No documents yet' : 'No documents match this view'} body={ tab === 'all' ? 'Create your first document to track signing across signers and watchers.' : 'Try a different tab or clear filters.' } actions={ tab === 'all' ? ( ) : null } /> ) : (
      {documents.map(renderRow)}
    )}
    ); }