"use client"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { useEffect, useState } from "react"; import { Activity, Brain, Clock, Copy, Cpu, Dumbbell, TrendingUp, type LucideIcon } from "lucide-react"; import clsx from "clsx"; import { api } from "@/lib/api"; import { SystemStatus } from "@/lib/types"; type NavItem = { href: string; label: string; icon: LucideIcon; aliases?: string[]; }; const nav: NavItem[] = [ { href: "/brain", label: "Brain", icon: Brain, aliases: ["/dashboard"] }, { href: "/training-ground", label: "Training Ground", icon: Dumbbell, aliases: ["/learning"] }, { href: "/paper-trading", label: "Paper Trading", icon: Copy, aliases: ["/copy-trading"] }, { href: "/alpha", label: "Alpha", icon: TrendingUp } ]; type SidebarStatus = { workerStatus: string; modelStatus: string; lastLearningCycle: string; paperForwardStatus: string; alphaEvidenceGrade: string; }; const defaultSidebarStatus: SidebarStatus = { workerStatus: "checking", modelStatus: "checking", lastLearningCycle: "checking", paperForwardStatus: "checking", alphaEvidenceGrade: "checking", }; export function AppShell({ children }: { children: React.ReactNode }) { const pathname = usePathname(); const [systemStatus, setSystemStatus] = useState(null); const [sidebarStatus, setSidebarStatus] = useState(defaultSidebarStatus); useEffect(() => { let mounted = true; const onPaperTrading = pathname === "/paper-trading" || pathname === "/copy-trading" || pathname.startsWith("/paper-trading/") || pathname.startsWith("/copy-trading/"); const onAlpha = pathname === "/alpha" || pathname.startsWith("/alpha/"); if (onPaperTrading) { api.paperForwardSnapshot().then((paper) => { if (!mounted) return; setSidebarStatus({ workerStatus: "snapshot", modelStatus: "paper forward", lastLearningCycle: "not queried", paperForwardStatus: compactStatus(paper?.payload?.readiness ?? paper?.payload?.status ?? paper?.status), alphaEvidenceGrade: "not queried", }); }).catch(() => { if (mounted) { setSidebarStatus({ workerStatus: "snapshot", modelStatus: "paper forward", lastLearningCycle: "not queried", paperForwardStatus: "unavailable", alphaEvidenceGrade: "not queried", }); } }); return () => { mounted = false; }; } if (onAlpha) { setSidebarStatus({ workerStatus: "snapshot", modelStatus: "alpha evidence", lastLearningCycle: "not queried", paperForwardStatus: "not queried", alphaEvidenceGrade: "see page", }); return () => { mounted = false; }; } api.systemStatus().then((system) => { if (!mounted) return; setSystemStatus(system); setSidebarStatus({ workerStatus: system?.runtime_flags?.autonomous_engine_enabled ? "workers on" : "workers off", modelStatus: system?.runtime_flags?.financial_brain_model_enabled ? "model active" : "snapshot mode", lastLearningCycle: "see Training", paperForwardStatus: "see Paper", alphaEvidenceGrade: "see Alpha", }); }).catch(() => { if (mounted) setSidebarStatus(defaultSidebarStatus); }); return () => { mounted = false; }; }, []); return (
{children}
); } function compactStatus(value: any) { if (!value) return "pending"; const text = String(value); if (text.includes("T")) { try { return new Date(text).toLocaleDateString(); } catch { return text; } } return text.replaceAll("_", " ").slice(0, 28); }