// Dashboard di Gruppo
const KpiHero = ({ label, value, unit, delta, deltaAbs, spark, invert }) => (
{label}
{value.toLocaleString('it-IT', { minimumFractionDigits: 1, maximumFractionDigits: 1 })}
{unit}
);
const CompanyCard = ({ c, onClick }) => {
const revLabel = c.sector === 'Fondazione' ? 'Entrate YTD' : 'Fatturato YTD';
const marLabel = c.sector === 'Fondazione' ? 'Copertura costi' : 'Margine %';
return (
{c.short}
{c.status === 'green' ? 'OK' : c.status === 'amber' ? 'Attenz.' : 'Critico'}
{revLabel}
{c.fatturato.value.toFixed(1)} M€
0 ? 'var(--green)' : 'var(--red)' }}>
{c.fatturato.delta > 0 ? '+' : ''}{c.fatturato.delta.toFixed(1)}%
{marLabel}
{c.margine.value.toFixed(1)}%
0 ? 'var(--green)' : 'var(--red)' }}>
{c.margine.delta > 0 ? '+' : ''}{c.margine.delta.toFixed(1)} p.p.
Cash position
{c.cash.value.toFixed(1)} M€
0 ? 'var(--green)' : 'var(--red)' }}>
{c.cash.delta > 0 ? '+' : ''}{c.cash.delta.toFixed(1)}%
);
};
// Treemap (sector allocation, hand-computed squarified-ish layout)
const Treemap = ({ data }) => {
// Simple row-based layout
const total = data.reduce((s, d) => s + d.value, 0);
// Row 1: first 2 items (large), Row 2: rest
const [a, b, c, d] = data;
return (
);
};
// Donut / asset class
const AssetDonut = ({ data }) => {
const total = data.reduce((s, d) => s + d.value, 0);
const colors = ['#2A3B48', '#5B7A6B', '#A89468', '#C4BFB3'];
let acc = 0;
const r = 60, cx = 80, cy = 80;
const segs = data.map((d, i) => {
const startAngle = (acc / total) * 2 * Math.PI - Math.PI / 2;
acc += d.value;
const endAngle = (acc / total) * 2 * Math.PI - Math.PI / 2;
const large = endAngle - startAngle > Math.PI ? 1 : 0;
const x1 = cx + r * Math.cos(startAngle), y1 = cy + r * Math.sin(startAngle);
const x2 = cx + r * Math.cos(endAngle), y2 = cy + r * Math.sin(endAngle);
return { d: `M${cx},${cy} L${x1},${y1} A${r},${r} 0 ${large} 1 ${x2},${y2} Z`, color: colors[i] };
});
return (
{data.map((d, i) => (
{d.label}
{d.pct}%
{d.value.toFixed(1)}
))}
);
};
const AlertsList = ({ alerts }) => (
{alerts.map((a, i) => (
{a.severity === 'critical' ? 'Critico' : a.severity === 'warning' ? 'Avviso' : 'Info'}
{a.text}
{a.company}
{a.date}
{a.days !== null && a.days !== undefined && · {a.days}gg}
))}
);
const Dashboard = ({ onCompanyClick, horizon = 'tattico' }) => {
const D = window.REGULA_DATA;
const k = D.group.kpis;
// Horizon-aware configuration
const horizonConfig = {
operativo: {
subtitle: 'Vista operativa · settimana corrente · 4 società · refresh 14:22',
periodLabel: 'Settimana 17 · 2026',
compareLabel: 'vs. sett. precedente',
briefLabel: 'Brief giornaliero',
kpis: [
{ ...k.liquidita, label: 'Liquidità disponibile' },
{ label: 'Pagamenti prossimi 7gg', value: 3.24, unit: 'M€', delta: -1.2, deltaAbs: '−0.1 M€', spark: [2.8, 3.0, 3.1, 3.2, 3.1, 3.25, 3.24] },
{ label: 'Incassi attesi 7gg', value: 2.98, unit: 'M€', delta: 4.8, deltaAbs: '+0.14 M€', spark: [2.4, 2.5, 2.7, 2.8, 2.85, 2.9, 2.98] },
{ ...k.debito, label: 'Utilizzo linee B/T', value: 18.4, deltaAbs: '−0.8 M€', spark: [22,21,20,19.5,19,18.6,18.4] }
],
sectionTitle: 'Cash position per società · oggi',
showForecasts: false
},
tattico: {
subtitle: 'Dashboard consolidata · ' + D.group.period + ' · 4 società · Ultimo refresh 14:22',
periodLabel: 'Apr 2026 — YTD',
compareLabel: 'vs. YTD 2025',
briefLabel: 'Brief AI',
kpis: [k.patrimonio, k.liquidita, k.ebitda, { ...k.debito }],
sectionTitle: 'Società del gruppo',
showForecasts: true
},
strategico: {
subtitle: 'Orizzonte strategico · Piano industriale 2026–2030 · 4 società',
periodLabel: 'Piano 2026–2030',
compareLabel: 'vs. piano precedente',
briefLabel: 'Proiezione piano',
kpis: [
{ label: 'Patrimonio netto target 2030', value: 418.0, unit: 'M€', delta: 46.9, deltaAbs: '+133 M€', spark: [284, 300, 320, 345, 370, 395, 418] },
{ label: 'EBITDA target 2030', value: 58.6, unit: 'M€', delta: 52.6, deltaAbs: '+20.2 M€', spark: [38, 42, 46, 50, 53, 56, 58.6] },
{ label: 'Capex cumulato 5y', value: 142.0, unit: 'M€', delta: 0, deltaAbs: 'pianificato', spark: [0, 24, 52, 82, 108, 128, 142] },
{ label: 'IRR medio progetti', value: 11.8, unit: '%', delta: 1.8, deltaAbs: 'vs hurdle 10%', spark: [9, 9.5, 10.2, 10.8, 11.2, 11.5, 11.8] }
],
sectionTitle: 'Società · traiettoria al 2030',
showForecasts: true
}
};
const H = horizonConfig[horizon] || horizonConfig.tattico;
return (
{D.group.name}
{H.subtitle}
{H.kpis.map((kpi, i) => )}
{H.sectionTitle}
4 società · click per drill-down · orizzonte {horizon}
{D.companies.map(c => onCompanyClick(c.id)} />)}
Allocazione per asset class
284.6 M€
Allocazione per settore
4 settori
{horizon === 'operativo' ? 'Alert operativi · oggi e prossimi 7gg' : horizon === 'strategico' ? 'Milestone piano industriale' : 'Alert & Scadenze'}
{horizon === 'operativo' ? '1 Urgente' : '2 Critici'}
3 Avvisi
a.days !== null && a.days <= 30) : D.alerts} />
);
};
Object.assign(window, { Dashboard });