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:
@@ -24,6 +24,7 @@ import { descargarRecibo } from '../lib/pdf/reciboAbono'
|
||||
import BadgeStatus from '../components/BadgeStatus'
|
||||
import KpiCard from '../components/KpiCard'
|
||||
import ModalAbono from '../components/ModalAbono'
|
||||
import TimelinePagos from '../components/TimelinePagos'
|
||||
|
||||
export default function PlanDetallePage() {
|
||||
const { id } = useParams<{ id: string }>()
|
||||
@@ -210,6 +211,16 @@ export default function PlanDetallePage() {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Timeline visual de pagos */}
|
||||
<section className="rounded-xl border border-[#E5E7EB] bg-white p-5 dark:border-[#1E293B] dark:bg-[#1E293B] shadow-sm" aria-labelledby="titulo-timeline">
|
||||
<h2 id="titulo-timeline" className="text-xs font-semibold uppercase tracking-wider text-[#64748B] dark:text-[#94A3B8]">
|
||||
Línea de pagos
|
||||
</h2>
|
||||
<div className="mt-4">
|
||||
<TimelinePagos pagos={plan.pagos} />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Tabla de pagos */}
|
||||
<div className="overflow-x-auto rounded-xl border border-[#E5E7EB] bg-white shadow dark:border-[#1E293B] dark:bg-[#1E293B] -sm">
|
||||
<table className="w-full text-left text-sm">
|
||||
@@ -278,10 +289,34 @@ export default function PlanDetallePage() {
|
||||
{expandido && (
|
||||
<tr className="bg-[#F8FAFC] dark:bg-[#0F172A]">
|
||||
<td colSpan={tasaMora > 0 ? 9 : 8} className="px-4 py-4">
|
||||
{/* Detalle del pago vencido */}
|
||||
<div className="mb-3 grid grid-cols-2 gap-2 text-xs sm:grid-cols-4">
|
||||
<div>
|
||||
<span className="font-semibold text-[#64748B] dark:text-[#94A3B8]">Vencimiento:</span>{' '}
|
||||
<span className="text-[#111827] dark:text-[#E2E8F0]">{formatoFechaCorta(pago.fechaVencimiento.slice(0, 10))}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="font-semibold text-[#64748B] dark:text-[#94A3B8]">Monto:</span>{' '}
|
||||
<span className="text-[#111827] dark:text-[#E2E8F0]">{formatoMoneda(pago.monto)}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="font-semibold text-[#64748B] dark:text-[#94A3B8]">Pagado:</span>{' '}
|
||||
<span className="text-[#111827] dark:text-[#E2E8F0]">{formatoMoneda(pago.montoPagado)}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="font-semibold text-[#64748B] dark:text-[#94A3B8]">Restante:</span>{' '}
|
||||
<span className={`font-medium ${restante > 0 ? 'text-red-700' : 'text-green-700'}`}>{formatoMoneda(restante)}</span>
|
||||
</div>
|
||||
</div>
|
||||
{/* Historial de abonos */}
|
||||
<p className="mb-2 text-xs font-semibold uppercase tracking-wider text-[#64748B] dark:text-[#94A3B8]">
|
||||
Historial de abonos
|
||||
</p>
|
||||
<table className="w-full text-xs">
|
||||
<thead>
|
||||
<tr className="text-left font-semibold uppercase tracking-wider text-[#64748B] dark:text-[#94A3B8]">
|
||||
<th scope="col" className="py-1">Fecha</th>
|
||||
<th scope="col" className="py-1">Fecha pago</th>
|
||||
<th scope="col" className="py-1">Vencimiento</th>
|
||||
<th scope="col" className="py-1 text-right">Monto</th>
|
||||
<th scope="col" className="py-1">Referencia</th>
|
||||
<th scope="col" className="py-1 text-right">Recibo</th>
|
||||
@@ -290,9 +325,10 @@ export default function PlanDetallePage() {
|
||||
<tbody>
|
||||
{pago.aplicaciones.map((a) => (
|
||||
<tr key={a.id} className="border-t border-[#E5E7EB] dark:border-[#1E293B]">
|
||||
<td className="py-1">{formatoFechaCorta(a.fechaPago)}</td>
|
||||
<td className="py-1">{formatoFechaCorta(a.fechaPago.slice(0, 10))}</td>
|
||||
<td className="py-1 text-[#94A3B8]">{formatoFechaCorta(pago.fechaVencimiento.slice(0, 10))}</td>
|
||||
<td className="py-1 text-right">{formatoMoneda(a.monto)}</td>
|
||||
<td className="py-1">{a.referencia}</td>
|
||||
<td className="py-1">{a.referencia || '—'}</td>
|
||||
<td className="py-1 text-right">
|
||||
<button
|
||||
onClick={() => descargarRecibo(plan, pago, a)}
|
||||
|
||||
Reference in New Issue
Block a user