feat: mis clientes en Mi dia + perfilamiento de la afluencia en dashboards

- Cliente.capturadoPorId: el alta (directa y progresiva) registra al
  usuario que la inicio; el panel Mi dia muestra 'Mis clientes' con su
  estado (En captura / Cliente) sin depender de Monday.
- LeadMonday ahora lee las 11 columnas de perfil del tablero Leads
  (estado civil, edad, rango salarial, tipo de empleo/economia,
  califica, credito, modelo, etc.).
- GET /api/reportes/resumen agrega leads.perfil con conteos por
  dimension (valores vacios se omiten; edad en buckets).
- /dash/ gana la seccion 'Perfilamiento de la afluencia' con
  mini-graficas de barras por dimension.
This commit is contained in:
2026-09-02 02:39:19 +00:00
parent 895a831ff8
commit 4030faee25
18 changed files with 551 additions and 14 deletions

View File

@@ -36,11 +36,21 @@ export interface CapturaMiDia {
capturadoEn: string // ISO
}
export interface ClienteMiDia {
id: string
nombre: string
proyecto: string // '' = alta aún en captura
unidadCodigo: string
completado: boolean
capturadoEn: string // ISO
}
export interface ResumenMiDia {
generadoEn: string
sinMapeoMonday: boolean
misLeads: LeadMiDia[]
misCapturas: CapturaMiDia[]
misClientes: ClienteMiDia[]
misActividadesHoy: ActividadMiDia[]
apartadosPorVencer: ApartadoPorVencer[]
misOportunidades: { porEtapa: Record<string, number> } | null

View File

@@ -398,6 +398,40 @@ export default function MiDiaPage() {
)}
</section>
<section aria-label="Mis clientes" className="mt-12">
<TituloSeccion>Mis clientes</TituloSeccion>
{resumen.misClientes.length === 0 ? (
<EstadoVacio mensaje="Aún no registras clientes" />
) : (
<ul className="space-y-2">
{resumen.misClientes.map((c) => (
<li key={c.id} className="flex flex-wrap items-center justify-between gap-3 border border-neutral-200 px-4 py-3">
<div>
<p className="text-sm font-medium">{c.nombre}</p>
<p className="mt-1 text-xs text-neutral-500">
{[c.proyecto, c.unidadCodigo].filter((p) => p !== '').join(' · ') || 'Alta sin proyecto'}
</p>
</div>
<div className="flex items-center gap-3">
<span
className={`border px-2 py-1 text-xs font-bold uppercase tracking-widest ${
c.completado
? 'border-neutral-300 text-neutral-500'
: 'border-amber-700 text-amber-700'
}`}
>
{c.completado ? 'Cliente' : 'En captura'}
</span>
<span className="text-xs font-bold uppercase tracking-widest text-neutral-500">
{formatoFechaCorta(c.capturadoEn.slice(0, 10))}
</span>
</div>
</li>
))}
</ul>
)}
</section>
<section aria-label="Captura rápida de lead" className="mt-12">
<TituloSeccion>Captura rápida de lead</TituloSeccion>
<form onSubmit={enviarCaptura} className="grid gap-4 border border-neutral-200 p-6 sm:grid-cols-2">