149 lines
6.8 KiB
TypeScript
149 lines
6.8 KiB
TypeScript
import { BrowserRouter, Routes, Route, useLocation, Navigate } from 'react-router-dom'
|
|
import { useEffect, ComponentType } from 'react'
|
|
import Sidebar from './components/layout/Sidebar'
|
|
import TabBar from './components/layout/TabBar'
|
|
import { TabsProvider, useTabs } from './context/TabsContext'
|
|
import { KEEP_ALIVE_META } from './config/keepAliveMeta'
|
|
import Dashboard from './pages/Dashboard'
|
|
import GeoRadar from './pages/GeoRadar'
|
|
import Markets from './pages/Markets'
|
|
import MacroRegime from './pages/MacroRegime'
|
|
import OptionsLab from './pages/OptionsLab'
|
|
import Backtest from './pages/Backtest'
|
|
import CalendarPage from './pages/CalendarPage'
|
|
import Portfolio from './pages/Portfolio'
|
|
import PatternEditor from './pages/PatternEditor'
|
|
import PatternExplorer from './pages/PatternExplorer'
|
|
import PatternLab from './pages/PatternLab'
|
|
import JournalDeBord from './pages/JournalDeBord'
|
|
import RapportIA from './pages/RapportIA'
|
|
import SuperContexte from './pages/SuperContexte'
|
|
import Config from './pages/Config'
|
|
import Analytics from './pages/Analytics'
|
|
import AnalyticsAdvanced from './pages/AnalyticsAdvanced'
|
|
import RiskDashboard from './pages/RiskDashboard'
|
|
import SystemLogs from './pages/SystemLogs'
|
|
import VaRAnalysis from './pages/VaRAnalysis'
|
|
import PositionHistory from './pages/PositionHistory'
|
|
import InstitutionalReports from './pages/InstitutionalReports'
|
|
import SpecialistDesks from './pages/SpecialistDesks'
|
|
import ExternalSnapshot from './pages/ExternalSnapshot'
|
|
import InstrumentDashboard from './pages/InstrumentDashboard'
|
|
import CycleActions from './pages/CycleActions'
|
|
import MarketEvents from './pages/MarketEvents'
|
|
import AIDesks from './pages/AIDesks'
|
|
import MacroSeriesPage from './pages/MacroSeriesPage'
|
|
import EuroSimulator from './pages/EuroSimulator'
|
|
import CausalLab from './pages/CausalLab'
|
|
import { useCycleWatcher } from './hooks/useApi'
|
|
|
|
// ── Keep-alive pages ──────────────────────────────────────────────────────────
|
|
// All pages except InstrumentDashboard (uses URL :id param — would break when hidden).
|
|
// Order must match KEEP_ALIVE_META in keepAliveMeta.ts.
|
|
|
|
const KEEP_ALIVE_DEFS: { path: string; component: ComponentType }[] = [
|
|
{ path: '/', component: Dashboard },
|
|
{ path: '/geo', component: GeoRadar },
|
|
{ path: '/markets', component: Markets },
|
|
{ path: '/macro', component: MacroRegime },
|
|
{ path: '/options', component: OptionsLab },
|
|
{ path: '/patterns', component: PatternExplorer },
|
|
{ path: '/pattern-lab', component: PatternLab },
|
|
{ path: '/portfolio', component: Portfolio },
|
|
{ path: '/journal', component: JournalDeBord },
|
|
{ path: '/rapport', component: RapportIA },
|
|
{ path: '/super-contexte', component: SuperContexte },
|
|
{ path: '/analytics', component: Analytics },
|
|
{ path: '/analytics-advanced', component: AnalyticsAdvanced },
|
|
{ path: '/risk', component: RiskDashboard },
|
|
{ path: '/var', component: VaRAnalysis },
|
|
{ path: '/position-history', component: PositionHistory },
|
|
{ path: '/backtest', component: Backtest },
|
|
{ path: '/calendar', component: CalendarPage },
|
|
{ path: '/simulator', component: EuroSimulator },
|
|
{ path: '/causal-lab', component: CausalLab },
|
|
{ path: '/macro-series', component: MacroSeriesPage },
|
|
{ path: '/institutional', component: InstitutionalReports },
|
|
{ path: '/specialist-desks', component: SpecialistDesks },
|
|
{ path: '/market-events', component: MarketEvents },
|
|
{ path: '/ai-desks', component: AIDesks },
|
|
{ path: '/cycle-actions', component: CycleActions },
|
|
{ path: '/snapshot', component: ExternalSnapshot },
|
|
{ path: '/logs', component: SystemLogs },
|
|
{ path: '/config', component: Config },
|
|
{ path: '/patterns/edit', component: PatternEditor },
|
|
]
|
|
|
|
const KEEP_ALIVE_PATHS = new Set(KEEP_ALIVE_DEFS.map(d => d.path))
|
|
|
|
// ── KeepAlivePage ─────────────────────────────────────────────────────────────
|
|
|
|
function KeepAlivePage({ path, component: Component }: { path: string; component: ComponentType }) {
|
|
const { kept, keepRoute } = useTabs()
|
|
const location = useLocation()
|
|
const isActive = location.pathname === path || location.pathname.startsWith(path + '/')
|
|
|
|
useEffect(() => {
|
|
if (isActive) keepRoute(path)
|
|
}, [isActive, path, keepRoute])
|
|
|
|
if (!kept.has(path) && !isActive) return null
|
|
|
|
return (
|
|
<div className={isActive ? 'flex-1 min-h-0 overflow-y-auto' : 'hidden'}>
|
|
<Component />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
// ── NormalRoutes — only InstrumentDashboard (uses :id param) + redirects ─────
|
|
|
|
function NormalRoutes() {
|
|
const location = useLocation()
|
|
if (KEEP_ALIVE_PATHS.has(location.pathname)) return null
|
|
|
|
return (
|
|
<div className="flex-1 overflow-auto">
|
|
<Routes>
|
|
{/* InstrumentDashboard kept here: useParams() reads :id from URL */}
|
|
<Route path="/instruments" element={<Navigate to="/instruments/SPY" replace />} />
|
|
<Route path="/instruments/:id" element={<InstrumentDashboard />} />
|
|
{/* Legacy redirects */}
|
|
<Route path="/impact" element={<Navigate to="/market-events" replace />} />
|
|
<Route path="/timeline" element={<Navigate to="/market-events" replace />} />
|
|
</Routes>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
// ── GlobalWatcher ─────────────────────────────────────────────────────────────
|
|
|
|
function GlobalWatcher() {
|
|
useCycleWatcher()
|
|
return null
|
|
}
|
|
|
|
// ── App ───────────────────────────────────────────────────────────────────────
|
|
|
|
export default function App() {
|
|
return (
|
|
<BrowserRouter>
|
|
<TabsProvider>
|
|
<div className="flex h-screen overflow-hidden">
|
|
<GlobalWatcher />
|
|
<Sidebar />
|
|
<div className="flex-1 flex flex-col min-h-0 overflow-hidden">
|
|
<TabBar />
|
|
<div className="flex-1 flex flex-col min-h-0">
|
|
{KEEP_ALIVE_DEFS.map(def => (
|
|
<KeepAlivePage key={def.path} path={def.path} component={def.component} />
|
|
))}
|
|
<NormalRoutes />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</TabsProvider>
|
|
</BrowserRouter>
|
|
)
|
|
}
|