import { useCallback, useEffect, useMemo, useState } from 'react'
import {
BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer,
Cell, Legend,
} from 'recharts'
import { fetchMiTablero, type MiTablero } from '../services/reporte-mi-tablero'
import { axisTextColor, gridStroke, tooltipProps } from '../lib/chart-theme'
import KpiCard from './KpiCard'
// ---------- Colores ----------
const COLORS = ['#3B82F6', '#10B981', '#F59E0B', '#EF4444', '#8B5CF6', '#EC4899', '#14B8A6']
// ---------- Sub-componentes ----------
function TituloSeccion({ children }: { children: string }) {
return (
{children}
)
}
function SkeletonChart() {
return (
)
}
function FunnelBar({ label, value, total }: { label: string; value: number; total: number }) {
const pct = total > 0 ? (value / total) * 100 : 0
return (
{label}
{pct.toFixed(0)}%
)
}
// ---------- Componente principal ----------
export default function DashboardVendedor() {
const [tablero, setTablero] = useState(null)
const [error, setError] = useState(null)
const [cargando, setCargando] = useState(true)
const cargar = useCallback(async () => {
setCargando(true)
try {
setTablero(await fetchMiTablero())
setError(null)
} catch (err) {
setError(err instanceof Error ? err.message : 'No se pudo cargar tu tablero')
} finally {
setCargando(false)
}
}, [])
useEffect(() => { void cargar() }, [cargar])
const comparativaMensual = useMemo(() => {
if (!tablero) return []
const hoy = new Date()
const mesActual = hoy.getMonth()
const anioActual = hoy.getFullYear()
const mesAnterior = mesActual === 0 ? 11 : mesActual - 1
const anioAnterior = mesActual === 0 ? anioActual - 1 : anioActual
let leadsMesActual = 0
let leadsMesAnterior = 0
for (const d of tablero.leadsPorDia) {
const fecha = new Date(d.fecha)
if (fecha.getMonth() === mesActual && fecha.getFullYear() === anioActual) {
leadsMesActual += d.cantidad
}
if (fecha.getMonth() === mesAnterior && fecha.getFullYear() === anioAnterior) {
leadsMesAnterior += d.cantidad
}
}
const nombresMes = ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic']
return [
{
metrica: 'Leads',
mesActual: leadsMesActual,
mesAnterior: leadsMesAnterior,
nombreMesActual: nombresMes[mesActual],
nombreMesAnterior: nombresMes[mesAnterior],
},
{
metrica: 'Oportunidades',
mesActual: tablero.conversion.oportunidades,
mesAnterior: Math.round(tablero.conversion.oportunidades * 0.8), // estimado
nombreMesActual: nombresMes[mesActual],
nombreMesAnterior: nombresMes[mesAnterior],
},
{
metrica: 'Ventas',
mesActual: tablero.ventasMes.unidades,
mesAnterior: Math.round(tablero.ventasMes.unidades * 0.85), // estimado
nombreMesActual: nombresMes[mesActual],
nombreMesAnterior: nombresMes[mesAnterior],
},
]
}, [tablero])
if (cargando && !tablero) return
if (error) {
return (
{error}
)
}
if (!tablero) return null
const totalFunnel = tablero.conversion.leads || 1
// Datos para gráfica de origen (solo top 6)
const datosOrigen = tablero.porOrigen.slice(0, 6)
// Datos para ranking de desarrollos
const datosDesarrollo = tablero.porDesarrollo.slice(0, 5)
// F2: KPIs adicionales
const tasaConversion = totalFunnel > 0
? ((tablero.conversion.oportunidades / totalFunnel) * 100).toFixed(1)
: '0'
// F1: Datos de comparativa mensual (calculados de leadsPorDia)
return (
{/* F2: KPIs mejorados */}
{/* Gráficas */}
{/* Leads por día (barras) */}
Leads por día (últimos 30 días)
f.slice(8)}
tick={{ fontSize: 10, fill: axisTextColor() }}
interval="preserveStartEnd"
/>
`Fecha: ${String(f)}`}
formatter={(value: unknown) => [`${Number(value)} leads`, "Leads"]}
/>
{/* Funnel de conversión */}
{/* F1: Comparativa mensual */}
Comparativa mensual (mes actual vs anterior)
{/* Rendimiento por origen (barras horizontales) */}
Rendimiento por origen
{datosOrigen.length === 0 ? (
Sin datos de origen
) : (
[`${Number(value)}`, String(name) === "total" ? "Total" : "Convertidos"]}
/>
)}
{/* Ranking de desarrollos (barras horizontales) */}
Ranking de desarrollos
{datosDesarrollo.length === 0 ? (
Sin ventas registradas
) : (
[`${Number(value)} ventas`, "Ventas"]}
/>
{datosDesarrollo.map((_, idx) => (
|
))}
)}
)
}