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,
|
nombrePila,
|
||||||
apellidoPaterno,
|
apellidoPaterno,
|
||||||
apellidoMaterno,
|
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,
|
email: lead.email,
|
||||||
origen: (ORIGENES_LEAD as readonly string[]).includes(lead.origen) ? lead.origen : prev.origen,
|
origen: (ORIGENES_LEAD as readonly string[]).includes(lead.origen) ? lead.origen : prev.origen,
|
||||||
desarrollo,
|
desarrollo,
|
||||||
@@ -173,6 +178,9 @@ export default function AltaAfluenciaForm({ onVolver, onPasarAAltaCliente, valor
|
|||||||
const nombreCompuesto = nombreCompleto()
|
const nombreCompuesto = nombreCompleto()
|
||||||
if (nombreCompuesto === '') nuevos.nombrePila = 'El nombre es obligatorio'
|
if (nombreCompuesto === '') nuevos.nombrePila = 'El nombre es obligatorio'
|
||||||
if (!form.telefono.trim()) nuevos.telefono = 'El teléfono 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) {
|
if (form.email.trim() && !emailSchema.safeParse(form.email).success) {
|
||||||
nuevos.email = 'Correo electrónico inválido'
|
nuevos.email = 'Correo electrónico inválido'
|
||||||
}
|
}
|
||||||
@@ -423,13 +431,19 @@ export default function AltaAfluenciaForm({ onVolver, onPasarAAltaCliente, valor
|
|||||||
<input
|
<input
|
||||||
id="afluencia-telefono"
|
id="afluencia-telefono"
|
||||||
type="tel"
|
type="tel"
|
||||||
placeholder="664 123 4567"
|
inputMode="numeric"
|
||||||
|
maxLength={10}
|
||||||
|
placeholder="6641234567"
|
||||||
value={form.telefono}
|
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
|
required
|
||||||
className={`${inputClase} ${errores.telefono ? 'border-red-400' : ''}`}
|
className={`${inputClase} ${errores.telefono ? 'border-red-400' : ''}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</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>}
|
{errores.telefono && <p className="mt-1 text-xs text-red-700">{errores.telefono}</p>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -117,10 +117,17 @@ export function CampoTelefono({ nombre, etiqueta, requerido, className }: CampoB
|
|||||||
const { watch, setValue, formState: { errors } } = useFormContext()
|
const { watch, setValue, formState: { errors } } = useFormContext()
|
||||||
const valor = ((watch(nombre) as string) ?? '').trim()
|
const valor = ((watch(nombre) as string) ?? '').trim()
|
||||||
const lada = valor.startsWith('+1') ? '+1' : '+52'
|
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 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
|
// Vacío se guarda vacío (sin prefijo huérfano); con número, compuesto
|
||||||
setValue(nombre, limpio === '' ? '' : `${nuevaLada} ${limpio}`, { shouldValidate: true })
|
setValue(nombre, limpio === '' ? '' : `${nuevaLada} ${limpio}`, { shouldValidate: true })
|
||||||
}
|
}
|
||||||
@@ -144,12 +151,15 @@ export function CampoTelefono({ nombre, etiqueta, requerido, className }: CampoB
|
|||||||
<input
|
<input
|
||||||
id={nombre}
|
id={nombre}
|
||||||
type="tel"
|
type="tel"
|
||||||
placeholder="664 123 4567"
|
inputMode="numeric"
|
||||||
|
maxLength={10}
|
||||||
|
placeholder="6641234567"
|
||||||
value={numero}
|
value={numero}
|
||||||
onChange={(e) => actualizar(lada, e.target.value)}
|
onChange={(e) => actualizar(lada, e.target.value)}
|
||||||
className={claseInput(nombre, errors)}
|
className={claseInput(nombre, errors)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<p className="mt-1 text-xs text-[#64748B] dark:text-[#94A3B8]">10 dígitos, sin lada</p>
|
||||||
<MensajeError nombre={nombre} />
|
<MensajeError nombre={nombre} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -62,8 +62,16 @@ export const datosGeneralesSchema = z
|
|||||||
peso: textoOpcional,
|
peso: textoOpcional,
|
||||||
estatura: textoOpcional,
|
estatura: textoOpcional,
|
||||||
email: z.string().trim().email('Correo electrónico inválido'),
|
email: z.string().trim().email('Correo electrónico inválido'),
|
||||||
telCasa: textoOpcional,
|
// Teléfonos: 10 dígitos (con o sin lada compuesta; el campo sólo acepta
|
||||||
celular: z.string().trim().min(8, 'El celular es requerido'),
|
// 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,
|
viviendaAnios: textoOpcional,
|
||||||
tipoVivienda: z.enum(['PRESTADA', 'RENTADA', 'FAMILIAR', 'PROPIA', '']),
|
tipoVivienda: z.enum(['PRESTADA', 'RENTADA', 'FAMILIAR', 'PROPIA', '']),
|
||||||
tipoCompra: z.enum(['INVERSION', 'VIVIR_AHI', '']),
|
tipoCompra: z.enum(['INVERSION', 'VIVIR_AHI', '']),
|
||||||
|
|||||||
Reference in New Issue
Block a user