/* Dashboard page — header, reports table, request form, and main wiring */ const { useState, useMemo, useEffect } = React; const TYPE_FILTERS = ['Alle', 'Makro', 'Geo', 'Konflikt', 'Infra', 'Asset', 'Simulation']; /* ---------- Helpers ---------- */ function fmtDate(iso) { if (!iso) return '—'; const d = new Date(iso); const months = ['Jan','Feb','Mrz','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','Dez']; return `${String(d.getDate()).padStart(2,'0')} · ${months[d.getMonth()]} · ${d.getFullYear()}`; } function fmtDateTime(iso) { if (!iso) return '—'; const d = new Date(iso); return d.toLocaleString('de-DE', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' }); } function nextAgentRun() { const now = new Date(); const noon = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), 12, 0, 0)); const midnight = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1, 0, 0, 0)); const next = now < noon ? noon : midnight; return next.toLocaleString('de-DE', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' }); } function simToRow(sim) { return { id: sim.sim_id, title: sim.title || sim.label || sim.dominant_scenario || sim.sim_id, type: 'Simulation', date: fmtDate(sim.published_at || sim.last_updated), pages: sim.pdf_pages ? `${sim.pdf_pages} S.` : null, status: 'live', // getLiveReports gibt ausschließlich live Reports zurück dominantPct: sim.dominant_probability ? Math.round(sim.dominant_probability * 100) : null, }; } function StatusPill({ status }) { if (status === 'live') return Aktuell; if (status === 'draft') return In Bearbeitung; return Archiv; } /* ---------- Dashboard header ---------- */ function DashHeader({ agentStatus, simCount }) { const lastRun = agentStatus?.recent_runs?.[0]; const lastRunIso = lastRun?.finished_at || lastRun?.started_at; const timestampStr = lastRunIso ? fmtDateTime(lastRunIso) + ' UTC' : new Date().toLocaleString('de-DE', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' }) + ' UTC'; const bodyText = lastRunIso ? `Letzter Agent-Run: ${fmtDateTime(lastRunIso)} UTC. Nächstes Update: ${nextAgentRun()} UTC. Eskalationspfade werden kontinuierlich überwacht.` : `Nächster geplanter Agent-Run: ${nextAgentRun()} UTC. Eskalationspfade werden kontinuierlich überwacht.`; const statsData = [ ['Aktive Simulationen', String(simCount || 0), 'vom Backend'], ['Letzter Agent-Run', lastRunIso ? fmtDateTime(lastRunIso) : '—', lastRun ? `${lastRun.sims_updated ?? '—'} Sims aktualisiert` : 'noch kein Run'], ]; return (
Dashboard / Lagebild
Stand {timestampStr}

{simCount} aktive Simulationen.

{bodyText}

{statsData.map(([k, v, sub], i) => (
{k}
{v}
{sub}
))}
); } /* ---------- Reports table ---------- */ function ReportsTable({ reports, loading }) { const [filter, setFilter] = useState('Alle'); const [query, setQuery] = useState(''); const filtered = useMemo(() => { return (reports || []).filter(r => { if (filter !== 'Alle' && r.type !== filter) return false; if (query && !(r.title.toLowerCase() + r.id.toLowerCase()).includes(query.toLowerCase())) return false; return true; }); }, [reports, filter, query]); return (
Reports · Übersicht
Alle Berichte
{TYPE_FILTERS.map(t => ( ))}
setQuery(e.target.value)} style={{ background: 'var(--surface-low)', borderColor: 'var(--ghost-strong)' }} />
Bericht
Datum
Status
{loading ? (
Daten werden geladen…
) : filtered.length === 0 ? (
{(reports || []).length === 0 ? 'Keine publizierten Simulationen' : 'Keine Treffer'}
{(reports || []).length === 0 && (

Starte eine Simulation über „Bericht anfordern" oder publiziere eine bestehende im Admin-Bereich.

)}
) : ( filtered.map((r) => (
{r.title}
{r.id}
{r.date}
)) )}
{loading ? '…' : `${filtered.length} von ${(reports || []).length} Berichten`}
Intelligence-Übersicht
); } /* ---------- Request a report ---------- */ function RequestReport() { return (
Auftragsanfrage
Bericht anfordern
Coming Soon

Die direkte Berichtsanfrage wird in Kürze freigeschaltet. Reports können bis dahin intern über das Admin-Panel ausgelöst werden.

Admin-Panel öffnen →
); } /* ---------- Welcome Modal ---------- */ function WelcomeModal({ onClose, onRequestReport }) { const sections = [ { tag: '01', name: 'Simulations-Archiv', body: 'Alle veröffentlichten Engine-Simulationen in Echtzeit vom Backend geladen. Klicken Sie eine Simulation an, um den vollständigen Report zu öffnen.' }, { tag: '02', name: 'Geopolitische Lagekarte', body: 'Interaktive Weltkarte mit Konfliktherden, Lieferketten und Sanktionsregimen. Layer ein- und ausblendbar. Vollbild per Taste F.' }, { tag: '03', name: 'GeoStrat-Portfolio', body: 'Aktuelle Allokationsempfehlung direkt aus der letzten Engine-Simulation — für Vermögensverwalter, Family Offices und Privatanleger.' }, { tag: '04', name: 'Bericht anfordern', body: 'Eigene Thesen einreichen. Die GeoStrat-Engine startet sofort eine KI-gestützte Simulation und generiert einen vollständigen Analyse-Report.' }, ]; return (
{ if (e.target === e.currentTarget) onClose(); }}>
RICS Analytics · Dashboard

Willkommen im
Analyse-Dashboard.

Das Dashboard gibt Ihnen Zugriff auf alle aktiven Engine-Reports, die geopolitische Lagekarte und die aktuelle GeoStrat-Portfolioempfehlung — in Echtzeit vom Backend.

{sections.map((s) => (
/{s.tag}
{s.name}

{s.body}

))}
KI-gestützte Simulation · Sofortiger Report
); } /* ---------- Dashboard root ---------- */ function Dashboard() { const [showWelcome, setShowWelcome] = React.useState(() => { try { return !localStorage.getItem('rics_dashboard_welcomed'); } catch (_) { return true; } }); const [agentStatus, setAgentStatus] = React.useState(null); const [sims, setSims] = React.useState([]); const [loading, setLoading] = React.useState(true); useEffect(() => { if (!window.RICS_API) { setLoading(false); return; } Promise.all([ window.RICS_API.getAgentStatus().catch(() => null), window.RICS_API.getLiveReports().catch(() => []), ]).then(([agent, simList]) => { setAgentStatus(agent); setSims(Array.isArray(simList) ? simList : []); setLoading(false); }); }, []); const allReports = useMemo(() => sims.map(simToRow), [sims]); const closeWelcome = () => { try { localStorage.setItem('rics_dashboard_welcomed', '1'); } catch (_) {} setShowWelcome(false); }; const goToRequest = () => { closeWelcome(); setTimeout(() => { const el = document.getElementById('request-report'); if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' }); }, 80); }; return ( {showWelcome && }