79540438

Date: 2025-03-28 03:08:31
Score: 1.5
Natty:
Report link

There are some issues with your code. As the comment above said, the useForm is initialized once and as such, the conditional logic in the resolver and defaultValues won't do anything when the step changes. Here is what you need to do to make it work.

  1. Remove the login in the useForm initialization and use a single schema
  2. Use the trigger from react hook form to handle the form validation as the user move between steps.

Here is the full code:

import { z } from "zod";
import { useState } from "react";
import { useForm, Controller } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";

const formSchema = z.object({
  dateOfBirth: z.string().min(1, "Date of birth is required"),
  phoneNumber: z.string().min(5, "Phone number is required"),
  streetAddress: z.string().min(1, "Street address is required"),
  city: z.string().min(1, "City is required"),
  emergencyContactName: z.string().min(1, "Name is required"),
  emergencyContactPhone: z.string().min(5, "Phone number is required"),
  emergencyContactRelation: z.string().min(1, "Relation is required"),
  experienceLevel: z.enum(["none", "beginner", "intermediate", "advanced"], {
    errorMap: () => ({ message: "Experience Level is required" }),
  }),
  experienceDescription: z.string().optional(),
  hasMedicalCondition: z.enum(["yes", "no"], {
    errorMap: () => ({ message: "please select yes or no" }),
  }),
  consent: z.enum(["true"], {
    errorMap: () => ({ message: "You must agree to continue" }),
  }),
});

const OnboardPage = () => {
  const [step, setStep] = useState<1 | 2>(1);
  const {
    register,
    control,
    handleSubmit,
    formState: { errors },
    trigger,
  } = useForm({
    resolver: zodResolver(formSchema),
    mode: "onChange",
    defaultValues: {
      dateOfBirth: "",
      phoneNumber: "",
      streetAddress: "",
      city: "",
      emergencyContactName: "",
      emergencyContactPhone: "",
      emergencyContactRelation: "",
      experienceLevel: undefined,
      experienceDescription: "",
      hasMedicalCondition: "" as z.infer<
        typeof formSchema.shape.hasMedicalCondition
      >,
      consent: "" as z.infer<typeof formSchema.shape.consent>,
    },
  });

  const onSubmit = async (data: z.infer<typeof formSchema>) => {
    console.log("Form Data:", data);
  };

  const handlePrevious = () => {
    if (step === 2) {
      setStep(1);
    }
  };

  const handleNext = async () => {
    const fieldsToValidate =
      step === 1
        ? ([
            "dateOfBirth",
            "phoneNumber",
            "streetAddress",
            "city",
            "emergencyContactName",
            "emergencyContactPhone",
            "emergencyContactRelation",
            "experienceLevel",
            "experienceDescription",
          ] as const)
        : (["hasMedicalCondition", "consent"] as const);

    const isValid = await trigger(fieldsToValidate);
    if (isValid) setStep(2);

    if (step === 2) {
      handleSubmit(onSubmit)();
    }
  };

  return (
    <div>
      <h1>Onboard</h1>
      <form>
        {step === 1 && (
          <>
            <div>
              <label>Date of Birth</label>
              <input {...register("dateOfBirth")} />
              {errors.dateOfBirth && (
                <p className="error-messsage">{errors.dateOfBirth.message}</p>
              )}
            </div>
            <div>
              <label>Phone Number</label>
              <input {...register("phoneNumber")} />
              {errors.phoneNumber && (
                <p className="error-messsage">{errors.phoneNumber.message}</p>
              )}
            </div>

            <div>
              <label>Street Address</label>
              <input {...register("streetAddress")} />
              {errors.streetAddress && (
                <p className="error-messsage">{errors.streetAddress.message}</p>
              )}
            </div>

            <div>
              <label>City</label>
              <input {...register("city")} />
              {errors.city && (
                <p className="error-messsage">{errors.city.message}</p>
              )}
            </div>

            <div>
              <label>Emergency Contact Name</label>
              <input {...register("emergencyContactName")} />
              {errors.emergencyContactName && (
                <p className="error-messsage">
                  {errors.emergencyContactName.message}
                </p>
              )}
            </div>

            <div>
              <label>Emergency Contact Phone</label>
              <input {...register("emergencyContactPhone")} />
              {errors.emergencyContactPhone && (
                <p className="error-messsage">
                  {errors.emergencyContactPhone.message}
                </p>
              )}
            </div>
            <div>
              <label>Emergency Contact Relation</label>
              <input {...register("emergencyContactRelation")} />
              {errors.emergencyContactRelation && (
                <p className="error-messsage">
                  {errors.emergencyContactRelation.message}
                </p>
              )}
            </div>
            <div>
              <label>Experience Level</label>
              <select {...register("experienceLevel")}>
                <option value="">Select</option>
                <option value="none">None</option>
                <option value="beginner">Beginner</option>
                <option value="intermediate">Intermediate</option>
                <option value="advanced">Advanced</option>
              </select>
              {errors.experienceLevel && (
                <p className="error-messsage">
                  {errors.experienceLevel.message}
                </p>
              )}
            </div>
            <div>
              <label>Experience Description</label>
              <textarea {...register("experienceDescription")} />
              {errors.experienceDescription && (
                <p className="error-messsage">
                  {errors.experienceDescription.message}
                </p>
              )}
            </div>
          </>
        )}
        {step === 2 && (
          <>
            <div>
              <label>Do you have a medical condition?</label>
              <select {...register("hasMedicalCondition")}>
                <option value="">Select</option>
                <option value="yes">Yes</option>
                <option value="no">No</option>
              </select>
              {errors.hasMedicalCondition && (
                <p className="error-messsage">
                  {errors.hasMedicalCondition.message}
                </p>
              )}
            </div>
            <div>
              <label>
                <Controller
                  name="consent"
                  control={control}
                  render={({ field }) => (
                    <input
                      type="checkbox"
                      {...field}
                      onChange={(e) =>
                        field.onChange(e.target.checked ? "true" : "")
                      }
                      checked={field.value === "true"}
                    />
                  )}
                />
                I agree to the terms and conditions
              </label>
              {errors.consent && (
                <p className="error-messsage">{errors.consent.message}</p>
              )}
            </div>
          </>
        )}
        {step === 2 && (
          <button type="button" onClick={handlePrevious}>
            Previous
          </button>
        )}
        <button type="button" onClick={handleNext}>
          {step === 1 ? "Next" : "Submit"}
        </button>
      </form>
    </div>
  );
};
export default OnboardPage;
.error-messsage {
  font-size: 12px;
  color: red;
}

Reasons:
  • RegEx Blacklisted phrase (2.5): Do you have a
  • Long answer (-1):
  • Has code block (-0.5):
  • Low reputation (0.5):
Posted by: AbdulSamad Ayoade