diff --git a/src/app/dashboard/documents/inbox/page.tsx b/src/app/dashboard/documents/inbox/page.tsx index 2e72dee..0c26043 100644 --- a/src/app/dashboard/documents/inbox/page.tsx +++ b/src/app/dashboard/documents/inbox/page.tsx @@ -1,75 +1,148 @@ 'use client'; +import { useMemo, useState } from 'react'; +import { useQuery } from '@tanstack/react-query'; +import { apiFetch } from '../../../../lib/api'; +import { useSession } from '../../../../components/session-provider'; import Link from 'next/link'; -const SETUP_STEPS = [ - { n: 1, label: 'Paperless-ngx server activ', status: 'done', desc: 'Paperless-ngx rulează pe serverul Hetzner (port 8010).' }, - { n: 2, label: 'Webhook POST configurat', status: 'todo', desc: 'În Paperless-ngx → Settings → Workflows → adaugă webhook POST la ceo-api /v1/data-sources/paperless/webhook.' }, - { n: 3, label: 'Adapter ceo-api', status: 'todo', desc: 'Endpoint /v1/documents/inbox care consumă webhook-ul și creează documente în CEO OS.' }, - { n: 4, label: 'UI Document Inbox', status: 'planned', desc: 'Lista documentelor primite cu preview, tag automat, și flux de aprobare.' }, -]; +interface Observation { + id: string; metric: string; value: string; unit: string | null; + subjectType: string; source: string | null; confidence: number | null; + observedAt: string | null; createdAt: string; +} + +const DOC_TYPES: Record = { + invoice: { icon: '🧾', label: 'Factură' }, + contract: { icon: '📝', label: 'Contract' }, + report: { icon: '📊', label: 'Raport' }, + letter: { icon: '✉️', label: 'Scrisoare' }, + document: { icon: '📄', label: 'Document' }, + receipt: { icon: '🗝️', label: 'Chitanță' }, +}; export default function DocumentInboxPage() { + const { activeTenant } = useSession(); + const tenantId = activeTenant?.tenantId ?? ''; + const [typeFilter, setTypeFilter] = useState('all'); + + const { data: observations = [], isLoading } = useQuery({ + queryKey: ['doc-inbox', tenantId], + queryFn: () => apiFetch('/v1/observations', { tenantId }), + enabled: Boolean(tenantId), staleTime: 30_000, + refetchInterval: 60_000, // poll every 60s for new Paperless docs + }); + + const documents = useMemo(() => + observations + .filter((o) => o.subjectType === 'document' || o.metric === 'document-received') + .sort((a, b) => (b.observedAt ?? b.createdAt).localeCompare(a.observedAt ?? a.createdAt)), + [observations]); + + const typeCountMap = useMemo(() => { + const map: Record = {}; + for (const d of documents) { + const t = d.unit ?? 'document'; + map[t] = (map[t] ?? 0) + 1; + } + return map; + }, [documents]); + + const filtered = typeFilter === 'all' + ? documents + : documents.filter((d) => d.unit === typeFilter); + + function docTypeInfo(d: Observation) { + const key = (d.unit ?? 'document').toLowerCase(); + return DOC_TYPES[key] ?? { icon: '📄', label: d.unit ?? 'Document' }; + } + return ( -
-
- -

Document Inbox

-

Documente scanate și procesate automat din Paperless-ngx.

-
- -
-

Paperless-ngx neconectat

-

- Paperless-ngx rulează pe server (port 8010) dar nu este conectat la ceo-api. - Configurează webhook-ul pentru a activa inbox-ul automat. -

-
- - {/* Setup steps */} -
-

Pași de configurare

- {SETUP_STEPS.map((step) => ( -
-
- {step.status === 'done' ? '✓' : step.n} -
-
-

{step.label}

-

{step.desc}

-
-
- ))} -
- - {/* Architecture */} -
-

Flux de date planificat

-
- {[ - 'Scanner → Paperless-ngx (OCR + tagging)', - 'Paperless-ngx → webhook POST → ceo-api /v1/documents/inbox', - 'ceo-api → creare document în CEO OS (cu metadate Paperless)', - 'CEO OS UI → Document Inbox (previzualizare, aprobare, taguri)', - ].map((line, i) => ( -
- {i < 3 ? '→' : '✓'} - {line} -
- ))} +
+
+
+

Document Inbox

+

+ {documents.length} documente primite via Paperless-ngx +

+ + 🔌 Intelligence Hub +
-
- ← Toate documentele - Integrare Paperless-ngx → - Ingestie date → -
+ {/* Webhook setup info */} + {documents.length === 0 && !isLoading && ( +
+

Configurare Paperless-ngx → CEO OS

+
    +
  1. + În Paperless-ngx Admin → Settings → Workflows → Add Workflow → trigger: Document Added +
  2. +
  3. + Action type: Webhook · URL: https://boardmind.dev/api/webhooks/paperless +
  4. +
  5. + Header opțional: X-Paperless-Tenant: {tenantId} +
  6. +
  7. + În Coolify → ceo-api env: PAPERLESS_WEBHOOK_SECRET=<secret> (opțional pentru HMAC) +
  8. +
+

+ Test webhook: curl -X POST https://boardmind.dev/api/webhooks/ping +

+
+ )} + + {/* Type filters */} + {documents.length > 0 && ( +
+ + {Object.entries(typeCountMap).map(([t, c]) => { + const info = DOC_TYPES[t.toLowerCase()] ?? { icon: '📄', label: t }; + return ( + + ); + })} +
+ )} + + {isLoading ? ( +
Se încarcă…
+ ) : filtered.length > 0 ? ( +
+ {filtered.map((d) => { + const info = docTypeInfo(d); + const date = d.observedAt ?? d.createdAt; + return ( +
+ {info.icon} +
+

{d.value}

+
+ {d.source &&

{d.source}

} +

+ {new Date(date).toLocaleDateString('ro-RO', { day: 'numeric', month: 'short', year: 'numeric' })} +

+ {info.label} +
+
+
+ ); + })} +
+ ) : documents.length > 0 ? ( +
+

Niciun document de tipul selectat.

+
+ ) : null}
); }