feat: ecosistema FRASA — apps Cotizador, Alta Clientes, Cobranza y Landing
- Cotizador (/quote): 4 propuestas con formulas validadas del Excel, comparador, combobox de unidades, vigencia, PDF ANEXO A - Alta Clientes (/client): wizard 8 pasos, validacion CURP RENAPO, OCR de INE, checklist de expediente, firma digital, 5 PDFs legales - Cobranza (/pay): planes de enganche, mora, vista cobranza del dia, recibos PDF, bitacora, dashboard con filtros - Landing (/): entrada al ecosistema - Design system StudioBlank (monocromo, acento #1B4332) en las 4 apps - 123 tests vitest
This commit is contained in:
65
apps/cotizador/src/hooks/useCotizacion.ts
Normal file
65
apps/cotizador/src/hooks/useCotizacion.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { useMemo, useState } from 'react'
|
||||
import type { Unidad, DescuentosPropuestas } from '../types'
|
||||
import {
|
||||
APARTADO_DEFAULT,
|
||||
DESCUENTOS_DEFAULT,
|
||||
calcularNumMensualidades,
|
||||
calcularPropuestas,
|
||||
obtenerPrecioLista,
|
||||
type PropuestaResultado,
|
||||
} from '../lib/calculations'
|
||||
|
||||
interface UseCotizacionResult {
|
||||
unidad: Unidad | null
|
||||
setUnidad: (u: Unidad | null) => void
|
||||
acabados: boolean
|
||||
setAcabados: (v: boolean) => void
|
||||
apartado: number
|
||||
setApartado: (v: number) => void
|
||||
descuentos: DescuentosPropuestas
|
||||
setDescuento: (clave: keyof DescuentosPropuestas, valor: number) => void
|
||||
precioLista: number
|
||||
numMeses: number
|
||||
propuestas: PropuestaResultado[]
|
||||
}
|
||||
|
||||
/** Estado central de la cotización: unidad, acabados, apartado y descuentos */
|
||||
export function useCotizacion(): UseCotizacionResult {
|
||||
const [unidad, setUnidad] = useState<Unidad | null>(null)
|
||||
const [acabados, setAcabados] = useState(false)
|
||||
const [apartado, setApartado] = useState<number>(APARTADO_DEFAULT)
|
||||
const [descuentos, setDescuentos] = useState<DescuentosPropuestas>({ ...DESCUENTOS_DEFAULT })
|
||||
|
||||
const setDescuento = (clave: keyof DescuentosPropuestas, valor: number) => {
|
||||
setDescuentos((prev) => ({ ...prev, [clave]: valor }))
|
||||
}
|
||||
|
||||
const numMeses = useMemo(
|
||||
() => (unidad ? calcularNumMensualidades(unidad.fechaEntrega) : 0),
|
||||
[unidad],
|
||||
)
|
||||
|
||||
const precioLista = useMemo(
|
||||
() => (unidad ? obtenerPrecioLista(unidad, acabados) : 0),
|
||||
[unidad, acabados],
|
||||
)
|
||||
|
||||
const propuestas = useMemo(() => {
|
||||
if (!unidad) return []
|
||||
return calcularPropuestas({ unidad, acabados, apartado, descuentos })
|
||||
}, [unidad, acabados, apartado, descuentos])
|
||||
|
||||
return {
|
||||
unidad,
|
||||
setUnidad,
|
||||
acabados,
|
||||
setAcabados,
|
||||
apartado,
|
||||
setApartado,
|
||||
descuentos,
|
||||
setDescuento,
|
||||
precioLista,
|
||||
numMeses,
|
||||
propuestas,
|
||||
}
|
||||
}
|
||||
38
apps/cotizador/src/hooks/useUnidades.ts
Normal file
38
apps/cotizador/src/hooks/useUnidades.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import type { Unidad } from '../types'
|
||||
import { getUnidades } from '../services/api'
|
||||
|
||||
interface UseUnidadesResult {
|
||||
unidades: Unidad[]
|
||||
cargando: boolean
|
||||
error: string | null
|
||||
}
|
||||
|
||||
/** Carga el inventario de unidades (hoy desde seed; mañana desde el API Gateway) */
|
||||
export function useUnidades(): UseUnidadesResult {
|
||||
const [unidades, setUnidades] = useState<Unidad[]>([])
|
||||
const [cargando, setCargando] = useState(true)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
let activo = true
|
||||
getUnidades()
|
||||
.then((data) => {
|
||||
if (activo) {
|
||||
setUnidades(data)
|
||||
setCargando(false)
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
if (activo) {
|
||||
setError('No se pudo cargar el inventario de unidades.')
|
||||
setCargando(false)
|
||||
}
|
||||
})
|
||||
return () => {
|
||||
activo = false
|
||||
}
|
||||
}, [])
|
||||
|
||||
return { unidades, cargando, error }
|
||||
}
|
||||
Reference in New Issue
Block a user