Primer commit — OPSV Dashboard de siniestralidad vial
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
import {
|
||||
BarChart,
|
||||
Bar,
|
||||
XAxis,
|
||||
YAxis,
|
||||
CartesianGrid,
|
||||
Tooltip,
|
||||
ResponsiveContainer,
|
||||
Cell,
|
||||
} from 'recharts'
|
||||
import { COLOR } from '../../utils/colores'
|
||||
import { useChartTheme } from '../../hooks/useChartTheme'
|
||||
|
||||
const getCategoria = (s) => {
|
||||
const fallecidos = parseInt(s.cantidad_fallecidos ?? s.fallecidos, 10) || 0
|
||||
const lesionados = parseInt(s.cantidad_lesionados ?? s.heridos, 10) || 0
|
||||
|
||||
if (fallecidos > 0) return 'fatales'
|
||||
if (lesionados > 0) return 'conLes'
|
||||
return 'sinLes'
|
||||
}
|
||||
|
||||
export default function PorLocalidad({ siniestros, tipo = 'todas' }) {
|
||||
const { tickColor, gridColor, tooltipBg, tooltipBorder, tooltipLabel } = useChartTheme()
|
||||
|
||||
const conteo = {}
|
||||
|
||||
siniestros.forEach((s) => {
|
||||
const categoria = getCategoria(s)
|
||||
if (tipo !== 'todas' && categoria !== tipo) return
|
||||
|
||||
const loc = (s.localidad || s.localidad_ocurrencia || 'Sin dato').trim() || 'Sin dato'
|
||||
|
||||
conteo[loc] = conteo[loc] || {
|
||||
total: 0,
|
||||
fatales: 0,
|
||||
conLes: 0,
|
||||
sinLes: 0,
|
||||
}
|
||||
|
||||
conteo[loc].total += 1
|
||||
conteo[loc][categoria] += 1
|
||||
})
|
||||
|
||||
const data = Object.entries(conteo)
|
||||
.map(([localidad, values]) => {
|
||||
const mayorCategoria = ['fatales', 'conLes', 'sinLes'].sort(
|
||||
(a, b) => values[b] - values[a]
|
||||
)[0]
|
||||
|
||||
return {
|
||||
localidad,
|
||||
total: values.total,
|
||||
categoria: mayorCategoria,
|
||||
}
|
||||
})
|
||||
.sort((a, b) => b.total - a.total)
|
||||
.slice(0, 10)
|
||||
|
||||
return (
|
||||
<div className="rounded-[28px] border border-opsv-border bg-opsv-surface p-6 shadow-sm">
|
||||
|
||||
<div className="h-[360px]">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<BarChart
|
||||
layout="vertical"
|
||||
data={data}
|
||||
margin={{ top: 10, right: 20, left: 0, bottom: 0 }}
|
||||
>
|
||||
<CartesianGrid
|
||||
strokeDasharray="3 3"
|
||||
stroke={gridColor}
|
||||
vertical={false}
|
||||
/>
|
||||
|
||||
<XAxis
|
||||
type="number"
|
||||
tick={{ fill: tickColor, fontSize: 12 }}
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
/>
|
||||
|
||||
<YAxis
|
||||
type="category"
|
||||
dataKey="localidad"
|
||||
tick={{ fill: tickColor, fontSize: 12 }}
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
width={150}
|
||||
/>
|
||||
|
||||
<Tooltip
|
||||
cursor={{ fill: 'rgba(148, 163, 184, 0.12)' }}
|
||||
contentStyle={{
|
||||
background: tooltipBg,
|
||||
border: `1px solid ${tooltipBorder}`,
|
||||
borderRadius: 16,
|
||||
boxShadow: '0 10px 30px rgba(0,0,0,0.08)',
|
||||
}}
|
||||
labelStyle={{ color: tooltipLabel, fontWeight: 700 }}
|
||||
itemStyle={{ color: tickColor }}
|
||||
/>
|
||||
|
||||
<Bar dataKey="total" radius={[0, 10, 10, 0]}>
|
||||
{data.map((entry) => (
|
||||
<Cell key={entry.localidad} fill={COLOR[entry.categoria]} />
|
||||
))}
|
||||
</Bar>
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user