/** * 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 } }