/* === value-tracker.jsx ===============================================
RoAI Value Tracker — full configurable surface.
Replaces the old PreviewRoAI in preview.jsx.
Features:
- Period selector (3m / 6m / 12m / Tudo)
- Alert banner for overdue plans
- 3 hero KPI cards (Pipeline Total / Realizado / Taxa de Conversão)
- Pipeline de Valor (5 status cards)
- Charts: Ganhos por Status horizontal bars + Composição donut
- Summary panels: Ganhos by status / Planos by status
- Planos de Ação Kanban with drag/drop + add/edit
- Side panel: Assistente de Valor (chat + quick actions)
===================================================================== */
const VT_COLUMNS = [
{ id: 'backlog', label: 'Backlog' },
{ id: 'planejado', label: 'Planejado' },
{ id: 'emAndamento', label: 'Em Andamento' },
{ id: 'concluido', label: 'Concluído' },
{ id: 'cancelado', label: 'Cancelado' },
];
function PreviewRoAI({ state, onSetState }) {
const vt = state.valueTracker;
const setVT = (patch) => onSetState({
...state,
valueTracker: { ...vt, ...(typeof patch === 'function' ? patch(vt) : patch) }
});
/* Assistant collapsed by default — the browser-body frame is narrow */
const [collapsedAssistant, setCollapsedAssistant] = React.useState(true);
return (
{vt.alert && }
{!collapsedAssistant && (
setCollapsedAssistant(true)}
/>
)}
{collapsedAssistant && (
)}
);
}
/* ==================================================================
HEADER
================================================================== */
function VTHeader({ state, setVT }) {
const vt = state.valueTracker;
const periods = [
{ id: '3m', label: '3 meses' },
{ id: '6m', label: '6 meses' },
{ id: '12m', label: '12 meses' },
{ id: 'all', label: 'Tudo' },
];
return (
RoAI - Value Tracker
{periods.map(p => (
))}
);
}
/* ==================================================================
ALERT BANNER
================================================================== */
function VTAlert({ alert }) {
return (
{alert.message}
);
}
/* ==================================================================
HERO KPIs (3 cards)
================================================================== */
function VTHeroKPIs({ vt, setVT, state }) {
const k = vt.kpis;
return (
{k.pipelineTotal.label}
{' · '}
);
}
function VTConversionDonut({ pct }) {
const r = 16;
const C = 2 * Math.PI * r;
const dash = (pct / 100) * C;
return (
);
}
/* ==================================================================
PIPELINE DE VALOR (5 status cards)
================================================================== */
function VTPipelineValor({ vt, setVT, state }) {
return (
Pipeline de Valor
{vt.pipelineValor.map((p, i) => (
))}
);
}
/* ==================================================================
CHARTS: Ganhos por Status (horizontal) + Composição (donut)
================================================================== */
function VTCharts({ vt, state }) {
const STATUS_COLOR = {
realizado: { color: '#10B981', label: 'Realizado' },
bloqueado: { color: '#EF4444', label: 'Bloqueado (vencido)' },
emAndamento: { color: '#F59E0B', label: 'Em andamento' },
semPlano: { color: '#9CA3AF', label: 'Sem plano' },
};
const maxValor = Math.max(...vt.ganhos.map(g => g.valor));
return (
Ganhos Identificados por Status
{vt.ganhos.map((g, i) => {
const stat = STATUS_COLOR[g.status] || STATUS_COLOR.semPlano;
const pct = (g.valor / maxValor) * 100;
return (
);
})}
{Object.values(STATUS_COLOR).map((s, i) => (
{s.label}
))}
Composição do Pipeline
{vt.composicao.map((c, i) => (
{c.label}
))}
);
}
function VTDonut({ data }) {
const size = 160;
const r = 60;
const cx = size / 2, cy = size / 2;
const total = data.reduce((s, d) => s + d.pct, 0);
let acc = 0;
return (
);
}
/* ==================================================================
SUMMARY by status (Ganhos / Planos)
================================================================== */
function VTSummary({ vt, state }) {
return (
);
}
function SummaryPanel({ title, items, idPrefix }) {
const total = items.reduce((s, x) => s + x.count, 0);
const max = Math.max(...items.map(x => x.count));
return (
{title}
Total: {total}
{items.map((it, i) => (
))}
);
}
Object.assign(window, { PreviewRoAI, VT_COLUMNS });