import React, { useMemo } from "react"; import type { ScenarioDef, PresetDef, SubCaseSpec } from "../scenarios/types"; import { EconGraph } from "../graph/EconGraph"; import { PresetBar } from "./PresetBar"; import { ParamControls } from "./ParamControls"; import { StatCards } from "./StatCards"; import { StepBreakdown } from "./StepBreakdown"; import { ComparisonTable } from "./ComparisonTable"; import { CrossCourseBridge } from "./CrossCourseBridge"; interface ScenarioLayoutProps

, R> { scenario: ScenarioDef; params: P; onParamChange: (key: keyof P, value: number) => void; onChangeParams?: (newParams: P) => void; onResetParams: () => void; onSelectPreset: (preset: PresetDef

) => void; onNavigateScenario?: (scenarioId: string) => void; } const BANNER_STYLES: Record< "info" | "success" | "warning" | "danger", string > = { info: "border-blue-200 bg-blue-50 text-blue-900", success: "border-emerald-200 bg-emerald-50 text-emerald-900", warning: "border-amber-200 bg-amber-50 text-amber-900", danger: "border-rose-200 bg-rose-50 text-rose-900", }; export function ScenarioLayout

, R>({ scenario, params, onParamChange, onChangeParams, onResetParams, onSelectPreset, onNavigateScenario, }: ScenarioLayoutProps): React.JSX.Element { const result = useMemo(() => { return scenario.model(params); }, [scenario, params]); const view = useMemo(() => { return scenario.view(result, params); }, [scenario, result, params]); const ExplainComponent = scenario.explain; const bannerType = view.statusBanner?.type ?? "info"; const bannerStyle = BANNER_STYLES[bannerType]; const handleSelectSubCase = (subCase: SubCaseSpec

) => { const updated = { ...params, ...subCase.params }; if (onChangeParams) { onChangeParams(updated as P); } else { for (const [k, v] of Object.entries(subCase.params)) { if (v !== undefined) { onParamChange(k as keyof P, v as number); } } } }; return (

{/* Left Column (7/12) */}
{scenario.presets && ( )} {scenario.subCases && scenario.subCases.length > 0 && (
Chọn Ví dụ Minh họa Tình huống 3 góc nhìn giáo trình Pindyck & Rubinfeld
{scenario.subCases.map((subCase) => { const active = subCase.isActive(params); return ( ); })}
)} {view.steps && view.steps.length > 0 && ( )}
{/* Right Column (5/12) */}
{view.statusBanner && (
{view.statusBanner.text}
)}
{view.comparison && view.comparison.rows.length > 0 && ( )} {view.bridgeLinks && view.bridgeLinks.length > 0 && ( )} {view.footnote && (
Công thức cơ sở:{" "} {view.footnote}
)}
); }