feat(pendientes): cotizador (mensualidades, bloqueo de unidad, totales, numMensualidades), cobranza (recibos, atrasos, mora configurable, recordatorios), soporte (adjuntos, filtros, estados), clientes maestro (catalogos reales), contactos (ficha y duplicados) y permisos de captura por rol

This commit is contained in:
2026-09-21 08:34:53 +00:00
parent b5a20aed4e
commit 2fc80e7f9e
66 changed files with 3792 additions and 436 deletions

View File

@@ -27,6 +27,15 @@ const formatoFechaHora = (iso: string): string =>
minute: '2-digit',
})
/**
* Mensualidades guardadas: "N × $m". Las cotizaciones viejas (plazo 0/null, sin
* mensualidad) muestran "—".
*/
const formatoMensualidades = (c: CotizacionGuardada): string => {
if (c.mensualidad === null || c.numMensualidades === 0) return '—'
return `${c.numMensualidades} × ${formatoMoneda(c.mensualidad)}`
}
/** Sección colapsable "Mis cotizaciones": historial del vendedor logueado */
export function MisCotizaciones({ cotizaciones, cargando, error, onRetomar }: Props) {
const [abierto, setAbierto] = useState(false)
@@ -65,7 +74,7 @@ export function MisCotizaciones({ cotizaciones, cargando, error, onRetomar }: Pr
<table className="w-full min-w-[640px] border-collapse text-sm">
<thead>
<tr className="bg-[#F8FAFC] dark:bg-[#0F172A]">
{['Fecha', 'Folio', 'Cliente', 'Unidad', 'Propuesta', 'Precio final', ''].map(
{['Fecha', 'Folio', 'Cliente', 'Unidad', 'Propuesta', 'Mensualidades', 'Precio final', ''].map(
(h) => (
<th
key={h}
@@ -95,6 +104,9 @@ export function MisCotizaciones({ cotizaciones, cargando, error, onRetomar }: Pr
<td className="border-t border-[#E5E7EB] dark:border-[#1E293B] p-3 whitespace-nowrap">
{TITULO_PROPUESTA[c.tipoPropuesta] ?? c.tipoPropuesta}
</td>
<td className="border-t border-[#E5E7EB] dark:border-[#1E293B] p-3 whitespace-nowrap">
{formatoMensualidades(c)}
</td>
<td className="border-t border-[#E5E7EB] dark:border-[#1E293B] p-3 text-right whitespace-nowrap">
{formatoMoneda(c.precioFinal)}
</td>