fix(afluencia): validación duplicados + campos nombre + fix lada

- Lead creation: validación por email y teléfono normalizados (últimos 10 dígitos)
- Si ya existe lead con mismo email/teléfono → 409 con aviso
- Alta Afluencia: nombre dividido en Nombre(s), Apellido Paterno, Apellido Materno
- Fix lada: strip robusto de +52 y +1 con/sin espacio
- Backend + frontend actualizados
This commit is contained in:
2026-09-08 09:36:46 +00:00
parent 06d4e154a5
commit f648430da0
3 changed files with 73 additions and 12 deletions

View File

@@ -39,6 +39,9 @@ interface Errores {
const FORM_INICIAL = {
nombre: '',
nombrePila: '',
apellidoPaterno: '',
apellidoMaterno: '',
telefono: '',
email: '',
origen: '',
@@ -95,7 +98,12 @@ export default function AltaAfluenciaForm({ onVolver, onPasarAAltaCliente, valor
// Teléfono con prefijo internacional: separa lada y número para el selector
const tel = lead.telefono.trim()
const esUsa = tel.startsWith('+1')
const numero = tel.startsWith('+1') ? tel.slice(2).trim() : tel.startsWith('+52') ? tel.slice(3).trim() : tel
// Strip lada: +52 or +1 prefix
let numero = tel
if (tel.startsWith('+52 ')) numero = tel.slice(4).trim()
else if (tel.startsWith('+52')) numero = tel.slice(3).trim()
else if (tel.startsWith('+1 ')) numero = tel.slice(3).trim()
else if (tel.startsWith('+1')) numero = tel.slice(2).trim()
setLada(esUsa ? 'US' : 'MX')
setForm((prev) => {
const desarrollo =
@@ -107,9 +115,17 @@ export default function AltaAfluenciaForm({ onVolver, onPasarAAltaCliente, valor
lead.modeloInteres !== undefined && (modelos as readonly string[]).includes(lead.modeloInteres)
? lead.modeloInteres
: ''
// Split name: lead.nombre may contain full name or just first name
const partes = lead.nombre.trim().split(/\s+/)
const nombrePila = partes[0] || ''
const apellidoPaterno = partes.length > 1 ? partes[1] : ''
const apellidoMaterno = partes.length > 2 ? partes.slice(2).join(' ') : ''
return {
...prev,
nombre: lead.nombre,
nombrePila,
apellidoPaterno,
apellidoMaterno,
telefono: numero,
email: lead.email,
origen: (ORIGENES_LEAD as readonly string[]).includes(lead.origen) ? lead.origen : prev.origen,
@@ -142,7 +158,7 @@ export default function AltaAfluenciaForm({ onVolver, onPasarAAltaCliente, valor
const telefono =
numeroTel === '' ? '' : numeroTel.startsWith('+') ? numeroTel : `${lada === 'US' ? '+1' : '+52'} ${numeroTel}`
const res = await crearAfluencia({
nombre: form.nombre.trim(),
nombre: [form.nombrePila, form.apellidoPaterno, form.apellidoMaterno].filter(Boolean).join(' ').trim() || form.nombre.trim(),
telefono,
...(oportunidadId !== undefined ? { oportunidadId } : {}),
...(form.email.trim() ? { email: form.email.trim() } : {}),
@@ -165,7 +181,7 @@ export default function AltaAfluenciaForm({ onVolver, onPasarAAltaCliente, valor
if (res.ok) {
setLeadCreado({
id: res.lead.id,
nombre: form.nombre.trim(),
nombre: [form.nombrePila, form.apellidoPaterno, form.apellidoMaterno].filter(Boolean).join(' ').trim() || form.nombre.trim(),
telefono,
email: form.email.trim(),
estado: res.lead.estado,
@@ -262,20 +278,42 @@ export default function AltaAfluenciaForm({ onVolver, onPasarAAltaCliente, valor
</div>
)}
<div className="grid gap-6 sm:grid-cols-2">
<label htmlFor="afluencia-nombre" className="block sm:col-span-2">
<label htmlFor="afluencia-nombre-pila" className="block">
<span className={labelClase}>
Nombre<span className="text-red-700"> *</span>
Nombre(s)<span className="text-red-700"> *</span>
</span>
<input
id="afluencia-nombre"
id="afluencia-nombre-pila"
type="text"
value={form.nombre}
onChange={cambiar('nombre')}
value={form.nombrePila}
onChange={cambiar('nombrePila')}
className={`${inputClase} ${errores.nombre ? 'border-red-400' : ''}`}
/>
{errores.nombre && <p className="mt-1 text-xs text-red-700">{errores.nombre}</p>}
</label>
<label htmlFor="afluencia-apellido-paterno" className="block">
<span className={labelClase}>Apellido paterno</span>
<input
id="afluencia-apellido-paterno"
type="text"
value={form.apellidoPaterno}
onChange={cambiar('apellidoPaterno')}
className={inputClase}
/>
</label>
<label htmlFor="afluencia-apellido-materno" className="block">
<span className={labelClase}>Apellido materno</span>
<input
id="afluencia-apellido-materno"
type="text"
value={form.apellidoMaterno}
onChange={cambiar('apellidoMaterno')}
className={inputClase}
/>
</label>
<div>
<label htmlFor="afluencia-telefono" className={labelClase}>
Teléfono<span className="text-red-700"> *</span>