Create a food ordering app with Strapi and Next.js 4/7

This tutorial is part of the « Cooking a Deliveroo clone with Next.js (React), GraphQL, Strapi and Stripe » tutorial series.


This is a companion discussion topic for the original entry at https://strapi.io/blog/nextjs-react-hooks-strapi-auth-4

Hello, when I register and click on submit I get an error saying:
TypeError: error.message.map is not a function:

Try to comment the section with errors, if the code brakes, try to console.log(error.message) and see if that returns a array, if it doesn’t, you should change that code from iterating through an array to something else.

Figure it out. In Strapi Enable email confirmation was enabled, after disabling it there were no more errors.

Maybe there will be a follow up tutorial as well on how to have Enable email confirmation enabled when users register?

image

UPDATE

I figured out how to get it working with email confirmation. I had to set an email address for Shipper email and Response email in Email address confirmation template.

However I did found a little mistake in the code above in _app.js
Where we have componentDidMount I had to add a forward slash / in

fetch(`${process.env.NEXT_PUBLIC_API_URL}users/me`

Becomes

fetch(`${process.env.NEXT_PUBLIC_API_URL}/users/me`

After that I got no more errors!

i am getting this error message when I try to register a user. the registration will be successful and I see the registered user in the strapi but this error will display on the sign up page before redirecting to home page

pages\users\register.js (90:50) @ eval

  88 |     })
  89 |     .catch((error) => {
> 90 |       setError(error.response.data);
     |                              ^
  91 |       setLoading(false);
  92 |     });
  93 | }}

Hey, in register.js you have to write it like this:

{Object.entries(error).length !== 0 &&
    error.constructor === Object &&
    error.error.details.errors.map((error) => {
        return (
            <div key={error.path[0]} style={{marginBottom: 10}}>
                <small style={{color: "red"}}>
                    {error.message}
                </small>
            </div>
        );
    })
}

and in login.js like this:

{Object.entries(error).length !== 0 &&
       error.constructor === Object &&
       <div key={error.error.name} style={{marginBottom: 10}}>
                <small style={{color: "red"}}>
                         {error.error.message}
                  </small>
        </div>
}

And now you have to change in the auth.js
every post-request to ${API_URL}/api/auth/local/
I hope I can help someone.

1 Like

Hello, the code for login would work successfully but that for register would return an undefined error.
Use this for register instead.

{Object.entries(error).length !== 0 &&
       error.constructor === Object &&
       <div key={error.error.name} style={{marginBottom: 10}}>
                <small style={{color: "red"}}>
                         {error.error.message}
                  </small>
        </div>
}

I was having an issue trying to register with (${API_URL}/auth/local/, { identifier, password } a user and was getting this error

The error went away and the “register” method worked when I updated the URL to ${API_URL}/auth/local/register, { username, email, password }

Thanks for sharing.

The code of register.js and login.js is missing event.preventDefault() and a couple awaits:

Register.js

import { useState } from "react";
import { useRouter } from "next/router";
import { useAppContext } from "@/context/AppContext";
import { gql, useMutation } from "@apollo/client";
import Cookie from "js-cookie";

import Form from "@/components/Form";
import Loader from "@/components/Loader";

const REGISTER_MUTATION = gql`
  mutation Register($username: String!, $email: String!, $password: String!) {
    register(
      input: { username: $username, email: $email, password: $password }
    ) {
      jwt
      user {
        username
        email
      }
    }
  }
`;

export default function RegisterRoute() {
  const { setUser } = useAppContext();
  const router = useRouter();

  const [formData, setFormData] = useState({ email: "", password: "" });
  const [registerMutation, { loading, error }] = useMutation(REGISTER_MUTATION);

  const handleRegister = async (event) => {
    event.preventDefault();
    try {
      const { email, password } = formData;
      const { data } = await registerMutation({
        variables: { username: email, email: email, password },
      });
      if (data?.register.user) {
        setUser(data.register.user);
        await router.push("/");
        Cookie.set("token", data.register.jwt);
      }
    } catch (error) {
      console.log(error);
    }
  };

  if (loading) return <Loader />;

  return (
      <Form
          title="Sign Up"
          buttonText="Sign Up"
          formData={formData}
          setFormData={setFormData}
          callback={handleRegister}
          error={error}
      />
  );
}

Login.js

import { useState } from "react";
import { useRouter } from "next/router";
import { useAppContext } from "@/context/AppContext";
import { gql, useMutation } from "@apollo/client";
import Cookie from "js-cookie";

import Form from "@/components/Form";
import Loader from "@/components/Loader";

const LOGIN_MUTATION = gql`
  mutation Login($identifier: String!, $password: String!) {
    login(input: { identifier: $identifier, password: $password }) {
      jwt
      user {
        username
        email
      }
    }
  }
`;

export default function LoginRoute() {
  const { setUser } = useAppContext();
  const router = useRouter();

  const [formData, setFormData] = useState({ email: "", password: "" });
  const [loginMutation, { loading, error }] = useMutation(LOGIN_MUTATION);

  const handleLogin = async (event) => {
    event.preventDefault();
    try {
      const { email, password } = formData;
      const { data } = await loginMutation({
        variables: { identifier: email, password },
      });
      if (data?.login.user) {
        setUser(data.login.user);
        Cookie.set("token", data.login.jwt);
        await router.push("/");
      }
    } catch (error) {
      console.log(error);
    }
  };

  if (loading) return <Loader />;

  return (
      <Form
          title="Login"
          buttonText="Login"
          formData={formData}
          setFormData={setFormData}
          callback={handleLogin}
          error={error}
      />
  );
}