Hey everyone I have the following code below and I am having trouble getting the error of 'Invalid domain structure' to show up in the input error property. I simply get an object that looks like this even when theres text in the field I want to get domain is invalid. To be clear this isn't an email I am validating I wanna validate specifically a domain. Thanks
import Button from '@/components/Button/Button';
import { useCallback, useMemo } from 'react';
import { useForm, SubmitHandler, FieldError } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import { twMerge } from 'tailwind-merge';
import { useLogin } from '@/services/auth/hooks/useLogin';
const schema = z.object({
vendor: z
.string()
.min(1, { message: 'Vendor is required' }) // Custom required message
.regex(/^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/, { message: 'Invalid domain structure' }),
});
interface FormData {
vendor: string;
}
interface InputProps extends LabelInputProps {
placeHolder: string;
}
const Input = ({ id, placeHolder, networkError, inputError, type }: InputProps) => {
return (
<div className="relative mt-2">
<input
id={id}
type={type}
placeholder={placeHolder}
className={twMerge(
`w-full border-[1px] pl-3 pr-${networkError ? '10' : '4'} py-2 text-sm rounded-sm`,
networkError || inputError ? 'border-error-color focus:border-error-color focus:ring-error-color' : 'border-gray-300'
)}
/>
{inputError && <p className="text-sm text-red-500">{inputError.message}</p>}
</div>
);
};
const Label = ({ htmlFor, name }: { htmlFor: string; name: string }) => (
<label htmlFor={htmlFor} className="w-full text-sm font-bold flex">
{name} <div className="text-red-500">*</div>
</label>
);
const upperCaseFirstLetter = (name: string) => name.charAt(0).toUpperCase() + name.slice(1);
interface LabelInputProps {
id: string;
type?: 'text';
networkError?: Error | null;
inputError?: FieldError;
}
const LabeledInput = ({ id, type, networkError, inputError }: LabelInputProps) => {
const name = useMemo(() => upperCaseFirstLetter(id), [id]);
return (
<>
<Label htmlFor={id} name={name} />
<Input id={id} type={type} placeHolder={name} networkError={networkError} inputError={inputError} />
</>
);
};
const SignInText = () => <div className="text-sm font-normal text-gray-600">Enter your vendor email</div>;
const Form = () => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<FormData>({ resolver: zodResolver(schema) });
const onSubmit: SubmitHandler<FormData> = useCallback((formData: FormData) => {
console.log(formData);
// loginHandler({ type: AuthenticationType.AwsCognito, navigate, user });
// gonna write my a vender handler
}, []);
const { loginHandler, error: networkError } = useLogin();
return (
<div className="w-1/4 mt-4 mx-auto p-6 bg-white rounded-lg shadow-md border border-gray-200">
{networkError && <p className="text-red-500 text-sm">{networkError.message}</p>}
<SignInText />
<form className="mt-4" onSubmit={handleSubmit(onSubmit)}>
<LabeledInput id="vendor" type="text" networkError={networkError} inputError={errors.vendor} />
<Button className="mt-4 w-full bg-blue-500 text-white hover:bg-blue-600 rounded-md py-2">Submit</Button>
</form>
</div>
);
};
export default Form;
Looks like like you're not registering the field under your form; rather, you're just passing an associated id
to the input: https://www.react-hook-form.com/api/useform/register/. For a more controlled wrapper component, you may also leverage Controller
or useController
: https://www.react-hook-form.com/api/usecontroller/controller/.
Your regex seems to resolve as you've described.