import { useMemo, useState } from 'react' import type { Unidad, TipoPropuesta } from '../types' import { compararUnidades, type ColumnaComparador } from '../lib/comparadorUnidades' import { formatoMoneda } from '../lib/formatters' import { SIN_REGLAS, desarrolloEfectivo, idsCotizables, type ReglasDesarrollo } from '../lib/reglas' interface Props { unidades: Unidad[] /** Tipo de propuesta activa en el cotizador (se aplica a ambas unidades) */ tipo: TipoPropuesta apartado: number acabados: boolean /** Reglas comerciales por desarrollo (vacío => constantes) */ reglas?: ReglasDesarrollo } const formatoM2 = (v: number | null): string => (v === null ? '—' : `${v.toLocaleString('es-MX')} m²`) interface Fila { etiqueta: string obtener: (c: ColumnaComparador) => string destacada?: boolean } /** * Comparador de 2 unidades (del mismo o distinto desarrollo), lado a lado, * con la propuesta activa calculada por el motor con los parámetros de cada * desarrollo (las reglas del admin con respaldo en las constantes). Solo ofrece * unidades DISPONIBLES de desarrollos activos en el cotizador: no se compara * (ni se cotiza) inventario apartado, vendido, bloqueado o desactivado. */ export function ComparadorUnidades({ unidades, tipo, apartado, acabados, reglas = SIN_REGLAS }: Props) { const [abierto, setAbierto] = useState(false) const [codigoA, setCodigoA] = useState('') const [codigoB, setCodigoB] = useState('') const desarrollos = useMemo(() => idsCotizables(reglas), [reglas]) const disponibles = useMemo( () => unidades.filter( (u) => (u.status ?? '').trim().toUpperCase() === 'DISPONIBLE' && desarrollos.includes(u.desarrollo ?? 'DIAGONAL'), ), [unidades, desarrollos], ) const porCodigo = useMemo(() => { const m = new Map() for (const u of disponibles) m.set(`${u.desarrollo ?? 'DIAGONAL'}|${u.codigo}`, u) return m }, [disponibles]) const unidadA = porCodigo.get(codigoA) ?? null const unidadB = porCodigo.get(codigoB) ?? null const comparacion = useMemo( () => unidadA && unidadB ? compararUnidades(unidadA, unidadB, tipo, apartado, acabados, reglas) : null, [unidadA, unidadB, tipo, apartado, acabados, reglas], ) const filas: Fila[] = [ { etiqueta: 'Desarrollo', obtener: (c) => c.desarrolloNombre }, { etiqueta: 'Modelo', obtener: (c) => c.unidad.modelo }, { etiqueta: 'Estatus', obtener: (c) => c.unidad.status }, { etiqueta: 'Sup. construcción', obtener: (c) => formatoM2(c.supConstruccion) }, { etiqueta: 'Precio de lista', obtener: (c) => formatoMoneda(c.precioLista) }, { etiqueta: 'Precio final c/desc.', obtener: (c) => formatoMoneda(c.propuesta.precioFinal) }, { etiqueta: 'Enganche', obtener: (c) => formatoMoneda(c.propuesta.enganche) }, { etiqueta: 'Mensualidad', obtener: (c) => c.propuesta.notaMensualidades ? `— (${c.propuesta.notaMensualidades})` : c.propuesta.mensualidad === null ? 'N/A' : `${c.propuesta.numMensualidades} × ${formatoMoneda(c.propuesta.mensualidad)}`, }, { etiqueta: 'Pago final', obtener: (c) => formatoMoneda(c.propuesta.pagoFinal) }, { etiqueta: 'Total pagado', obtener: (c) => (c.total === null ? '—' : formatoMoneda(c.total)), destacada: true, }, ] const selector = (id: string, valor: string, onChange: (v: string) => void, etiqueta: string) => (
) return (

Comparar unidades

{abierto && (
{selector('comparador-a', codigoA, setCodigoA, 'Unidad A')} {selector('comparador-b', codigoB, setCodigoB, 'Unidad B')}
{!comparacion ? (

Selecciona dos unidades para ver la comparación lado a lado.

) : (
{[comparacion.a, comparacion.b].map((c) => ( ))} {filas.map((fila) => ( {[comparacion.a, comparacion.b].map((c) => ( ))} ))}
Concepto {c.unidad.codigo}
{fila.etiqueta} {fila.obtener(c)}

Solo se ofrecen unidades DISPONIBLES. Cada unidad se calcula con los parámetros de su desarrollo y el mismo apartado. El enganche ya incluye la deducción del apartado.

)}
)}
) }