'use client'; import React, { useEffect, useState } from 'react'; import { Loader2, RefreshCw, FileText } from 'lucide-react'; type Match = { docId: string; docName: string; tenantId: string | null; tenantName: string | null; score: number; status: string; }; type SyncResult = { tenantName: string; status: string; upserted: number; docName: string | null; error?: string; }; export default function SuperhumanSyncPanel() { const [matches, setMatches] = useState([]); const [docCount, setDocCount] = useState(0); const [loading, setLoading] = useState(true); const [syncing, setSyncing] = useState(false); const [message, setMessage] = useState(null); const [results, setResults] = useState([]); async function loadStatus() { setLoading(true); setMessage(null); try { const r = await fetch('/api/admin/superhuman/sync', { cache: 'no-store' }); const j = await r.json(); if (!r.ok) throw new Error(j.error || 'No se pudo leer Superhuman'); setMatches(j.matches || []); setDocCount(j.docCount || 0); } catch (e) { setMessage(e instanceof Error ? e.message : 'Error'); } finally { setLoading(false); } } useEffect(() => { loadStatus(); }, []); async function runSync() { setSyncing(true); setMessage(null); try { const r = await fetch('/api/admin/superhuman/sync', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ exportBodies: true, maxEntries: 20 }), }); const j = await r.json(); if (!r.ok) throw new Error(j.error || 'Sync falló'); setResults(j.results || []); setMessage( `Sincronizados ${j.synced}/${(j.results || []).length} tenants (sin contraseñas).` ); await loadStatus(); } catch (e) { setMessage(e instanceof Error ? e.message : 'Error'); } finally { setSyncing(false); } } const matched = matches.filter((m) => m.status === 'matched').length; return (

Superhuman Docs → Seguimiento

Importa páginas de Seguimiento/KPIs por cliente. Excluye CONTRASEÑAS.

{docCount} docs · {matched} matched a tenants del portal

{message && (

{message}

)} {results.length > 0 && (
    {results.map((r) => (
  • {r.tenantName} · {r.status} {r.docName ? ` · ${r.docName}` : ''} {r.upserted ? ` · ${r.upserted} entradas` : ''} {r.error ? ` · ${r.error}` : ''}
  • ))}
)} {!loading && matches.length > 0 && (
{matches.slice(0, 20).map((m) => ( ))}
Tenant Doc Match
{m.tenantName || '—'} {m.docName || '—'} {m.status} {m.score ? ` ${m.score}` : ''}
)}
); }