diff --git a/src/app/dashboard/market/page.tsx b/src/app/dashboard/market/page.tsx new file mode 100644 index 0000000..be625ff --- /dev/null +++ b/src/app/dashboard/market/page.tsx @@ -0,0 +1,167 @@ +'use client'; +import { useSession } from '../../../lib/session'; +import { apiFetch } from '../../../lib/api'; +import { useQuery } from '@tanstack/react-query'; + +interface Signal { + id: string; + category: string; + region: string; + source: string; + title: string; + summary: string; + rawValue?: string; + changePercent?: string; + unit?: string; + severity: string; + publishedAt: string; +} + +const SEV_CLS: Record = { + critical: 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300', + warning: 'bg-amber-100 text-amber-800 dark:bg-amber-900/30 dark:text-amber-300', + info: 'bg-sky-100 text-sky-800 dark:bg-sky-900/30 dark:text-sky-300', +}; + +const CAT: Record = { + macro: 'Macro', fx: 'FX / Valute', rates: 'Dobânzi', + commodity: 'Mărfuri', news: 'Știri Economice', +}; + +const REGION: Record = { + ro: 'RO', de: 'DE', eu: 'EU', us: 'US', global: '—', +}; + +function fmt(v?: string, u?: string) { + if (!v) return null; + const n = parseFloat(v); + return isNaN(n) ? null : `${n.toLocaleString('ro-RO', { maximumFractionDigits: 2 })}${u ? ' ' + u : ''}`; +} + +function Chip({ v }: { v?: string }) { + if (!v) return null; + const n = parseFloat(v); + if (isNaN(n)) return null; + return ( + = 0 ? 'text-emerald-600 font-medium' : 'text-red-600 font-medium'}> + {n >= 0 ? '+' : ''}{n.toFixed(2)}% + + ); +} + +export default function MarketIntelligencePage() { + const { session } = useSession(); + const { data: signals = [], isLoading } = useQuery({ + queryKey: ['financial-signals'], + enabled: !!session, + staleTime: 5 * 60_000, + queryFn: () => + apiFetch('/v1/financial-intelligence/signals?limit=100', { + headers: { + Authorization: `Bearer ${session!.access_token}`, + 'x-tenant-id': session!.tenant_id, + }, + }), + }); + + const cats = [...new Set(signals.map((s) => s.category))].sort(); + const byCategory = (cat: string) => signals.filter((s) => s.category === cat); + + const critical = signals.filter((s) => s.severity === 'critical').length; + const warning = signals.filter((s) => s.severity === 'warning').length; + + return ( +
+
+
+

Market Intelligence

+

+ Semnale economice live — World Bank · ECB · Eurostat · FRED +

+
+
+ {critical > 0 && ( + + {critical} critice + + )} + {warning > 0 && ( + + {warning} atenționări + + )} + + {signals.length} total + +
+
+ + {isLoading && ( +
+
+ Se încarcă semnalele... +
+ )} + + {!isLoading && signals.length === 0 && ( +
+

Fără semnale economice

+

+ Importă workflow-ul n8n “08 Economic Data API” în n8n + (rulează la fiecare 6h și populează această pagină automat). +

+
+

Fișier: /root/ceo-os-economic-data-n8n.json

+

POST → /v1/financial-intelligence/ingest

+
+
+ )} + + {cats.map((cat) => ( +
+

+ {CAT[cat] ?? cat} +

+
+ {byCategory(cat).map((s) => ( +
+
+ {s.title} + + {s.severity} + +
+ + {(s.rawValue || s.changePercent) && ( +
+ {s.rawValue && ( + + {fmt(s.rawValue, s.unit)} + + )} + +
+ )} + +

{s.summary}

+ +
+ {s.source} +
+ {s.region !== 'global' && ( + + {REGION[s.region] ?? s.region} + + )} + {new Date(s.publishedAt).toLocaleDateString('ro-RO')} +
+
+
+ ))} +
+
+ ))} +
+ ); +}