115 lines
3.8 KiB
JavaScript
115 lines
3.8 KiB
JavaScript
/**
|
|
* useSiniestralidad.js — v2 CORREGIDO
|
|
*
|
|
* CAMBIO CRÍTICO: Persona e Involucrados se consultan por ano/mes directamente,
|
|
* NO por id_feu con .in(). Motivo: .in() con muchos IDs supera el límite de URL
|
|
* de PostgREST y devuelve array vacío sin error visible.
|
|
*
|
|
* El filtro de zona se aplica en memoria en Dashboard.jsx usando id_feu.
|
|
*
|
|
* Paginación: .range(0, 4999) para hasta 5000 filas por tabla.
|
|
* Si tu dataset tiene más, aumentá el límite.
|
|
*/
|
|
import { useState, useEffect } from 'react'
|
|
import { supabase } from '../lib/supabase'
|
|
|
|
// ── Nombres EXACTOS de tablas en Supabase (case-sensitive) ────
|
|
const T = {
|
|
siniestros: 'siniestros',
|
|
involucrados: 'Involucrados', // I mayúscula
|
|
personas: 'Personas', // P mayúscula
|
|
}
|
|
|
|
// ── Columnas seleccionadas ────────────────────────────────────
|
|
const SEL = {
|
|
sin: [
|
|
'id_feu','mes','ano','siniestro_hora','localidad','departamento',
|
|
'zona_ocurrencia','via_publica','tipo_siniestro_unico',
|
|
'fallecidos','heridos','ilesos','dia_semana','es_fin_semana',
|
|
'configuracion_de_la_via','luminosidad','latitud','longitud',
|
|
].join(','),
|
|
|
|
inv: [
|
|
'id_feu','tipo_involucrado','marca','modelo','color','ano','mes',
|
|
].join(','),
|
|
|
|
per: [
|
|
'id_feu','genero','edad','rol_persona_involucrada','ubicacion_vehiculo',
|
|
'estado_ocupante_inicio','estado_ocupante_final','categoria_siniestro',
|
|
'cinturon_seguridad','casco','airbag','prueba_alcohol',
|
|
'fuga','nacionalidad','ano','mes',
|
|
].join(','),
|
|
}
|
|
|
|
const MAX_ROWS = 4999 // ajustá si tu dataset es mayor
|
|
|
|
async function queryByAnoMes(tabla, select, año, mes) {
|
|
let q = supabase.from(tabla).select(select).eq('ano', año).range(0, MAX_ROWS)
|
|
if (mes > 0) q = q.eq('mes', mes)
|
|
const { data, error } = await q
|
|
return { data: data ?? [], error }
|
|
}
|
|
|
|
export function useSiniestralidad(año, mes) {
|
|
const [siniestros, setSiniestros] = useState([])
|
|
const [involucrados, setInvolucrados] = useState([])
|
|
const [personas, setPersonas] = useState([])
|
|
const [loading, setLoading] = useState(true)
|
|
const [debug, setDebug] = useState(null)
|
|
const [error, setError] = useState(null)
|
|
|
|
useEffect(() => {
|
|
let cancelled = false
|
|
|
|
async function cargar() {
|
|
setLoading(true)
|
|
|
|
// ── Las 3 consultas en PARALELO — cada una por ano/mes ─
|
|
const [resS, resI, resP] = await Promise.all([
|
|
queryByAnoMes(T.siniestros, SEL.sin, año, mes),
|
|
queryByAnoMes(T.involucrados, SEL.inv, año, mes),
|
|
queryByAnoMes(T.personas, SEL.per, año, mes),
|
|
])
|
|
|
|
const log = {
|
|
año_consultado: año,
|
|
mes_consultado: mes > 0 ? mes : 'todos',
|
|
siniestros: {
|
|
tabla: T.siniestros,
|
|
registros: resS.data.length,
|
|
error: resS.error?.message ?? null,
|
|
},
|
|
involucrados: {
|
|
tabla: T.involucrados,
|
|
registros: resI.data.length,
|
|
error: resI.error?.message ?? null,
|
|
},
|
|
personas: {
|
|
tabla: T.personas,
|
|
registros: resP.data.length,
|
|
error: resP.error?.message ?? null,
|
|
},
|
|
}
|
|
|
|
if (cancelled) return
|
|
|
|
const errorEntries = [resS.error, resI.error, resP.error].filter(Boolean)
|
|
const errorMessage = errorEntries.length
|
|
? errorEntries.map((err) => err?.message || String(err)).join(' | ')
|
|
: null
|
|
|
|
setSiniestros(resS.data)
|
|
setInvolucrados(resI.data)
|
|
setPersonas(resP.data)
|
|
setDebug(log)
|
|
setError(errorMessage)
|
|
setLoading(false)
|
|
}
|
|
|
|
cargar()
|
|
return () => { cancelled = true }
|
|
}, [año, mes])
|
|
|
|
return { siniestros, involucrados, personas, loading, debug, error }
|
|
}
|