fix(alta-cliente/afluencia): telefono limitado a 10 digitos, normalizacion de valores heredados con lada duplicada o caracteres invisibles

This commit is contained in:
2026-09-29 19:33:36 +00:00
parent 438e3c85af
commit 17afcc9d8f
3 changed files with 40 additions and 8 deletions

View File

@@ -155,7 +155,12 @@ export default function AltaAfluenciaForm({ onVolver, onPasarAAltaCliente, valor
nombrePila,
apellidoPaterno,
apellidoMaterno,
telefono: numero,
telefono: (() => {
// Normaliza a dígitos y toma los últimos 10 (limpia ladas duplicadas,
// espacios inseparables y marcas invisibles de copiar/pegar)
const soloDigitos = numero.replace(/\D/g, '')
return soloDigitos.length > 10 ? soloDigitos.slice(-10) : soloDigitos
})(),
email: lead.email,
origen: (ORIGENES_LEAD as readonly string[]).includes(lead.origen) ? lead.origen : prev.origen,
desarrollo,
@@ -173,6 +178,9 @@ export default function AltaAfluenciaForm({ onVolver, onPasarAAltaCliente, valor
const nombreCompuesto = nombreCompleto()
if (nombreCompuesto === '') nuevos.nombrePila = 'El nombre es obligatorio'
if (!form.telefono.trim()) nuevos.telefono = 'El teléfono es obligatorio'
else if (form.telefono.replace(/\D/g, '').length !== 10) {
nuevos.telefono = 'El teléfono debe tener exactamente 10 dígitos'
}
if (form.email.trim() && !emailSchema.safeParse(form.email).success) {
nuevos.email = 'Correo electrónico inválido'
}
@@ -423,13 +431,19 @@ export default function AltaAfluenciaForm({ onVolver, onPasarAAltaCliente, valor
<input
id="afluencia-telefono"
type="tel"
inputMode="numeric"
maxLength={10}
placeholder="6641234567"
value={form.telefono}
onChange={cambiar('telefono')}
onChange={(e) => {
setForm((prev) => ({ ...prev, telefono: e.target.value.replace(/\D/g, '').slice(0, 10) }))
setErrores((prev) => ({ ...prev, telefono: undefined }))
}}
required
className={`${inputClase} ${errores.telefono ? 'border-red-400' : ''}`}
/>
</div>
<p className="mt-1 text-xs text-[#64748B] dark:text-[#94A3B8]">10 dígitos, sin lada (la lada va en el selector)</p>
{errores.telefono && <p className="mt-1 text-xs text-red-700">{errores.telefono}</p>}
</div>

View File

@@ -117,10 +117,17 @@ export function CampoTelefono({ nombre, etiqueta, requerido, className }: CampoB
const { watch, setValue, formState: { errors } } = useFormContext()
const valor = ((watch(nombre) as string) ?? '').trim()
const lada = valor.startsWith('+1') ? '+1' : '+52'
const numero = valor.startsWith('+1') ? valor.slice(2).trim() : valor.startsWith('+52') ? valor.slice(3).trim() : valor
// Normaliza lo que se muestra: dígitos, últimos 10 (limpia ladas duplicadas
// o caracteres invisibles heredados de registros viejos)
const numero = (() => {
const crudo = valor.startsWith('+1') ? valor.slice(2).trim() : valor.startsWith('+52') ? valor.slice(3).trim() : valor
const d = crudo.replace(/\D/g, '')
return d.length > 10 ? d.slice(-10) : d
})()
const actualizar = (nuevaLada: string, nuevoNumero: string) => {
const limpio = nuevoNumero.trim()
// Sólo dígitos y máximo 10 (la lada va en el selector)
const limpio = nuevoNumero.replace(/\D/g, '').slice(0, 10)
// Vacío se guarda vacío (sin prefijo huérfano); con número, compuesto
setValue(nombre, limpio === '' ? '' : `${nuevaLada} ${limpio}`, { shouldValidate: true })
}
@@ -144,12 +151,15 @@ export function CampoTelefono({ nombre, etiqueta, requerido, className }: CampoB
<input
id={nombre}
type="tel"
inputMode="numeric"
maxLength={10}
placeholder="6641234567"
value={numero}
onChange={(e) => actualizar(lada, e.target.value)}
className={claseInput(nombre, errors)}
/>
</div>
<p className="mt-1 text-xs text-[#64748B] dark:text-[#94A3B8]">10 dígitos, sin lada</p>
<MensajeError nombre={nombre} />
</div>
)

View File

@@ -62,8 +62,16 @@ export const datosGeneralesSchema = z
peso: textoOpcional,
estatura: textoOpcional,
email: z.string().trim().email('Correo electrónico inválido'),
telCasa: textoOpcional,
celular: z.string().trim().min(8, 'El celular es requerido'),
// Teléfonos: 10 dígitos (con o sin lada compuesta; el campo sólo acepta
// dígitos en la UI, así que aquí sólo se valida la longitud mínima)
telCasa: z
.string()
.trim()
.refine((v) => v === '' || v.replace(/\D/g, '').length >= 10, 'El teléfono debe tener 10 dígitos'),
celular: z
.string()
.trim()
.refine((v) => v.replace(/\D/g, '').length >= 10, 'El celular debe tener 10 dígitos'),
viviendaAnios: textoOpcional,
tipoVivienda: z.enum(['PRESTADA', 'RENTADA', 'FAMILIAR', 'PROPIA', '']),
tipoCompra: z.enum(['INVERSION', 'VIVIR_AHI', '']),