Next.js Discord

Discord Forum

cookies.set is not a function

Unanswered
Harlequin posted this in #help-forum
Open in Discord
HarlequinOP
"use server";

import { redirect } from "next/navigation";
import { generateToken, hashPassword } from "../authentication-utils";
import prisma from "../db";
import { cookies } from "next/headers";

export async function createUser(formData: FormData) {
  const firstName = formData.get("firstName");
  const lastName = formData.get("lastName");
  const email = formData.get("email");
  const password = formData.get("password");
  console.log({ firstName, lastName, email, password });
  const isEmailAlreadyTaken = await prisma.user.findUnique({
    where: { email: email as string },
  });
  if (isEmailAlreadyTaken) {
    return "Email is already taken. Please use another one.";
  }
  const hashedPassword = await hashPassword(password as string);
  const newUser = await prisma.user.create({
    data: {
      firstName: firstName as string,
      lastName: lastName as string,
      email: email as string,
      password: hashedPassword,
    },
  });
  const jwt = await generateToken({ id: newUser.id });
  // set a cookie with the jwt
  //@ts-ignore
  cookies.set("jwt", jwt, {
    httpOnly: true,
    secure: process.env.NODE_ENV === "production",
    sameSite: "strict",
    maxAge: 60 * 60 * 24 * 7, // 1 week
    path: "/",
  });
  console.log("User created", newUser);
  redirect("/dashboard");
}

why can i not set cookies in a form action? it says it is not a function but the docs describes that

31 Replies

Barbary Lion
how are you calling the function?
HarlequinOP
@Barbary Lion

  <form action={createUser}>
        <Stack>
          <TextInput
            label="First Name"
            placeholder="Your first name"
            value={form.values.firstName}
            name="firstName"
            onChange={(event) =>
              form.setFieldValue("firstName", event.currentTarget.value)
            }
            radius="md"
          />
          <TextInput
            label="Last Name"
            name="lastName"
            placeholder="Your last name"
            value={form.values.lastName}
            onChange={(event) =>
              form.setFieldValue("lastName", event.currentTarget.value)
            }
            radius="md"
          />

          <TextInput
            required
            label="Email"
            placeholder="hello@mantine.dev"
            name="email"
            value={form.values.email}
            onChange={(event) =>
              form.setFieldValue("email", event.currentTarget.value)
            }
            error={form.errors.email && "Invalid email"}
            radius="md"
          />

          <PasswordInput
            required
            label="Password"
            placeholder="Your password"
            name="password"
            value={form.values.password}
            onChange={(event) =>
              form.setFieldValue("password", event.currentTarget.value)
            }
            error={
              form.errors.password &&
              "Password should include at least 6 characters"
            }
            radius="md"
          />
        </Stack>

        <Group justify="space-between" mt="xl">
          <Anchor component="button" type="button" c="dimmed" size="xs">
            Already have an account? Login
          </Anchor>
          <Button type="submit" radius="xl">
            {upperFirst(type)}
          </Button>
        </Group>
      </form>
`
as an action
HarlequinOP
im so confused 😄
Barbary Lion
yeah not familiar enough with server actions yet and they seem pretty buggy and unstable. I'd recommend using patterns that have been around longer especially if your building anything serious that isn't a side project. react-hook-form works great

          <Form {...form}>
            <form
              onSubmit={form.handleSubmit(handleSubmit)}
              className="space-y-4"
            >
              <FormField
                disabled={isLoading}
                control={form.control}
                name="agencyLogo"
                render={({ field }) => (
                  <FormItem>
                    <FormLabel>Agency Logo</FormLabel>
                    <FormControl>
                      <FileUpload
                        apiEndpoint="agencyLogo"
                        onChange={field.onChange}
                        value={field.value}
                      />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />
const handleSubmit = async (values: z.infer<typeof FormSchema>) => {
    try {
      let newUserData
      let custId
      if (!data?.id) {
        const bodyData = {
          email: values.companyEmail,
          name: values.name,
          shipping: {
            address: {
              city: values.city,
              country: values.country,
              line1: values.address,
              postal_code: values.zipCode,
              state: values.zipCode,
            },
            name: values.name,
          },
          address: {
            city: values.city,
            country: values.country,
            line1: values.address,
            postal_code: values.zipCode,
            state: values.zipCode,
          },
        }

        const customerResponse = await fetch('/api/stripe/create-customer', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(bodyData),
        })
HarlequinOP
this is just a side project and i thought i would give server actions a try, the docs about the cookie stuff sucks soo hard
HarlequinOP
i feel like i have a wrong node version or something
v20.11.1
Barbary Lion
yeah id be scared with builds and everything theyve had so many issues where things work in dev but not after build.
v20 is current
HarlequinOP
I think im gonna stick to sveltekit, this is hilarious 😄
Barbary Lion
i have two other people asking me how server actions right now lol everyone is confused and stuck. the pattern makes it too hard to tell whats on server/client across dev and builds. not a fan i like predictable code.
HarlequinOP
i mean its easy to use because i dont need to create api routes anymore, but this sucks, and i am pretty sure that it is because either my node version or my next version. But that shouldnt be a thing at all xD
Barbary Lion
if it was easy to use it would be working lol
yeah definitely nothing with node/next version its more about this/context and how you call functions and if they pass that this/context or if it gets swapped with another context between server/client
its like you have client context still within the server call which is why you dont have access to server-side functions
HarlequinOP
but why is ts yelling at me if it is from context? thats why i guessed it is because of some version
correct me if im wrong
@Barbary Lion
Barbary Lion
ohh i think i see the problem
you need to do this
cookies().set('name', 'lee')
cookies is returning a function that needs invoked
its basically a store
const cookiesStore = cookies()
cookiesStore.set()
HarlequinOP
cookies().set("jwt", jwt, {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "strict",
maxAge: 60 * 60 * 24 * 7, // 1 week
path: "/",
});
haha
this was the issue
im SOOO STUPID
Barbary Lion
its all good thats kind of a weird implementation for that