/**
* ProteccionPersonas.jsx — v3 CORREGIDA
*/
const VERDE = '#2D7A4F'
const ROJO = '#C0392B'
const GRIS = '#4A4E6A'
const NARANJA = '#E8881A'
const CON_HABITACULO = new Set([
'Automóvil',
'Camioneta/Utilitario',
'Transporte De Pasajeros',
'Transporte De Carga',
])
const SIN_HABITACULO = new Set([
'Motocicleta',
'Peatón',
'Bicicleta',
'Tracción A Sangre',
'Tracción a Sangre',
])
function pct(n, base) {
return base > 0 ? `${((n / base) * 100).toFixed(1)}%` : '—'
}
function IndicadorChip({
titulo,
icon,
base,
baseLabel,
si,
no,
sd,
colorSi = VERDE,
}) {
return (
{icon && {icon}}
{titulo}
base: {base.toLocaleString('es-AR')} {baseLabel}
{base > 0 ? (
<>
{si > 0 && (
)}
{no > 0 && (
)}
{sd > 0 && (
)}
{[
{ label: 'Sí', v: si, color: colorSi },
{ label: 'No', v: no, color: ROJO },
{ label: 'Sin dato', v: sd, color: GRIS },
]
.filter((item) => item.v > 0)
.map((item) => (
{item.v.toLocaleString('es-AR')}
{` ${item.label} (${pct(item.v, base)})`}
))}
>
) : (
Sin datos para esta categoría en el período seleccionado
)}
)
}
function SeccionAlcohol({ personas }) {
const total = personas.length
const pos = personas.filter((p) => p.prueba_alcohol === 'Positivo').length
const neg = personas.filter((p) => p.prueba_alcohol === 'Negativo').length
const nr = personas.filter((p) => p.prueba_alcohol === 'No se Realizó').length
const sd = total - pos - neg - nr
const realizadas = pos + neg
const items = [
{ label: 'Positivo', v: pos, color: ROJO },
{ label: 'Negativo', v: neg, color: VERDE },
{ label: 'No realizada', v: nr, color: NARANJA },
{ label: 'Sin dato', v: sd, color: GRIS },
].filter((i) => i.v > 0)
return (
Prueba de alcohol
base: {total.toLocaleString('es-AR')} personas totales
{items.map((item) => (
{item.v.toLocaleString('es-AR')}
{item.label}
{pct(item.v, total)}
))}
{realizadas > 0 && (
Tasa de positividad sobre pruebas realizadas (
{realizadas.toLocaleString('es-AR')}
):
{' '}
0 ? ROJO : VERDE }}
>
{((pos / realizadas) * 100).toFixed(1)}%
)}
)
}
export default function ProteccionPersonas({ personas, involucrados }) {
if (!personas?.length) return null
const tipoMap = new Map()
if (involucrados?.length) {
involucrados.forEach((i) => {
if (i.id_involucrado != null && i.tipo_involucrado) {
tipoMap.set(String(i.id_involucrado), i.tipo_involucrado)
}
})
}
const personasConTipo = personas.map((p) => ({
...p,
_tipo: tipoMap.get(String(p.id_involucrado)) || null,
}))
const motociclistas = personasConTipo.filter(
(p) => p._tipo === 'Motocicleta'
)
const cascaSi = motociclistas.filter((p) => p.casco === 'Si').length
const cascaNo = motociclistas.filter((p) => p.casco === 'No').length
const cascaSD = motociclistas.length - cascaSi - cascaNo
const enHabitaculo = personasConTipo.filter((p) => {
if (!p._tipo) return false
if (SIN_HABITACULO.has(p._tipo)) return false
if (CON_HABITACULO.has(p._tipo)) return true
return true
})
const cinSi = enHabitaculo.filter(
(p) => p.cinturon_seguridad === 'Si'
).length
const cinNo = enHabitaculo.filter(
(p) => p.cinturon_seguridad === 'No'
).length
const cinSD = enHabitaculo.length - cinSi - cinNo
const airSi = enHabitaculo.filter((p) => p.airbag === 'Si').length
const airNo = enHabitaculo.filter((p) => p.airbag === 'No').length
const airSD = enHabitaculo.length - airSi - airNo
const sinMapa = tipoMap.size === 0
return (
{sinMapa && (
⚠ No se recibieron datos de Involucrados — los cálculos de casco/cinturón/airbag
no pueden segmentarse por tipo de vehículo. Verificá que el componente reciba
la prop involucrados.
)}
)
}