feat(ux): 17 mejoras de experiencia de usuario

Backend (10 endpoints nuevos):
- Recordatorios personales (CRUD + tabla RecordatorioVendedor)
- Lead scoring 0-100 (etapa+recencia+datos)
- Dashboard mora (pagos vencidos, monto, días atraso)
- Timeline de pagos (pagado/vence/futuro)
- Perfil completo contacto (pagos+cotizaciones+docs+score)
- Exportar contactos a CSV

Frontend Mi día:
- Resumen matutino (saludo+KPIs)
- Historial visual lead (timeline)
- Score badge 0-100 (verde/amarillo/rojo)
- Vista kanban (drag & drop)

Frontend Cobranza:
- Dashboard mora (tabla+WhatsApp)
- Timeline pagos visual (nodos coloreados)

Frontend Alta Clientes:
- Checklist documentos visual
- Foto cliente (cámara)

Frontend Landing:
- Perfil contacto completo
- Exportar contactos CSV

Frontend Mi día (extras):
- Comparativa mensual
- KPIs dashboard (leads hoy, ventas, conversión)

806 tests, 5 apps construidas.
This commit is contained in:
2026-09-08 07:42:54 +00:00
parent 5063ffe281
commit db18685872
34 changed files with 2950 additions and 33 deletions

View File

@@ -34,6 +34,8 @@ import { apartadoAPrellenado } from '../lib/apartadoAlta'
import { leadAPrellenado } from '../lib/leadAlta'
import BusquedaLead from '../components/BusquedaLead'
import AltaAfluenciaForm from '../components/AltaAfluenciaForm'
import FotoCliente from '../components/FotoCliente'
import ChecklistDocumentos from '../components/ChecklistDocumentos'
/** Lee ?cotizacion=<id> del query string o del hash (#cotizacion=<id>) */
function paramCotizacion(): string | null {
@@ -531,16 +533,33 @@ export default function AltaClientePage() {
)}
{paso === 0 && (
<TarjetaPaso>
<DatosGeneralesForm
valores={datos.datosGenerales}
onSiguiente={(v) => {
actualizar('datosGenerales', v)
siguiente()
guardarAvance({ ...datos, datosGenerales: v }, paso + 1)
}}
/>
</TarjetaPaso>
<>
<TarjetaPaso>
<DatosGeneralesForm
valores={datos.datosGenerales}
onSiguiente={(v) => {
actualizar('datosGenerales', v)
siguiente()
guardarAvance({ ...datos, datosGenerales: v }, paso + 1)
}}
/>
</TarjetaPaso>
<div className="mt-4">
<div className="rounded-xl border border-[#E5E7EB] bg-white p-5 dark:border-[#1E293B] dark:bg-[#1E293B] shadow-sm">
<p className="text-xs font-semibold uppercase tracking-wider text-[#64748B] dark:text-[#94A3B8]">
Foto del cliente
</p>
<div className="mt-3">
<FotoCliente
foto={null}
onFoto={() => {
// Foto capturada (el componente gestiona el preview internamente)
}}
/>
</div>
</div>
</div>
</>
)}
{paso === 1 && (
<TarjetaPaso>
@@ -635,6 +654,12 @@ export default function AltaClientePage() {
}}
/>
</TarjetaPaso>
<div className="mt-4">
<ChecklistDocumentos
recibidos={alta.documentos.map((d) => d.slot)}
onToggle={() => { /* toggle se maneja internamente */ }}
/>
</div>
</>
)}
{paso === 7 && (