diff --git a/src/app/dashboard/intelligence/page.tsx b/src/app/dashboard/intelligence/page.tsx index d3ee274..a4849ef 100644 --- a/src/app/dashboard/intelligence/page.tsx +++ b/src/app/dashboard/intelligence/page.tsx @@ -3,50 +3,61 @@ import Link from 'next/link'; import { useQuery } from '@tanstack/react-query'; import { apiFetch } from '../../../lib/api'; -import type { SavedSegment, ResearchBrief } from '../../../lib/api'; +import type { SavedSegment, ResearchBrief, FinancialSignal } from '../../../lib/api'; import { useSession } from '../../../components/session-provider'; const B = '/dashboard'; -interface StatCard { label: string; value: number | string; href: string; sublabel?: string } +const SEV_CFG = { + critical: { borderClass: 'border-l-signal-danger', badgeClass: 'bg-signal-danger text-white', icon: '!' }, + warning: { borderClass: 'border-l-signal-warn', badgeClass: 'bg-signal-warn text-white', icon: '⚠' }, + info: { borderClass: 'border-l-bronze-deep', badgeClass: 'bg-bronze-wash text-bronze-deep', icon: 'i' }, +} as const; + +const CAT_LABEL: Record = { + macro: 'Macro', fx: 'Valute', rates: 'Rate', news: 'Știri', commodity: 'Materii prime', +}; export default function IntelligenceOverviewPage() { const { activeTenant } = useSession(); const tenantId = activeTenant?.tenantId ?? ''; + const opts = { enabled: Boolean(tenantId), staleTime: 60_000 }; const { data: segments = [], isLoading: loadingSegs } = useQuery({ queryKey: ['segments-intel', tenantId], queryFn: () => apiFetch('/v1/segments', { tenantId }), - enabled: Boolean(tenantId), - staleTime: 60_000, + ...opts, }); const { data: briefs = [], isLoading: loadingBriefs } = useQuery({ queryKey: ['briefs-intel', tenantId], queryFn: () => apiFetch('/v1/research-briefs', { tenantId }), - enabled: Boolean(tenantId), - staleTime: 60_000, + ...opts, }); - const isLoading = loadingSegs || loadingBriefs; + const { data: signals = [], isLoading: loadingSignals } = useQuery({ + queryKey: ['financial-signals', tenantId], + queryFn: () => apiFetch('/v1/financial-intelligence/signals?limit=20', { tenantId }), + ...opts, + staleTime: 300_000, + }); + + const isLoading = loadingSegs || loadingBriefs || loadingSignals; const recentBriefs = [...briefs].sort( (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(), - ).slice(0, 5); + ).slice(0, 4); - const stats: StatCard[] = [ - { label: 'Segmente salvate', value: segments.length, href: `${B}/segments`, sublabel: 'Căutări B2B salvate' }, - { label: 'Research Briefs', value: briefs.length, href: `${B}/research`, sublabel: 'Rapoarte de cercetare' }, - { label: 'Companii B2B', value: '147M+', href: `${B}/companies`, sublabel: 'Apollo/ClickHouse' }, - { label: 'Contact match AI', value: 'live', href: `${B}/companies`, sublabel: 'intelligence-api activ' }, - ]; + const criticalSignals = signals.filter((s) => s.severity === 'critical'); + const warningSignals = signals.filter((s) => s.severity === 'warning'); + const lastSignalAt = signals[0]?.publishedAt; return (

Intelligence Overview

- Motorul de intelligence B2B — companii, segmente, research și insight-uri. + Motorul de intelligence B2B + semnale de piață financiară internațională.

@@ -54,26 +65,118 @@ export default function IntelligenceOverviewPage() {

Se încarcă…

) : ( <> + {/* ── MARKET SIGNALS ─────────────────────────────────────────── */} +
+
+

+ Market Intelligence + {(criticalSignals.length > 0 || warningSignals.length > 0) && ( + + {criticalSignals.length + warningSignals.length} alerte + + )} +

+ {lastSignalAt && ( + + Actualizat: {new Date(lastSignalAt).toLocaleString('ro-RO', { + month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', + })} + + )} +
+ + {signals.length === 0 ? ( +
+

Niciun semnal de piață disponibil

+

+ Semnalele sunt generate automat de n8n din World Bank, IMF și Eurostat. +

+

+ Importați workflow-ul n8n din /dashboard/data sau contactați administratorul. +

+
+ ) : ( +
+ {signals.slice(0, 8).map((sig) => { + const cfg = SEV_CFG[sig.severity as keyof typeof SEV_CFG] ?? SEV_CFG.info; + return ( +
+
+
+
+ + {cfg.icon} + + + {CAT_LABEL[sig.category] ?? sig.category} + + + {sig.region} + + {sig.niche && ( + + {sig.niche} + + )} +
+

+ {sig.title} +

+ {sig.rawValue != null && ( +

+ {Number(sig.rawValue).toFixed(2)}{sig.unit ? ` ${sig.unit}` : ''} + {sig.changePercent != null && ( + = 0 ? 'text-signal-ok ml-1' : 'text-signal-danger ml-1'}> + ({Number(sig.changePercent) >= 0 ? '+' : ''}{Number(sig.changePercent).toFixed(2)}%) + + )} +

+ )} +

{sig.summary}

+
+
+

{sig.source}

+

+ {new Date(sig.publishedAt).toLocaleDateString('ro-RO')} +

+
+
+
+ ); + })} + {signals.length > 8 && ( +
+ +{signals.length - 8} semnale suplimentare disponibile +
+ )} +
+ )} +
+ + {/* ── B2B INTELLIGENCE STATS ─────────────────────────────────── */}
- {stats.map((s) => ( - + {[ + { label: 'Segmente salvate', value: segments.length, href: `${B}/segments` }, + { label: 'Research Briefs', value: briefs.length, href: `${B}/research` }, + { label: 'Companii B2B', value: '147M+', href: `${B}/companies` }, + { label: 'Semnale piață', value: signals.length, href: '#' }, + ].map((s) => ( +

{s.label}

{s.value}

- {s.sublabel &&

{s.sublabel}

} ))}
+ {/* ── B2B MODULES ────────────────────────────────────────────── */}
- {/* Recent research briefs */}
-

- Research recente -

- - Vezi toate → - +

Research recente

+ Toate →
{recentBriefs.length === 0 ? (

Niciun brief creat.

@@ -83,12 +186,8 @@ export default function IntelligenceOverviewPage() {
  • {b.title}

    - - {b.status} - - - {new Date(b.createdAt).toLocaleDateString('ro-RO')} - + {b.status} + {new Date(b.createdAt).toLocaleDateString('ro-RO')}
  • ))} @@ -96,15 +195,10 @@ export default function IntelligenceOverviewPage() { )}
    - {/* Active segments */}
    -

    - Segmente active -

    - - Gestionează → - +

    Segmente active

    + Gestionează →
    {segments.length === 0 ? (

    Niciun segment salvat.

    @@ -128,23 +222,23 @@ export default function IntelligenceOverviewPage() { {/* Capability map */}

    - Capabilități platformă Intelligence + Capabilități Intelligence

    {[ { label: 'Company Search', status: 'live', href: `${B}/companies` }, { label: 'Saved Segments', status: 'live', href: `${B}/segments` }, { label: 'Research Briefs', status: 'live', href: `${B}/research` }, - { label: 'People Intelligence', status: 'a3', href: `${B}/people-intelligence` }, + { label: 'Market Signals', status: signals.length > 0 ? 'live' : 'setup', href: '#' }, + { label: 'People Intelligence', status: 'a3', href: '#' }, { label: 'Market Intelligence', status: 'a4', href: '#' }, { label: 'Insights Engine', status: 'a3', href: '#' }, - { label: 'Trends & Patterns', status: 'a3', href: '#' }, { label: 'Digital Twin', status: 'a4', href: '#' }, ].map((cap) => ( -
    +

    {cap.label}

    - - {cap.status === 'live' ? '● live' : cap.status} + + {cap.status === 'live' ? '● live' : cap.status === 'setup' ? '○ setup' : cap.status}
    ))}