feat(cotizador): historial, compartir WhatsApp, folio+QR, comparador de unidades, alertas de inventario
- Mis cotizaciones (guardar con cliente, retomar, nueva) asociadas al vendedor del token - Compartir: resumen copiable + deep link wa.me; PDF con folio, vigencia y QR - GET /api/cotizaciones/:id/publico (público, datos mínimos sin PII del cliente) - Comparador lado a lado de 2 unidades (mismo o distinto desarrollo) - POST /api/cotizaciones/alertas-inventario: avisa al vendedor si una unidad cotizada cambia de estatus (dedup; wire con syncs documentado) - Fix: labels de propuesta mapeados a los reales del board Oportunidades - Tests: api 201, cotizador 82
This commit is contained in:
@@ -28,9 +28,27 @@ interface UseCotizacionResult {
|
||||
errorApartado: string | null
|
||||
descuentos: DescuentosPropuestas
|
||||
setDescuento: (clave: keyof DescuentosPropuestas, valor: number) => void
|
||||
/** Índice de la propuesta elegida (para guardar/compartir) */
|
||||
propuestaIndex: number
|
||||
setPropuestaIndex: (i: number) => void
|
||||
precioLista: number
|
||||
numMeses: number | null
|
||||
propuestas: PropuestaResultado[]
|
||||
/** Restaura el estado completo desde una cotización guardada (historial) */
|
||||
restaurar: (estado: EstadoRestaurar) => void
|
||||
/** Reinicia la cotización (botón "Nueva") */
|
||||
nueva: () => void
|
||||
}
|
||||
|
||||
export interface EstadoRestaurar {
|
||||
desarrollo: string
|
||||
/** Unidad ya resuelta del inventario cargado */
|
||||
unidad: Unidad
|
||||
acabados: boolean
|
||||
apartado: number
|
||||
/** Descuento (fracción) de la propuesta elegida; se aplica sobre su clave */
|
||||
descuento?: number
|
||||
propuestaIndex?: number
|
||||
}
|
||||
|
||||
/** Estado central de la cotización: desarrollo, unidad, acabados, apartado y descuentos */
|
||||
@@ -40,6 +58,7 @@ export function useCotizacion(): UseCotizacionResult {
|
||||
const [acabados, setAcabados] = useState(false)
|
||||
const [apartado, setApartado] = useState<number>(APARTADO_DEFAULT)
|
||||
const [descuentos, setDescuentos] = useState<DescuentosPropuestas>(descuentosDefault(DESARROLLO_DEFAULT))
|
||||
const [propuestaIndex, setPropuestaIndex] = useState(0)
|
||||
|
||||
const params = obtenerDesarrollo(desarrollo)
|
||||
|
||||
@@ -48,12 +67,36 @@ export function useCotizacion(): UseCotizacionResult {
|
||||
setUnidad(null)
|
||||
setAcabados(false)
|
||||
setDescuentos(descuentosDefault(id))
|
||||
setPropuestaIndex(0)
|
||||
}
|
||||
|
||||
const setDescuento = (clave: keyof DescuentosPropuestas, valor: number) => {
|
||||
setDescuentos((prev) => ({ ...prev, [clave]: valor }))
|
||||
}
|
||||
|
||||
const restaurar = (estado: EstadoRestaurar) => {
|
||||
setDesarrolloState(estado.desarrollo)
|
||||
setUnidad(estado.unidad)
|
||||
setAcabados(estado.acabados)
|
||||
setApartado(estado.apartado)
|
||||
const base = descuentosDefault(estado.desarrollo)
|
||||
if (estado.descuento !== undefined) {
|
||||
const idx = estado.propuestaIndex ?? 0
|
||||
const clave = obtenerDesarrollo(estado.desarrollo).propuestas[idx]?.claveDescuento
|
||||
if (clave) base[clave] = estado.descuento
|
||||
}
|
||||
setDescuentos(base)
|
||||
setPropuestaIndex(estado.propuestaIndex ?? 0)
|
||||
}
|
||||
|
||||
const nueva = () => {
|
||||
setUnidad(null)
|
||||
setAcabados(false)
|
||||
setApartado(APARTADO_DEFAULT)
|
||||
setDescuentos(descuentosDefault(desarrollo))
|
||||
setPropuestaIndex(0)
|
||||
}
|
||||
|
||||
const numMeses = useMemo(
|
||||
() => (unidad ? resolverNumMensualidades(unidad, params) : null),
|
||||
[unidad, params],
|
||||
@@ -87,8 +130,12 @@ export function useCotizacion(): UseCotizacionResult {
|
||||
errorApartado,
|
||||
descuentos,
|
||||
setDescuento,
|
||||
propuestaIndex,
|
||||
setPropuestaIndex,
|
||||
precioLista,
|
||||
numMeses,
|
||||
propuestas,
|
||||
restaurar,
|
||||
nueva,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user