import { useFormContext, get } from 'react-hook-form' export interface CampoBaseProps { nombre: string etiqueta: string requerido?: boolean className?: string } const inputClase = 'w-full rounded-lg border border-[#D1D5DB] bg-white px-3 dark:border-[#334155] dark:bg-[#0F172A] dark:text-[#E2E8F0] py-2.5 text-sm uppercase transition-colors focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/20' const labelClase = 'mb-1 block text-xs font-medium text-[#4B5563] dark:text-[#CBD5E1]' function Etiqueta({ etiqueta, requerido }: { etiqueta: string; requerido?: boolean }) { return ( {etiqueta} {requerido && *} ) } /** Clase del input según haya error de validación */ function claseInput(nombre: string, errors: unknown): string { return get(errors, nombre) ? `${inputClase} border-red-400` : inputClase } export function MensajeError({ nombre }: { nombre: string }) { const { formState: { errors }, } = useFormContext() const error = get(errors, nombre) if (!error) return null return

{String(error.message)}

} interface CampoTextoProps extends CampoBaseProps { tipo?: string placeholder?: string soloLectura?: boolean } /** Input de texto conectado a react-hook-form (soporta rutas anidadas con punto) */ export function CampoTexto({ nombre, etiqueta, tipo = 'text', placeholder, requerido, soloLectura, className }: CampoTextoProps) { const { register, formState: { errors } } = useFormContext() return ( ) } interface CampoNumeroProps extends CampoBaseProps { paso?: string } /** Input numérico; cadena vacía se guarda como 0 */ export function CampoNumero({ nombre, etiqueta, requerido, paso = '0.01', className }: CampoNumeroProps) { const { register, formState: { errors } } = useFormContext() return ( ) } interface CampoSelectProps extends CampoBaseProps { opciones: { valor: string; etiqueta: string }[] } /** CampoSelect (dropdown) conectado a react-hook-form */ export function CampoSelect({ nombre, etiqueta, opciones, requerido, className }: CampoSelectProps) { const { register, formState: { errors } } = useFormContext() return ( ) } /** * Teléfono con selector de lada (México +52 / USA +1). El campo del formulario * guarda el valor compuesto " " (p. ej. "+52 6641234567"); * el dedup del API compara por los últimos 10 dígitos, así que no afecta. */ export function CampoTelefono({ nombre, etiqueta, requerido, className }: CampoBaseProps) { const { watch, setValue, formState: { errors } } = useFormContext() const valor = ((watch(nombre) as string) ?? '').trim() const lada = valor.startsWith('+1') ? '+1' : '+52' // 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) => { // 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 }) } return (
actualizar(lada, e.target.value)} className={claseInput(nombre, errors)} />

10 dígitos, sin lada

) }