feat(ux): 17 mejoras de experiencia de usuario
Backend (10 endpoints nuevos): - Recordatorios personales (CRUD + tabla RecordatorioVendedor) - Lead scoring 0-100 (etapa+recencia+datos) - Dashboard mora (pagos vencidos, monto, días atraso) - Timeline de pagos (pagado/vence/futuro) - Perfil completo contacto (pagos+cotizaciones+docs+score) - Exportar contactos a CSV Frontend Mi día: - Resumen matutino (saludo+KPIs) - Historial visual lead (timeline) - Score badge 0-100 (verde/amarillo/rojo) - Vista kanban (drag & drop) Frontend Cobranza: - Dashboard mora (tabla+WhatsApp) - Timeline pagos visual (nodos coloreados) Frontend Alta Clientes: - Checklist documentos visual - Foto cliente (cámara) Frontend Landing: - Perfil contacto completo - Exportar contactos CSV Frontend Mi día (extras): - Comparativa mensual - KPIs dashboard (leads hoy, ventas, conversión) 806 tests, 5 apps construidas.
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { useFormContext } from 'react-hook-form'
|
||||
import { CampoTexto, CampoSelect, CampoTelefono } from '../components/Campos'
|
||||
import SectionCard from '../components/SectionCard'
|
||||
import { compararConDatos } from '../lib/curp'
|
||||
import { ESTADOS_CIVILES, REGIMENES_BIENES, TIPOS_VIVIENDA, TIPOS_COMPRA } from '../data/constantes'
|
||||
import { autocompletarPorCP } from '../data/cps'
|
||||
|
||||
interface Props {
|
||||
prefix: string
|
||||
@@ -11,7 +13,7 @@ interface Props {
|
||||
|
||||
/** Campos de datos generales; reutilizable con prefijo (cliente y co-acreditado) */
|
||||
export default function DatosGeneralesCampos({ prefix, compacto = false }: Props) {
|
||||
const { watch } = useFormContext()
|
||||
const { watch, setValue } = useFormContext()
|
||||
const p = (campo: string) => `${prefix}${campo}`
|
||||
const estadoCivil = watch(p('estadoCivil')) as string
|
||||
const curp = (watch(p('curp')) as string) ?? ''
|
||||
@@ -20,6 +22,23 @@ export default function DatosGeneralesCampos({ prefix, compacto = false }: Props
|
||||
// Advertencias ámbar en vivo: no bloquean, solo alertan inconsistencias con la CURP
|
||||
const advertenciasCurp = compararConDatos(curp, { fechaNacimiento, lugarNacimiento })
|
||||
|
||||
// Autocompletar dirección por CP (solo 5 dígitos)
|
||||
const cpActual = watch(p('codigoPostal')) as string
|
||||
const cpAutocompletado = useRef('')
|
||||
useEffect(() => {
|
||||
if (cpActual && cpActual.length === 5 && cpActual !== cpAutocompletado.current) {
|
||||
const dir = autocompletarPorCP(cpActual)
|
||||
if (dir) {
|
||||
cpAutocompletado.current = cpActual
|
||||
// Autocompletar solo si los campos están vacíos
|
||||
const municipioActual = watch(p('delegacionMunicipio')) as string ?? ''
|
||||
if (!municipioActual) {
|
||||
setValue(p('delegacionMunicipio'), dir.municipio)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [cpActual])
|
||||
|
||||
return (
|
||||
<SectionCard titulo="Datos generales">
|
||||
{!compacto && <CampoTexto nombre={p('campaniaVenta')} etiqueta="Campaña de la venta" />}
|
||||
|
||||
Reference in New Issue
Block a user