fix(alta-cliente/afluencia): telefono limitado a 10 digitos, normalizacion de valores heredados con lada duplicada o caracteres invisibles
This commit is contained in:
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
|
||||
@@ -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', '']),
|
||||
|
||||
Reference in New Issue
Block a user