'use client'; import { useMemo } from 'react'; import { useQuery } from '@tanstack/react-query'; import Link from 'next/link'; import { apiFetch } from '../../../../lib/api'; import { useSession } from '../../../../components/session-provider'; interface Contact { id: string; fullName: string; email: string | null; phone: string | null; role: string | null; linkedinUrl: string | null; tags: string[]; } interface Organization { id: string; name: string; industry: string | null; country: string | null; website: string | null; employeeCount: number | null; } interface EnrichmentItem { id: string; name: string; type: 'contact' | 'organization'; missing: string[]; completeness: number; } export default function EnrichmentPage() { const { activeTenant } = useSession(); const tenantId = activeTenant?.tenantId ?? ''; const { data: contacts = [], isLoading: cL } = useQuery({ queryKey: ['enr-contacts', tenantId], queryFn: () => apiFetch('/v1/contacts?limit=500', { tenantId }), enabled: Boolean(tenantId), staleTime: 120_000, }); const { data: orgs = [], isLoading: oL } = useQuery({ queryKey: ['enr-orgs', tenantId], queryFn: () => apiFetch('/v1/organizations?limit=500', { tenantId }), enabled: Boolean(tenantId), staleTime: 120_000, }); const items = useMemo(() => { const contactItems: EnrichmentItem[] = contacts.map((c) => { const missing: string[] = []; if (!c.email) missing.push('email'); if (!c.phone) missing.push('telefon'); if (!c.role) missing.push('funcție'); if (!c.linkedinUrl) missing.push('LinkedIn'); const completeness = Math.round(((4 - missing.length) / 4) * 100); return { id: c.id, name: c.fullName, type: 'contact', missing, completeness }; }).filter((i) => i.completeness < 100); const orgItems: EnrichmentItem[] = orgs.map((o) => { const missing: string[] = []; if (!o.industry) missing.push('industrie'); if (!o.country) missing.push('țară'); if (!o.website) missing.push('website'); if (!o.employeeCount) missing.push('angajați'); const completeness = Math.round(((4 - missing.length) / 4) * 100); return { id: o.id, name: o.name, type: 'organization', missing, completeness }; }).filter((i) => i.completeness < 100); return [...contactItems, ...orgItems].sort((a, b) => a.completeness - b.completeness); }, [contacts, orgs]); const avgContact = useMemo(() => { if (!contacts.length) return 0; const scores = contacts.map((c) => { let filled = 0; if (c.email) filled++; if (c.phone) filled++; if (c.role) filled++; if (c.linkedinUrl) filled++; return (filled / 4) * 100; }); return Math.round(scores.reduce((a, b) => a + b, 0) / scores.length); }, [contacts]); const avgOrg = useMemo(() => { if (!orgs.length) return 0; const scores = orgs.map((o) => { let filled = 0; if (o.industry) filled++; if (o.country) filled++; if (o.website) filled++; if (o.employeeCount) filled++; return (filled / 4) * 100; }); return Math.round(scores.reduce((a, b) => a + b, 0) / scores.length); }, [orgs]); function clsCls(pct: number) { if (pct >= 75) return 'text-signal-ok'; if (pct >= 50) return 'text-warn'; return 'text-signal-danger'; } return (

Enrichment Date

{cL || oL ? 'Se calculează…' : `${items.length} entități cu date incomplete`}

{avgContact}%

Completitudine medie contacte

= 75 ? 'bg-signal-ok' : avgContact >= 50 ? 'bg-warn' : 'bg-signal-danger'}`} style={{ width: `${avgContact}%` }} />

{avgOrg}%

Completitudine medie organizații

= 75 ? 'bg-signal-ok' : avgOrg >= 50 ? 'bg-warn' : 'bg-signal-danger'}`} style={{ width: `${avgOrg}%` }} />

Surse de enrichment disponibile

📊 ClickHouse (147M+ rânduri date publice) 🔍 AnythingLLM (RAG pe documente interne) 🤖 Hermes (enrichment automat prin AI)

Enrichment-ul automat rulează periodic pe server. Această pagină afișează starea curentă.

{cL || oL ? (
Se calculează…
) : items.length === 0 ? (

Toate entitățile au date complete.

) : (

Entități de îmbogățit (sortat după completitudine crescătoare)

{items.slice(0, 50).map((item) => (
{item.completeness}%

{item.name}

{item.missing.map((m) => ( -{m} ))}
Editează →
))} {items.length > 50 && (

și alte {items.length - 50}

)}
)}
); }