"use client"; import { BarChart, Bar, XAxis, YAxis, Tooltip, ReferenceLine, ResponsiveContainer, Cell, } from "recharts"; export interface TornadoEntry { param_name: string; low_value: number; high_value: number; base_kpi: number; low_kpi: number; high_kpi: number; swing: number; } interface Props { entries: TornadoEntry[]; kpiLabel?: string; baseValue?: number; } interface ChartRow { name: string; low: number; high: number; base: number; lowLabel: string; highLabel: string; } export function TornadoChart({ entries, kpiLabel = "Equity IRR", baseValue }: Props) { if (entries.length === 0) return null; const base = baseValue ?? entries[0]?.base_kpi ?? 0; const isPercent = kpiLabel.toLowerCase().includes("irr") || kpiLabel.toLowerCase().includes("cuf"); const fmtKpi = (v: number) => isPercent ? `${(v * 100).toFixed(1)}%` : v.toFixed(2); const data: ChartRow[] = entries.map((e) => ({ name: e.param_name, low: Math.min(e.low_kpi, e.high_kpi) - base, high: Math.max(e.low_kpi, e.high_kpi) - base, base, lowLabel: fmtKpi(Math.min(e.low_kpi, e.high_kpi)), highLabel: fmtKpi(Math.max(e.low_kpi, e.high_kpi)), })); const absMax = Math.max(...data.map((d) => Math.max(Math.abs(d.low), Math.abs(d.high)))); const domain = [-absMax * 1.1, absMax * 1.1]; return (

Sensitivity: {kpiLabel} (base = {fmtKpi(base)})

isPercent ? `${(v * 100).toFixed(1)}%` : v.toFixed(2)} tick={{ fontSize: 10 }} /> { const v = typeof value === "number" ? value : 0; return [ `${fmtKpi(base + v)} (Δ ${isPercent ? `${(v * 100).toFixed(1)}%` : v.toFixed(2)})`, "", ]; }} /> {data.map((entry, index) => ( = 0 ? "#10b981" : "#f43f5e"} /> ))}
); }