import { useCallback, useEffect, useState } from 'react' import { Bar, BarChart, CartesianGrid, Cell, Funnel, FunnelChart, LabelList, Legend, Pie, PieChart, ResponsiveContainer, Tooltip, XAxis, YAxis, } from 'recharts' import KpiCard from '../components/KpiCard' import { datosCobranza, datosFunnel, datosPipeline, formatoMoneda, formatoPorcentaje, unidadesApiladas, unidadesEnEtapa, type ResumenReportes, } from '../lib/reportes' import { fetchResumen } from '../services/reportes' // Paleta StudioBlank: acento verde + neutros (sin gradientes ni sombras) const COLORES_STATUS: Record = { DISPONIBLE: '#1B4332', APARTADO: '#b45309', VENDIDO: '#525252', BLOQUEADO: '#b91c1c', OTROS: '#d4d4d4', } const COLORES_FUNNEL = ['#a3a3a3', '#737373', '#52796f', '#1B4332'] const COLORES_COBRANZA = ['#1B4332', '#b45309'] function EstadoVacio({ mensaje }: { mensaje: string }) { return (

{mensaje}

) } function TituloSeccion({ children }: { children: string }) { return

{children}

} export default function DashboardPage() { const [resumen, setResumen] = useState(null) const [error, setError] = useState(null) const [cargando, setCargando] = useState(true) const cargar = useCallback(async () => { setCargando(true) try { setResumen(await fetchResumen()) setError(null) } catch (err) { setError(err instanceof Error ? err.message : 'No se pudo cargar el tablero') } finally { setCargando(false) } }, []) useEffect(() => { void cargar() }, [cargar]) const unidades = resumen ? unidadesApiladas(resumen) : [] const funnel = resumen ? datosFunnel(resumen) : [] const cobranza = resumen ? datosCobranza(resumen) : [] const pipeline = resumen ? datosPipeline(resumen) : [] const sinPipeline = pipeline.every((e) => e.valor === 0) const sinCobranza = resumen !== null && resumen.cobranza.planesAlCorriente + resumen.cobranza.planesConVencidos === 0 return (

FRASA Desarrollos

Tablero comercial

{resumen && (

Actualizado: {new Date(resumen.generadoEn).toLocaleString('es-MX')}

)}
{error && (

Sin datos del API — {error}

)} {!resumen && !error && cargando && } {!resumen && !error && !cargando && } {resumen && ( <>
Unidades por desarrollo y status {unidades.length === 0 ? ( ) : (
{Object.keys(COLORES_STATUS).map((status) => ( ))}
)}
Pipeline de ventas por etapa {sinPipeline ? ( ) : (
)}
Embudo: leads → oportunidades → ganado {funnel.every((e) => e.valor === 0) ? ( ) : (
{funnel.map((etapa, i) => ( ))}
)}
Cobranza: al corriente vs vencidos {sinCobranza ? ( ) : (
`${name}: ${value}`} fontSize={11} > {cobranza.map((rebanada, i) => ( ))}
)}
)}
) }