I’m trying to build a login using gatsby and I want to use a context to store the token and use it in other pages, the build was running fine before I added the context but once I added the context the build started to fail, the most confusing thing is that I get zero errors in development.
LoginForm.js
import React, {useContext} from "react";
import {Formik, Field, Form, useFormikContext} from "formik";
import * as Yup from "yup";
import PrimaryButton from "../Button";
import { Link, navigate } from "gatsby";
import FormInput from "./inputs/FormInput";
import ErrorMessage from "../ErrorMessage"
import {useAuth} from "../../../contexts/AuthContext";
const validationSchema = Yup.object().shape({
email: Yup.string().email("Invalid email").required("Required"),
password: Yup.string().required("Required"),
});
const initialValues = {
email: "",
password: "",
remind: "",
};
const LoginForm = () => {
// const { login } = useAuth();
/**
* Handle the login process by sending a POST request to the authentication endpoint
* with user credentials and handling the response.
*
* @param {Object} values - User input values including email and password.
* @param {Function} setFieldError - Function to set form field errors.
* @returns {Promise<void>} - A Promise that resolves once the login process is complete.
*/
async function handleLogin(values, setFieldError) {
try {
const loginResponse = await fetch(`${process.env.CUSTOMER_PANEL_URL}/auth/login`, {
method: 'POST',
body: JSON.stringify({ email: values.email, password: values.password }),
});
if (loginResponse.ok) {
const token = await loginResponse.text();
await handleTokenVerification(token, setFieldError);
} else {
const errorMessage = await loginResponse.text(); // Extract error message from response body
setFieldError("general", errorMessage); // Set a general error message
}
} catch (error) {
console.error('Error during the login process:', error);
setFieldError('general', `Login process error: ${error.message}`);
}
}
/**
* Verify the received token by sending a POST request to the token verification endpoint
* and handle the response accordingly.
*
* @param {string} token - The token to be verified.
* @param {Function} setFieldError - Function to set form field errors.
* @returns {Promise<void>} - A Promise that resolves once the token verification is complete.
*/
async function handleTokenVerification(token, setFieldError) {
try {
const tokenResponse = await fetch(`${process.env.CUSTOMER_PANEL_URL}/auth/token`, {
method: 'POST',
body: JSON.stringify({ code: token }),
});
if (tokenResponse.ok) {
login(token)
await navigate("/profiles");
} else {
const errorMessage = await tokenResponse.text(); // Extract error message from response body
setFieldError("general", errorMessage); // Set a general error message
await navigate("/login");
}
} catch (error) {
console.error('Error during token verification:', error);
setFieldError('general', `Token verification process error: ${error.message}`);
await navigate("/login");
}
}
return (
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={(values, { setSubmitting, setFieldError }) => {
handleLogin(values, setFieldError).finally(() => setSubmitting(false));
}}
>
{({ errors, isSubmitting }) => (
<Form className="text-white flex flex-col gap-8 items-center w-full self-center">
<FormInput label="Email" name="email" type="text" error={errors.email} />
<FormInput label="Password" name="password" type="password" error={errors.password} />
<div className="flex w-full justify-between group">
<label htmlFor="remind" className="group flex gap-1.5 items-center">
<Field
id="remind"
type="checkbox"
name="remind"
className="group-hover:cursor-pointer focus:ring-offset-transition-all duration-150 shadow-inner rounded bg-gradient-to-t"
/>
<span className="text-sm group-hover:cursor-pointer">
Recordarme
</span>
</label>
<Link
to="/recover-password"
className="text-sm hover:underline cursor-pointer"
>
Olvide mi contraseña
</Link>
</div>
{errors.general && <ErrorMessage errorMessageTitle={errors.general} errorMessage="Please try again"></ErrorMessage>}
<PrimaryButton type="submit" className="w-1/3 self-center" disabled={isSubmitting}>
Login
</PrimaryButton>
</Form>
)}
</Formik>
);
};
export default LoginForm;
AuthContext.js
import React, {createContext, useContext, useEffect, useState} from "react";
const AuthContext = createContext(null);
export const AuthProvider = ({ children }) => {
const [token, setToken] = useState({
token: null
});
// Function to set the token
const login = (token) => {
setToken(token);
localStorage.setItem("token", JSON.stringify(token));
};
useEffect(() => {
const storedToken = localStorage.getItem("token");
if (storedToken) {
setToken(JSON.parse(storedToken));
}
}, []);
return (
<AuthContext.Provider value={{ token, login }}>
{children}
</AuthContext.Provider>
);
};
export const useAuth = () => {
const context = useContext(AuthContext);
if (!context) {
throw new Error(
"useAuth must be used within a AuthContext"
);
}
return context;
};
export default AuthContext;
gatsby-config.js
/**
* @type {import('gatsby').GatsbyConfig}
*/
module.exports = {
siteMetadata: {
title: `Customer Panel`,
description: `Meta description for Customer Panel goes here`,
twitterUsername: ``,
image: `/gatsby-icon.png`,
siteUrl: ``,
},
plugins: [
"gatsby-plugin-postcss",
{
resolve: "gatsby-plugin-google-analytics",
options: {
trackingId: "1234",
},
},
"gatsby-plugin-image",
"gatsby-plugin-sitemap",
{
resolve: "gatsby-plugin-manifest",
options: {
icon: "src/images/icon.png",
},
},
"gatsby-plugin-sharp",
"gatsby-transformer-sharp",
{
resolve: "gatsby-source-filesystem",
options: {
name: "images",
path: "./src/images/",
},
__key: "images",
},
],
};
gatsby-browser.js
import React from "react";
import "./src/styles/global.css";
import "@fontsource/montserrat/400.css";
import "@fontsource/montserrat/700.css";
import {AuthProvider} from "./src/contexts/AuthContext";
export const wrapRootElement = ({ element }) => (
<AuthProvider>{element}</AuthProvider>
);
package.json in case it matters
{
"name": "customer-panel",
"version": "1.0.0",
"private": true,
"description": "customer-panel",
"author": "",
"keywords": [
"gatsby"
],
"scripts": {
"develop": "gatsby develop",
"start": "gatsby develop",
"build": "gatsby build",
"serve": "gatsby serve",
"clean": "gatsby clean"
},
"dependencies": {
"@fontsource/montserrat": "^5.0.16",
"@tailwindcss/forms": "^0.5.7",
"formik": "^2.4.5",
"gatsby": "^5.12.4",
"gatsby-plugin-google-analytics": "^5.12.0",
"gatsby-plugin-image": "^3.12.3",
"gatsby-plugin-manifest": "^5.12.3",
"gatsby-plugin-sharp": "^5.12.3",
"gatsby-plugin-sitemap": "^6.12.3",
"gatsby-source-filesystem": "^5.12.1",
"gatsby-transformer-sharp": "^5.12.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^4.12.0",
"react-spinners": "^0.13.8",
"yup": "^1.3.3"
},
"devDependencies": {
"autoprefixer": "^10.4.16",
"gatsby-plugin-postcss": "^6.12.0",
"postcss": "^8.4.32",
"tailwindcss": "^3.3.6"
}
}
Error I get
ERROR UNKNOWN
Truncated page data information for the failed page "/login/": {
"errors": {},
"path": "/login/",
"slicesMap": {},
"pageContext": {}
}
failed Building static HTML for pages - 6.932s
ERROR #95313 HTML.COMPILATION
Building static HTML failed for path "/login/"
See our docs page for more info on this error: https://gatsby.dev/debug-html
WebpackError: useAuth must be used within a AuthContext
- AuthContext.js:34
webpack:/customer-panel/src/contexts/AuthContext.js:34:15
- LoginForm.js:22
webpack:/customer-panel/src/components/ui/forms/LoginForm.js:22:20
- es.js:50
[customer-panel]/[formik]/[deepmerge]/dist/es.js:50:1
- es.js:52
[customer-panel]/[formik]/[deepmerge]/dist/es.js:52:5
- index.js:70
[customer-panel]/[node-fetch]/lib/index.js:70:1
- es.js:61
[customer-panel]/[formik]/[deepmerge]/dist/es.js:61:1
- es.js:60
[customer-panel]/[formik]/[deepmerge]/dist/es.js:60:1
- index.js:70
[customer-panel]/[node-fetch]/lib/index.js:70:1
- es.js:61
[customer-panel]/[formik]/[deepmerge]/dist/es.js:61:1
- es.js:53
[customer-panel]/[formik]/[deepmerge]/dist/es.js:53:1
- index.js:70
[customer-panel]/[node-fetch]/lib/index.js:70:1
- es.js:61
[customer-panel]/[formik]/[deepmerge]/dist/es.js:61:1
- es.js:53
[customer-panel]/[formik]/[deepmerge]/dist/es.js:53:1
- index.js:70
[customer-panel]/[node-fetch]/lib/index.js:70:1
- es.js:52
[customer-panel]/[formik]/[deepmerge]/dist/es.js:52:5
- index.js:70
[customer-panel]/[node-fetch]/lib/index.js:70:1
This error disappears when I comment out any usages of my context but I need to use the context, I really don’t understand or see what’s the problem with my context