"use client"; import React, { useEffect, useState } from "react"; import Sidebar from "../components/Sidebar"; import TopBar from "../components/TopBar"; import { fetchGroups, fetchAllSignals, fetchCrossGroupInsights, Group, Signal, CrossGroupInsight, formatRelativeTime, getSignalIcon, getSeverityColor, parseMetaList, } from "../lib/api"; function SignalCard({ signal, delay }: { signal: Signal; delay: number }) { const meta = signal.metadata; const icon = getSignalIcon(meta.type); const color = getSeverityColor(meta.severity); const time = formatRelativeTime(meta.timestamp); return (
{icon}
{time}

{signal.document}

{meta.type.replace(/_/g, " ")} arrow_forward
); } function InsightHeroCard({ insight }: { insight: CrossGroupInsight }) { const groupAName = insight.group_a?.name || insight.group_a?.group_id || "Group A"; const groupBName = insight.group_b?.name || insight.group_b?.group_id || "Group B"; return (
{insight.severity.toUpperCase()}_ALERT Cross-Group Intelligence Analysis

{insight.type.replace(/_/g, " ")}

{insight.description}

{groupAName}

{insight.group_a?.evidence || "Evidence collected"}

{groupBName}

{insight.group_b?.evidence || "Evidence collected"}

{insight.recommendation && (

RECOMMENDATION: {insight.recommendation}

)}
); } export default function MissionDashboard() { const [groups, setGroups] = useState([]); const [signals, setSignals] = useState([]); const [insights, setInsights] = useState([]); const [loading, setLoading] = useState(true); const [insightsLoading, setInsightsLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const ctrl = new AbortController(); const timer = setTimeout(() => ctrl.abort(), 12000); async function loadCore() { setLoading(true); setError(null); try { const [grps, allGroupSignals] = await Promise.all([ fetchGroups(), fetchAllSignals(), ]); setGroups(grps); const flat = allGroupSignals .flatMap((g) => g.signals) .sort( (a, b) => new Date(b.metadata.timestamp).getTime() - new Date(a.metadata.timestamp).getTime() ) .slice(0, 16); setSignals(flat); } catch (e) { if ((e as Error)?.name !== "AbortError") { setError("Backend unavailable — check that the API server is running."); } } finally { clearTimeout(timer); setLoading(false); } } async function loadInsights() { setInsightsLoading(true); try { const cgi = await fetchCrossGroupInsights(); setInsights(cgi); } catch { // Non-fatal — insights just won't show } finally { setInsightsLoading(false); } } loadCore(); loadInsights(); return () => { ctrl.abort(); clearTimeout(timer); }; }, []); const totalSignals = groups.reduce((acc, g) => acc + g.signal_count, 0); const criticalSignals = signals.filter( (s) => s.metadata.severity === "critical" || s.metadata.severity === "high" ).length; const criticalInsights = insights.filter((i) => i.severity === "critical").length; return (
{/* Status Banner */} {error && (
warning {error}
)} {/* Metric Tiles */}
Monitored Groups sensors
{loading ? "—" : groups.length}
trending_up Active Streams
Signals Processed data_exploration
{loading ? "—" : totalSignals >= 1000 ? `${(totalSignals / 1000).toFixed(1)}k` : totalSignals}
Total Indexed
Open Insights lightbulb
{loading ? "—" : insights.length}
{criticalInsights > 0 && (
{criticalInsights} Critical Priority
)} {criticalInsights === 0 && !loading && (
All Clear
)}
High Priority priority_high
{loading ? "—" : criticalSignals}
{criticalSignals > 0 ? "Needs Attention" : "Optimal Range"}
{/* Hero Insight */} {insightsLoading && !loading && (
autorenew Analysing cross-group patterns...
)} {!insightsLoading && insights.length > 0 && ( )} {!insightsLoading && insights.length === 0 && groups.length >= 2 && (
hub

No cross-group insights yet. Signals are accumulating...

)} {!loading && groups.length < 2 && (
hub

Cross-group analysis requires at least 2 monitored groups.

)} {/* Live Signals Stream */}

Live Signals Stream {!loading && ( ({signals.length} signals) )}

filter_list sort
{loading && (
autorenew Loading signals...
)} {!loading && signals.length === 0 && (
inbox No signals yet. Connect Telegram groups to start receiving intelligence.
)} {!loading && signals.length > 0 && (
{signals.map((signal, idx) => ( ))}
)}
{/* Intelligence Ticker */}
); }