0

I am trying to call the signup function defined my actions.ts (a server action) from a form on client side but I face the same error:

You're importing a component that needs next/headers. That only works in a Server Component but one of its parents is marked with "use client", so it's a Client Component.

import { lucia } from "@/auth";
import prisma from "@/lib/prisma";
import { signUpSchema, SignUpValues } from "@/lib/validation";
import { hash } from "@node-rs/argon2";
import { generateIdFromEntropySize } from "lucia";
import { isRedirectError } from "next/dist/client/components/redirect";
import { cookies } from "next/headers";
import { redirect } from "next/navigation";

export async function signUp(
  credentials: SignUpValues
): Promise<{ error: string }> {
  try {
    const { username, email, password } = signUpSchema.parse(credentials);

    const passwordHash = await hash(password, {
        // recommended minimum parameters
        memoryCost: 19456,
        timeCost: 2,
        outputLen: 32,
        parallelism: 1
    });
    const userId = generateIdFromEntropySize(10); // 16 characters long

    const existingUsername = await prisma.user.findFirst({
        where:{
            username:{
                equals: username,
                mode: "insensitive"
            }
        }
    });

    if (existingUsername){
        return {error: "Username already taken"}
    }

    const existingEmail = await prisma.user.findFirst({
        where:{
            username:{
                equals: email,
                mode: "insensitive"
            }
        }
    });

    if (existingEmail){
        return {error: "Email already taken"}
    }

    await prisma.user.create({
        data:{
            id: userId,
            username: username,
            displayName: username,
            email: email,
            passwordHash: passwordHash
        }
    })

    const session = await lucia.createSession(userId, {});
    const sessionCookie = lucia.createSessionCookie(session.id);
    cookies().set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
    return redirect("/");


  } catch (error) {
    if (isRedirectError(error)) throw error;
    console.log(error);
    return{
        error: "Something went wrong. Please try again"
    }
  }
}


I am calling it from SignupForm.tsx (that I will later call in my page.tsx)

/* eslint-disable @typescript-eslint/no-unused-vars */
"use client";

// import LoadingButton from "@/components/LoadingButton";
// import { PasswordInput } from "@/components/PasswordInput";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { signUpSchema, SignUpValues } from "@/lib/validation";
import { zodResolver } from "@hookform/resolvers/zod";
import { useState, useTransition } from "react";
import { useForm } from "react-hook-form";
import { signUp } from "./actions";
import { Button } from "@/components/ui/button";

export default function SignUpForm() {
  const [error, setError] = useState<string>();

  const [isPending, startTransition] = useTransition();

  const form = useForm<SignUpValues>({
    resolver: zodResolver(signUpSchema),
    defaultValues: {
      email: "",
      username: "",
      password: "",
    },
  });

  async function onSubmit(values: SignUpValues) {
    setError(undefined);
    startTransition(async () => {
      const { error } = await signUp(values);
      if (error) setError(error);
    });
  }

  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-3">
        {error && <p className="text-center text-destructive">{error}</p>}
        <FormField
          control={form.control}
          name="username"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Username</FormLabel>
              <FormControl>
                <Input placeholder="Username" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        <FormField
          control={form.control}
          name="email"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Email</FormLabel>
              <FormControl>
                <Input placeholder="Email" type="email" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        <FormField
          control={form.control}
          name="password"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Password</FormLabel>
              <FormControl>
                <Input placeholder="Password" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        <Button type="submit" className="w-full">
          Create account
        </Button>
      </form>
    </Form>
  );
  
}

I don't understand where is the problem since I have already done things similar and it's the first time I faced this error

4
  • First, it would be nice to know which one is the Server Component you want to include. Second, there is a mismatch between your action code shown here and the call to the server action (login vs signup). Please clean it up and let us know when it is done Commented Oct 11, 2024 at 9:51
  • @grekier it's done. Please @ me if you need any more information Commented Oct 11, 2024 at 10:04
  • I don't think this is due to the server action but one of the components that you import is a server component. Can you check them all and tell us if any of them are? Commented Oct 11, 2024 at 10:22
  • @grekier nope none of them is (if you are talking of the SignupForm.tsx imports) The action.ts and signupform are both in src/app/signup Commented Oct 11, 2024 at 10:31

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.