const { useState, useMemo } = React;
// ─── 5×5 Risk Matrix ─────────────────────────────────────────────────────────
function RiskMatrix({ risks, onHover }) {
const [hovered, setHovered] = useState(null);
const CELL = 56;
function cellBg(p, i) {
const s = p * i;
if (s >= 20) return { bg:'#FEE2E2', border:C.danger };
if (s >= 15) return { bg:'#FEF3C7', border:C.warning };
if (s >= 10) return { bg:'#FEF9C3', border:'#EAB308' };
if (s >= 5) return { bg:'#ECFDF5', border:C.success };
return { bg:'#F0FDF4', border:'#86EFAC' };
}
function scoreLabel(s) {
if (s >= 20) return { label:'CRÍTICO', color:C.danger };
if (s >= 15) return { label:'MUITO ALTO',color:C.warning };
if (s >= 10) return { label:'ALTO', color:'#CA8A04' };
if (s >= 5) return { label:'MÉDIO', color:C.success };
return { label:'BAIXO', color:'#16A34A' };
}
const risksInCell = (prob, imp) => risks.filter(r => r.P === prob && r.I === imp);
return (
{/* Y axis label */}
{/* Probability labels + rows */}
{[5,4,3,2,1].map(prob => (
{prob}
{[1,2,3,4,5].map(imp => {
const { bg, border } = cellBg(prob, imp);
const items = risksInCell(prob, imp);
const cellKey = `${prob}-${imp}`;
return (
{ setHovered(cellKey); if(items.length) onHover(items); }}
onMouseLeave={() => { setHovered(null); onHover([]); }}
>
{items.map(r => (
{r.id}
))}
{!items.length &&
{prob*imp}
}
);
})}
))}
{/* X axis */}
{[1,2,3,4,5].map(i => (
{i}
))}
IMPACTO →
{/* Legend */}
{[{s:'≥20',l:'Crítico',bg:'#FEE2E2',c:C.danger},{s:'15–19',l:'Muito Alto',bg:'#FEF3C7',c:C.warning},{s:'10–14',l:'Alto',bg:'#FEF9C3',c:'#CA8A04'},{s:'5–9',l:'Médio',bg:'#ECFDF5',c:C.success},{s:'<5',l:'Baixo',bg:'#F0FDF4',c:'#16A34A'}].map(z => (
))}
);
}
// ─── Risk Row ─────────────────────────────────────────────────────────────────
function RiskRow({ r, idx, highlight }) {
const score = r.P * r.I;
const col = score >= 20 ? C.danger : score >= 15 ? C.warning : score >= 10 ? '#CA8A04' : C.success;
const stale = false; // would check days since review
const escalated = score >= 20;
return (
|
{r.id}
{escalated && ESCALONADO CEx}
|
|
{r.description} |
{r.P} |
{r.I} |
{score}
|
{r.trend==='up'?'↑':r.trend==='down'?'↓':'→'}
|
{r.strategy} |
{r.owner} |
{r.lastReview} |
);
}
// ─── Screen 7: Gestão de Riscos ───────────────────────────────────────────────
function Screen7Riscos() {
const { risks } = window.SIGP_DATA;
const [hoveredRisks, setHoveredRisks] = useState([]);
const [filterCat, setFilterCat] = useState('Todos');
const [filterTrend, setFilterTrend] = useState('Todos');
const [activeTab, setActiveTab] = useState('matrix');
const cats = ['Todos', 'Financeiro', 'Técnico', 'Ambiental', 'RH'];
const filtered = useMemo(() => risks.filter(r => {
if (filterCat !== 'Todos' && r.category !== filterCat) return false;
if (filterTrend !== 'Todos') {
if (filterTrend === 'Piorando' && r.trend !== 'up') return false;
if (filterTrend === 'Melhorando' && r.trend !== 'down') return false;
}
return true;
}), [filterCat, filterTrend]);
const critical = risks.filter(r => r.P * r.I >= 20).length;
const high = risks.filter(r => { const s = r.P*r.I; return s>=15&&s<20; }).length;
const worsened = risks.filter(r => r.trend === 'up').length;
const improved = risks.filter(r => r.trend === 'down').length;
return (
{/* ── Summary KPIs ── */}
0?'critical':'ok'} />
0?'at_risk':'ok'} />
3?'at_risk':'warning'} />
{/* ── Tabs ── */}
{[{id:'matrix',label:'Matriz de Risco'},{id:'register',label:'Registro de Riscos'},{id:'trends',label:'Tendências'}].map(t => (
))}
{/* ── Matrix Tab ── */}
{activeTab === 'matrix' && (
{hoveredRisks.length === 0 && (
Selecione uma célula na matriz →
)}
{hoveredRisks.map(r => {
const score = r.P * r.I;
const col = score >= 20 ? C.danger : score >= 15 ? C.warning : score >= 10 ? '#CA8A04' : C.success;
return (
{r.description}
Estratégia: {r.strategy}
Owner: {r.owner} · Revisão: {r.lastReview}
);
})}
{risks.sort((a,b) => b.P*b.I - a.P*a.I).slice(0,3).map((r,i) => {
const score = r.P*r.I;
const col = score>=20?C.danger:C.warning;
return (
{score}
{r.id} · {r.category}
{r.description.substring(0,70)}…
{r.trend==='up'?'↑ Tendência piorando':r.trend==='down'?'↓ Tendência melhorando':'→ Estável'}
);
})}
)}
{/* ── Register Tab ── */}
{activeTab === 'register' && (
{cats.map(c => (
))}
}
>
| ID |
Categoria |
Descrição |
P |
I |
Score |
Tend. |
Estratégia de Resposta |
Owner |
Última Rev. |
{filtered.map((r, i) => (
h.id === r.id)} />
))}
)}
{/* ── Trends Tab ── */}
{activeTab === 'trends' && (
{risks.filter(r => r.trend === 'up').map((r, i) => {
const score = r.P * r.I;
const col = score >= 20 ? C.danger : score >= 15 ? C.warning : '#CA8A04';
return (
↑
{r.id} · {r.category}
Score {score}
{r.description}
Owner: {r.owner}
);
})}
{risks.filter(r => r.trend === 'down').map((r, i) => (
↓
{r.id} · {r.category}
Score {r.P*r.I}
{r.description}
Estratégia efetiva · {r.strategy.substring(0,50)}…
))}
{risks.filter(r => r.trend === 'down').length === 0 && (
Nenhum risco com tendência de melhora
)}
)}
);
}
Object.assign(window, { Screen7Riscos });