feat(cotizador): enganche editable directo en su renglon (min 7.5%, tope 90% de anticipo); se quita el espacio separado de adicional
This commit is contained in:
@@ -16,11 +16,13 @@ interface Props {
|
|||||||
fechaEntrega?: string | null
|
fechaEntrega?: string | null
|
||||||
/** Tope de mensualidades: los meses que faltan para la entrega (default 36 sin fecha) */
|
/** Tope de mensualidades: los meses que faltan para la entrega (default 36 sin fecha) */
|
||||||
maxMensualidades?: number
|
maxMensualidades?: number
|
||||||
/** Enganche adicional capturado (>= 0) */
|
/** Enganche base del esquema (7.5% del precio, neto del excedente del apartado) */
|
||||||
engancheAdicional: number
|
engancheBase: number
|
||||||
onEngancheAdicional: (v: number) => void
|
/** Enganche total capturado (base + extra); el input vive en el renglón del enganche */
|
||||||
/** Máximo de enganche adicional permitido por el tope del 90% de anticipo */
|
engancheTotal: number
|
||||||
engancheAdicionalMaximo: number
|
onEngancheTotal: (v: number) => void
|
||||||
|
/** Máximo de enganche total permitido por el tope del 90% de anticipo */
|
||||||
|
engancheMax: number
|
||||||
numMensualidades: number
|
numMensualidades: number
|
||||||
onNumMensualidades: (n: number) => void
|
onNumMensualidades: (n: number) => void
|
||||||
escrituracionDiferida: boolean
|
escrituracionDiferida: boolean
|
||||||
@@ -44,9 +46,10 @@ export function EsquemaPanel({
|
|||||||
esquema,
|
esquema,
|
||||||
fechaEntrega,
|
fechaEntrega,
|
||||||
maxMensualidades = MENSUALIDADES_MAX,
|
maxMensualidades = MENSUALIDADES_MAX,
|
||||||
engancheAdicional,
|
engancheBase,
|
||||||
onEngancheAdicional,
|
engancheTotal,
|
||||||
engancheAdicionalMaximo,
|
onEngancheTotal,
|
||||||
|
engancheMax,
|
||||||
numMensualidades,
|
numMensualidades,
|
||||||
onNumMensualidades,
|
onNumMensualidades,
|
||||||
escrituracionDiferida,
|
escrituracionDiferida,
|
||||||
@@ -116,10 +119,24 @@ export function EsquemaPanel({
|
|||||||
)}
|
)}
|
||||||
<div className="flex flex-col gap-1 py-2 sm:flex-row sm:items-center sm:justify-between">
|
<div className="flex flex-col gap-1 py-2 sm:flex-row sm:items-center sm:justify-between">
|
||||||
<dt className="text-sm text-[#64748B] dark:text-[#94A3B8]">
|
<dt className="text-sm text-[#64748B] dark:text-[#94A3B8]">
|
||||||
Enganche ({formatoPorcentaje(PCT_ENGANCHE)}) diferible
|
Enganche diferible
|
||||||
|
<span className="mt-0.5 block text-xs font-normal text-[#64748B] dark:text-[#94A3B8]">
|
||||||
|
Mín. {formatoPorcentaje(PCT_ENGANCHE)} del precio; puedes subirlo hasta el tope del{' '}
|
||||||
|
{formatoPorcentaje(PCT_ENGANCHE_MAXIMO)} de anticipo total
|
||||||
|
</span>
|
||||||
</dt>
|
</dt>
|
||||||
<dd className="text-sm font-medium text-[#111827] dark:text-[#E2E8F0]">
|
<dd className="flex items-center gap-1.5">
|
||||||
{formatoMoneda(esquema.enganche)}
|
<span className="text-sm text-[#64748B] dark:text-[#94A3B8]">$</span>
|
||||||
|
<input
|
||||||
|
id="enganche-diferible"
|
||||||
|
type="number"
|
||||||
|
min={engancheBase}
|
||||||
|
max={engancheMax}
|
||||||
|
step={1000}
|
||||||
|
value={Math.round(engancheTotal)}
|
||||||
|
onChange={(e) => onEngancheTotal(e.target.value === '' ? engancheBase : Number(e.target.value))}
|
||||||
|
className="w-36 rounded-lg border border-[#D1D5DB] bg-white px-3 py-1.5 text-right text-sm font-medium text-[#111827] transition-colors focus:border-accent focus:ring-2 focus:ring-accent/20 focus:outline-none dark:bg-[#0F172A] dark:border-[#334155] dark:text-[#E2E8F0]"
|
||||||
|
/>
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-1 py-2 sm:flex-row sm:items-center sm:justify-between">
|
<div className="flex flex-col gap-1 py-2 sm:flex-row sm:items-center sm:justify-between">
|
||||||
@@ -135,20 +152,15 @@ export function EsquemaPanel({
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-1 py-2 sm:flex-row sm:items-center sm:justify-between">
|
<div className="flex flex-col gap-1 py-2 sm:flex-row sm:items-center sm:justify-between">
|
||||||
<dt className="text-sm font-semibold text-[#111827] dark:text-[#E2E8F0]">
|
<dt className="text-sm font-semibold text-[#111827] dark:text-[#E2E8F0]">
|
||||||
Total del esquema (15.5% del precio)
|
Total del esquema
|
||||||
|
<span className="ml-2 text-xs font-normal text-[#64748B] dark:text-[#94A3B8]">
|
||||||
|
{formatoPorcentaje(esquema.totalPagado / esquema.precio)} del precio
|
||||||
|
</span>
|
||||||
</dt>
|
</dt>
|
||||||
<dd className="text-sm font-semibold text-[#111827] dark:text-[#E2E8F0]">
|
<dd className="text-sm font-semibold text-[#111827] dark:text-[#E2E8F0]">
|
||||||
{formatoMoneda(esquema.totalPagado)}
|
{formatoMoneda(esquema.totalPagado)}
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
{esquema.engancheAdicional > 0 && (
|
|
||||||
<div className="flex flex-col gap-1 py-2 sm:flex-row sm:items-center sm:justify-between">
|
|
||||||
<dt className="text-sm text-[#64748B] dark:text-[#94A3B8]">Enganche adicional</dt>
|
|
||||||
<dd className="text-sm font-medium text-[#111827] dark:text-[#E2E8F0]">
|
|
||||||
{formatoMoneda(esquema.engancheAdicional)}
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="flex flex-col gap-1 py-2 sm:flex-row sm:items-center sm:justify-between">
|
<div className="flex flex-col gap-1 py-2 sm:flex-row sm:items-center sm:justify-between">
|
||||||
<dt className="text-sm font-semibold text-[#111827] dark:text-[#E2E8F0]">
|
<dt className="text-sm font-semibold text-[#111827] dark:text-[#E2E8F0]">
|
||||||
Saldo a financiar
|
Saldo a financiar
|
||||||
@@ -163,31 +175,6 @@ export function EsquemaPanel({
|
|||||||
</dl>
|
</dl>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Enganche adicional: anticipo extra hasta completar 90% del precio */}
|
|
||||||
<section className="rounded-xl border border-[#E5E7EB] bg-white p-6 dark:border-[#1E293B] dark:bg-[#1E293B] shadow-sm">
|
|
||||||
<label htmlFor="enganche-adicional" className="mb-2 block text-xs font-medium text-[#4B5563] dark:text-[#CBD5E1]">
|
|
||||||
Enganche adicional (opcional)
|
|
||||||
</label>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<span className="text-sm text-[#64748B] dark:text-[#94A3B8]">$</span>
|
|
||||||
<input
|
|
||||||
id="enganche-adicional"
|
|
||||||
type="number"
|
|
||||||
min={0}
|
|
||||||
max={engancheAdicionalMaximo}
|
|
||||||
step={1000}
|
|
||||||
value={engancheAdicional === 0 ? '' : engancheAdicional}
|
|
||||||
placeholder="0"
|
|
||||||
onChange={(e) => onEngancheAdicional(e.target.value === '' ? 0 : Number(e.target.value))}
|
|
||||||
className="w-full rounded-lg border border-[#D1D5DB] bg-white px-3 py-2.5 text-sm transition-colors focus:border-accent focus:ring-2 focus:ring-accent/20 focus:outline-none dark:bg-[#0F172A] dark:border-[#334155] dark:text-[#E2E8F0]"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<p className="mt-1 text-xs text-[#64748B] dark:text-[#94A3B8]">
|
|
||||||
Anticipo extra del cliente; máximo {formatoMoneda(engancheAdicionalMaximo)} para no pasar del{' '}
|
|
||||||
{formatoPorcentaje(PCT_ENGANCHE_MAXIMO)} de enganche total (queda un mínimo del 10% por financiar)
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* Controles del diferimiento */}
|
{/* Controles del diferimiento */}
|
||||||
<section className="flex flex-col gap-4 rounded-xl border border-[#E5E7EB] bg-white p-6 dark:border-[#1E293B] dark:bg-[#1E293B] shadow-sm sm:flex-row sm:items-end">
|
<section className="flex flex-col gap-4 rounded-xl border border-[#E5E7EB] bg-white p-6 dark:border-[#1E293B] dark:bg-[#1E293B] shadow-sm sm:flex-row sm:items-end">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
|
|||||||
@@ -792,9 +792,14 @@ export default function CotizadorPage() {
|
|||||||
esquema={resultado}
|
esquema={resultado}
|
||||||
fechaEntrega={unidad?.fechaEntrega ?? null}
|
fechaEntrega={unidad?.fechaEntrega ?? null}
|
||||||
maxMensualidades={unidad ? mensualidadesParaUnidad(unidad) : MENSUALIDADES_MAX}
|
maxMensualidades={unidad ? mensualidadesParaUnidad(unidad) : MENSUALIDADES_MAX}
|
||||||
engancheAdicional={engancheAdicional}
|
engancheBase={resultado.enganche}
|
||||||
onEngancheAdicional={setEngancheAdicional}
|
engancheTotal={resultado.enganche + engancheAdicional}
|
||||||
engancheAdicionalMaximo={engancheAdicionalMaximo}
|
onEngancheTotal={(v) =>
|
||||||
|
setEngancheAdicional(
|
||||||
|
Math.min(Math.max(0, v - resultado.enganche), engancheAdicionalMaximo),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
engancheMax={resultado.enganche + engancheAdicionalMaximo}
|
||||||
numMensualidades={numMensualidades}
|
numMensualidades={numMensualidades}
|
||||||
onNumMensualidades={setNumMensualidades}
|
onNumMensualidades={setNumMensualidades}
|
||||||
escrituracionDiferida={escrituracionDiferida}
|
escrituracionDiferida={escrituracionDiferida}
|
||||||
|
|||||||
Reference in New Issue
Block a user