I want to validate a phone number. If it has a value then it should output "Invalid mobile number format". If it is blank, then it should output "Mobile number is required".
Currently, it always outputs as "Invalid mobile number format".
I'm using Zod
, react-hook-form
and libphonenumber-js
import { isValidPhoneNumber } from "libphonenumber-js";
...
const schema = zod.object({
firstName: zod
.string({
required_error: "First name is required.",
})
.nonempty("First name is required."),
lastName: zod
.string({
required_error: "Last name is required.",
})
.nonempty("Last name is required."),
contactNumber: zod
.string({
required_error: "Mobile number is required.",
})
.transform((value) => `+${value}`)
.refine(isValidPhoneNumber, "Invalid mobile number format.")
.transform((value) => value.slice(1)),
});
...
<Controller
control={control}
name="contactNumber"
rules={{ required: true }}
render={({ field: { ref, ...field }, ...props }) => (
<StyledPhoneInput
enableSearch
enableTerritories
specialLabel="Mobile number "
inputProps={{
ref,
required: true,
placeholder: "+84",
}}
country={"vn"}
autoFormat
field={field}
muiProps={{ required: true, fullWidth: true }}
{...props}
/>
)}
/>
I don't exactly know what constitutes a minimum valid phone number, but basically it seems you need to validate some minimum input on the contactNumber
field. From what I can tell, specifying required_error
prop only seems to require a defined value.
For example, if you had just firstName: zod.string({ required_error: "First name is required." })
then the value ""
is accepted while undefined
throws the error that "First name is required."
. The .nonempty
validator appears to coerce the string into a character array and assert that it is not empty.
You can assert the the contactNumber
also has some minimal, non-zero, amount of input.
Example:
contactNumber: zod
.string({
required_error: "Mobile number is required.",
})
.min(1, "Mobile number is required.")
.transform((value) => `+${value}`)
.refine(isValidPhoneNumber, "Invalid mobile number format.")
.transform((value) => value.slice(1)),
const schema = zod.object({
firstName: zod
.string({
required_error: "First name is required.",
})
.nonempty("First name is required."),
lastName: zod
.string({
required_error: "Last name is required.",
})
.nonempty("Last name is required."),
contactNumber: zod
.string({
required_error: "Mobile number is required.",
})
.min(10, "Mobile number is too short.")
.transform((value) => `+${value}`)
.refine(isValidPhoneNumber, "Invalid mobile number format.")
.transform((value) => value.slice(1)),
});
schema.parse({
firstName: "Norman",
lastName: "Newman",
contactNumber: undefined, // Number is required
});
schema.parse({
firstName: "Bob",
lastName: "Sacamano",
contactNumber: "5555555", // Too short
});
schema.parse({
firstName: "Cosmo",
lastName: "Kramer",
contactNumber: "2125555555", // Invalid format
});
const result = schema.parse({
firstName: "Jerry",
lastName: "Seinfeld",
contactNumber: "12125555555", // Valid
});