reactjsnext.jsshadcnui

Submit button does not invoke action


I did almost everything but clicking on submit button does not invoke onSubmit function. Any idea why the action is not being invoked?

This is my src/app/(auth)/signup/page.tsx

"use client";

import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";
import Link from "next/link";
import { useToast } from "@/hooks/use-toast";
import { useRouter } from "next/navigation";
import axios from "axios";
import signupSchema from "@/lib/schemas/signUpSchema";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";

const SignUp = () => {
  const { toast } = useToast();
  const router = useRouter();

  // Initialize the form using react-hook-form and Zod for validation
  const form = useForm<z.infer<typeof signupSchema>>({
    resolver: zodResolver(signupSchema),
    defaultValues: {
      firstName: "",
      lastName: "",
      email: "",
      password: "",
      gender: "male",
    },
  });
  function onSubmit(values: z.infer<typeof signupSchema>) {
    // Do something with the form values.
    // ✅ This will be type-safe and validated.
    console.log(values);
  }

  return (
    <div className="min-h-screen flex items-center justify-center">
      <div className="bg-white p-8 rounded shadow-md w-full max-w-md">
        <h2 className="text-2xl font-bold mb-4">Sign Up</h2>
        <Form {...form}>
          <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
            <FormField
              control={form.control}
              name="firstName"
              render={({ field }) => (
                <FormItem>
                  <FormLabel>First Name</FormLabel>
                  <FormControl>
                    <Input placeholder="First Name" {...field} />
                  </FormControl>
                  <FormMessage />
                </FormItem>
              )}
            />
            <FormField
              control={form.control}
              name="lastName"
              render={({ field }) => (
                <FormItem>
                  <FormLabel>Last Name</FormLabel>
                  <FormControl>
                    <Input placeholder="Last Name" {...field} />
                  </FormControl>
                  <FormMessage />
                </FormItem>
              )}
            />
            <FormField
              control={form.control}
              name="email"
              render={({ field }) => (
                <FormItem>
                  <FormLabel>Email</FormLabel>
                  <FormControl>
                    <Input type="email" placeholder="Email" {...field} />
                  </FormControl>
                  <FormMessage />
                </FormItem>
              )}
            />
            <FormField
              control={form.control}
              name="password"
              render={({ field }) => (
                <FormItem>
                  <FormLabel>Password</FormLabel>
                  <FormControl>
                    <Input type="password" placeholder="Password" {...field} />
                  </FormControl>
                  <FormMessage />
                </FormItem>
              )}
            />
            <FormField
              control={form.control}
              name="gender"
              render={({ field }) => (
                <FormItem>
                  <FormLabel>Gender</FormLabel>
                  <Select onValueChange={field.onChange}>
                    <FormControl>
                      <SelectTrigger>
                        <SelectValue placeholder="Select gender" />
                      </SelectTrigger>
                    </FormControl>
                    <SelectContent>
                      <SelectItem value="male">Male</SelectItem>
                      <SelectItem value="female">Female</SelectItem>
                      <SelectItem value="other">Other</SelectItem>
                    </SelectContent>
                  </Select>
                  <FormMessage />
                </FormItem>
              )}
            />
            <Button
              type="submit"
              className="w-full bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
            >
              Sign Up
            </Button>
          </form>
        </Form>
        <p className="mt-4 text-sm text-center">
          Already have an account?{" "}
          <Link href="/signin" className="text-blue-500 hover:text-blue-700">
            Login
          </Link>
        </p>
      </div>
    </div>
  );
};

export default SignUp;

This is my SignupSchema

import { z } from "zod";

// Define the signup schema
const signupSchema = z.object({
  firstName: z.string().min(1, { message: "First name is required" }),
  lastName: z.string().min(1, { message: "Last name is required" }),
  email: z
    .string()
    .min(1, { message: "Email is required" })
    .email({ message: "Please use a valid email address" }),
  password: z.string().min(1, { message: "Password is required" }),
  gender: z.enum(["male", "female", "other"]),
  verifyCode: z.string().min(1, { message: "Verify code is required" }),
  verifyCodeExpiry: z.date({
    required_error: "Verify code expiry is required",
  }),
  isVerified: z.boolean().default(false),
  githubId: z.string().optional().default(""),
  googleId: z.string().optional().default(""),
});

// Export the signup schema
export default signupSchema;

Solution

  • Your signup schema includes additional required fields that aren't in your form's default values or form fields:

    verifyCode, verifyCodeExpiry, isVerified, githubId, googleId
    

    These additional fields will cause validation errors when trying to submit the form.

    Here's a corrected version of the signup schema:

    typescriptCopyimport { z } from "zod";
    
    const signupSchema = z.object({
      firstName: z.string().min(1, { message: "First name is required" }),
      lastName: z.string().min(1, { message: "Last name is required" }),
      email: z
        .string()
        .min(1, { message: "Email is required" })
        .email({ message: "Please use a valid email address" }),
      password: z.string().min(1, { message: "Password is required" }),
      gender: z.enum(["male", "female", "other"]),
      // Optional or provide sensible defaults for the additional fields
      verifyCode: z.string().optional(),
      verifyCodeExpiry: z.date().optional(),
      isVerified: z.boolean().optional().default(false),
      githubId: z.string().optional().default(""),
      googleId: z.string().optional().default(""),
    });
    

    Also, update your defaultValues in the useForm hook to match the schema:

    typescriptCopyconst form = useForm<z.infer<typeof signupSchema>>({
      resolver: zodResolver(signupSchema),
      defaultValues: {
        firstName: "",
        lastName: "",
        email: "",
        password: "",
        gender: "male",
        verifyCode: "",
        verifyCodeExpiry: undefined,
        isVerified: false,
        githubId: "",
        googleId: "",
      },
    });
    

    If you're not using these additional fields right now, you can simplify the schema to only include the fields you're currently using in the form. A minimal schema could look like:

    typescriptCopyconst signupSchema = z.object({
      firstName: z.string().min(1, { message: "First name is required" }),
      lastName: z.string().min(1, { message: "Last name is required" }),
      email: z
        .string()
        .min(1, { message: "Email is required" })
        .email({ message: "Please use a valid email address" }),
      password: z.string().min(1, { message: "Password is required" }),
      gender: z.enum(["male", "female", "other"]),
    });
    

    These changes should help resolve the issue with the submit button not invoking the onSubmit function. The problem was likely caused by validation errors due to the mismatched schema and form fields.