Files
FRASA-CAS/apps/alta-clientes/src/forms/ViviendaCreditoForm.tsx

135 lines
6.5 KiB
TypeScript

import { useForm, FormProvider } from 'react-hook-form'
import { useEffect } from 'react'
import { zodResolver } from '@hookform/resolvers/zod'
import type { ViviendaCredito, TipoCredito } from '../types'
import { viviendaCreditoSchema } from '../lib/schemas'
import { CampoTexto, CampoSelect, MensajeError } from '../components/Campos'
import SectionCard from '../components/SectionCard'
import Navegacion from './Navegacion'
import type { PasoProps } from './DatosGeneralesForm'
import { PROYECTOS, MODELOS_POR_PROYECTO, TIPOS_CREDITO, TIPOS_PRODUCTO } from '../data/constantes'
/** Paso 6: datos de la vivienda, crédito e identificación oficial (PLD) */
export default function ViviendaCreditoForm({ valores, onAnterior, onSiguiente }: PasoProps<ViviendaCredito>) {
const metodos = useForm<ViviendaCredito>({
resolver: zodResolver(viviendaCreditoSchema),
defaultValues: valores,
mode: 'onSubmit',
})
const proyecto = metodos.watch('proyecto')
const tiposSeleccionados = metodos.watch('tiposCredito') ?? []
type Proyecto = (typeof PROYECTOS)[number]
const modelos = MODELOS_POR_PROYECTO[proyecto as Proyecto]
// Al cambiar de proyecto, limpia el modelo si no aplica en la lista nueva
useEffect(() => {
const actual = metodos.getValues('modelo')
if (modelos && actual && !modelos.includes(actual)) {
metodos.setValue('modelo', '', { shouldDirty: true })
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [proyecto])
/**
* El tipo de crédito es de selección ÚNICA (Infonavit, Apoyo Infonavit,
* Cofinavit, Segundo crédito, etc.). Se guarda como arreglo de un elemento
* para no cambiar el contrato de datos; volver a tocar el elegido lo quita.
*/
const seleccionarCredito = (valor: TipoCredito) => {
const actuales = metodos.getValues('tiposCredito') ?? []
metodos.setValue('tiposCredito', actuales.includes(valor) ? [] : [valor], { shouldDirty: true })
}
return (
<FormProvider {...metodos}>
<form onSubmit={metodos.handleSubmit(onSiguiente)} noValidate>
<div>
<SectionCard titulo="Datos vivienda">
<CampoSelect
nombre="proyecto"
etiqueta="Proyecto"
requerido
opciones={PROYECTOS.map((p) => ({ valor: p, etiqueta: p === 'OTRO' ? 'Otro' : p }))}
/>
{proyecto === 'OTRO' && (
<CampoTexto nombre="proyectoOtro" etiqueta="Nombre del proyecto" requerido />
)}
{modelos ? (
<CampoSelect
nombre="modelo"
etiqueta="Modelo"
opciones={modelos.map((m) => ({ valor: m, etiqueta: m }))}
/>
) : (
<CampoTexto nombre="modelo" etiqueta="Modelo" />
)}
<CampoTexto nombre="manzana" etiqueta="Manzana" />
<CampoTexto nombre="lote" etiqueta="Lote" />
<CampoTexto nombre="ubicacion" etiqueta="Ubicación" />
<CampoTexto nombre="superficieM2" etiqueta="Superficie (m²)" />
<CampoTexto nombre="valorVenta" etiqueta="Valor venta ($)" />
<CampoTexto nombre="enganche" etiqueta="Enganche ($)" />
<CampoTexto nombre="equipamientoAdicional" etiqueta="Equipamiento adicional" />
<CampoTexto nombre="fechaPagoEnganche" etiqueta="Fecha pago de enganche" tipo="date" />
<CampoTexto nombre="firmaContrato" etiqueta="Firma de contrato" tipo="date" />
</SectionCard>
<SectionCard titulo="Tipo de crédito">
<div className="sm:col-span-2 lg:col-span-3">
<div className="flex flex-wrap gap-2">
{TIPOS_CREDITO.map((tc) => (
<label
key={tc.valor}
htmlFor={`tipoCredito-${tc.valor}`}
className={`cursor-pointer rounded-full border px-3 py-1.5 text-xs font-medium transition-all duration-100 ease-out ${
tiposSeleccionados.includes(tc.valor)
? 'border-accent bg-accent text-white shadow-sm'
: 'border-[#D1D5DB] bg-white text-[#4B5563] hover:border-accent hover:text-accent'
}`}
>
<input
id={`tipoCredito-${tc.valor}`}
type="radio"
name="tipoCreditoUnico"
className="sr-only"
checked={tiposSeleccionados.includes(tc.valor)}
onChange={() => seleccionarCredito(tc.valor)}
/>
{tc.etiqueta}
</label>
))}
</div>
</div>
<CampoTexto nombre="montoCreditoInfoFovi" etiqueta="Monto de crédito Info o Fovi ($)" />
<CampoTexto nombre="ahorroVoluntarioSubcuenta" etiqueta="Ahorro voluntario o subcuenta ($)" />
<CampoTexto nombre="descuentoMensualInfoFovissste" etiqueta="Desc. mensual Info o Fovissste ($)" />
<CampoSelect nombre="tipoProducto" etiqueta="Tipo de producto" opciones={TIPOS_PRODUCTO} />
</SectionCard>
<SectionCard
titulo="Identificación oficial (PLD)"
descripcion="Datos de la identificación vigente para los formatos de ley anti-lavado."
>
<CampoTexto nombre="idAutoridadEmisora" etiqueta="Autoridad que la emite" className="sm:col-span-2" />
<CampoTexto nombre="idNumero" etiqueta="Número de identificación" />
<CampoTexto nombre="idVigencia" etiqueta="Vigencia" tipo="date" />
</SectionCard>
<SectionCard titulo="Domicilio fiscal (opcional)" descripcion="Art. 29 y 29-A CFF.">
<CampoTexto nombre="domicilioFiscal.calle" etiqueta="Calle o avenida" className="sm:col-span-2" />
<CampoTexto nombre="domicilioFiscal.numExt" etiqueta="Núm. exterior" />
<CampoTexto nombre="domicilioFiscal.numInt" etiqueta="Núm. interior" />
<CampoTexto nombre="domicilioFiscal.colonia" etiqueta="Colonia" />
<CampoTexto nombre="domicilioFiscal.municipio" etiqueta="Municipio" />
<CampoTexto nombre="domicilioFiscal.estado" etiqueta="Estado" />
<CampoTexto nombre="domicilioFiscal.cp" etiqueta="Código postal" />
<CampoTexto nombre="domicilioFiscal.pais" etiqueta="País" />
</SectionCard>
</div>
<MensajeError nombre="proyectoOtro" />
<Navegacion onAnterior={onAnterior} />
</form>
</FormProvider>
)
}