Creating the Account Page

Working on the Account Page that will add the tab that switches to the SignIn to SignUp form but has been debug the code I can see that the code. What are some suggestions or code advice just finished:

It seems that the shopifyConfig function is not being called correctly. The error indicates that the object { domain: string; storefrontAccessToken:
string; } does not have call signatures.

/** @jsxRuntime classic */
/** @jsx jsx */

import React, { FC, useState, useEffect, useRef } from 'react';
import { useRouter } from 'next/router'
import shopifyConfig from '@config/shopify'

// Define the Props interface for the Account component
interface Props {
    className?: string
    id?: string
}

// Define the Account component as a Functional Component (FC) with Props
const Account: FC<Props> = () => {
    // Get the router object from Next.js
    const router = useRouter()

    // State variables for managing the component's behavior
    const [isSwitch, setIsSwitch] = useState(false) // Toggle between login and signup forms
    const buttonRef = useRef<HTMLDivElement>(null) // Reference to the button element
    const [accountPageData, setAccountPageData] = useState(null); // Store data related to the account page

    // Effect hook to fetch data when the route changes
    useEffect(() => {
        const fetchAccountPageData = async () => {
            // Fetch account page data using the shopifyConfig function
            const data = await shopifyConfig('account-page');
            // Set the fetched data and update the switch state
            setAccountPageData(data);
            setIsSwitch(false);
        }
        // Trigger the fetch when the route changes (excluding query parameters)
        fetchAccountPageData();
    }, [router.asPath.split('?')[0]])

    // Function to toggle between login and signup forms
    const switchTab = () => {
        setIsSwitch(!isSwitch);
    }

    // Render the Account component
    return (
        <>
            {/* Display a welcome message with the user's name */}
            <h1>Welcome, {accountPageData?.user?.name}!</h1>

            {/* Button to toggle between login and signup forms */}
            <button ref={buttonRef} onClick={switchTab}>
                {isSwitch ? "Log in to your account" : "Create an account"}
            </button>

            {/* Conditional rendering based on the switch state */}
            {isSwitch ? (
                <div>
                    {/* Render the login form here */}
                </div>
            ) : (
                <div>
                    {/* Render the signup form here */}
                </div>
            )}
        </>
    )
}

// Export the Account component as the default export
export default Account

Hello @xbrandonpowell,

The error indicates that the shopifyConfig function is expected to have call signatures, but it doesn’t. To fix this error, you may need to ensure that the shopifyConfig function is defined correctly and has the necessary call signatures. I’ll provide an example of how you might define the shopifyConfig function with call signatures:

// Assuming shopifyConfig is a function that takes a string parameter and returns a Promise
// The returned Promise resolves to an object with domain and storefrontAccessToken properties

interface ShopifyConfigResponse {
    domain: string;
    storefrontAccessToken: string;
}

const shopifyConfig = async (configKey: string): Promise<ShopifyConfigResponse> => {
    // Implementation of fetching Shopify configuration data
    // This is just a placeholder, replace it with your actual implementation
    const response = await fetch(`/api/shopify/config/${configKey}`);
    const data = await response.json();
    return data;
};

export default shopifyConfig;

I’ve added an interface ShopifyConfigResponse to define the structure of the response from the shopifyConfig function. The function takes a configKey parameter (assumed to be a string) and returns a Promise that resolves to an object with domain and storefrontAccessToken properties.

Make sure to adjust the implementation of the shopifyConfig function based on how you actually fetch and structure your Shopify configuration data.

Best regards,

@manish-sharma, I’ve been using a new IDE called Cursor, which supposedly incorporates AI to assist with coding. Despite its help, I’m still struggling to ensure that all aspects of my code are correct. Specifically, I keep encountering the “Rules of Hooks” issue. Here’s a breakdown:

  1. I’ve invoked AI to inspect the body function where we are calling the hook.
  2. I’ve updated everything within the React DOM.
  3. After consulting AI, it seems that I’m not violating the Rules of Hooks, as everything appears correct.
  4. I’ve even read a blog on the subject, but I’m still unable to resolve the issue.

Hello @xbrandonpowell,

Encountering this error is a common issue when working with React hooks. I suggest checking out the following article for a potential solution: Invalid Hook Call Warning.

If the provided information doesn’t resolve the issue, please share the complete code with me. With the full code, I can pinpoint the exact cause of the error and provide more targeted assistance.

  • What I see by checking the React Dom this vis is - react-dom@18.2.0.

  • I have tried to figure this out by doing Yarn Package but still does not fix the issue that we need to do figure solve the issues Hook we still getting the same issue:

It look like the issue happen where him get router object and state variables: I have done everything I have done to figure this issues could find it.

/** @jsxRuntime classic */
/** @jsx jsx */

import React, { FC, useState, useEffect, useRef } from 'react';
import { useRouter } from 'next/router'
import { jsx } from '@emotion/react'
import shopifyConfig from '@config/shopify'

// Define the expected response structure from Shopify configuration
interface shopifyConfig {
  domain: process.env.SHOPIFY_STORE_DOMAIN; // Fixed: 'process.env.SHOPIFY_STORE_DOMAIN' was a string literal, changed to just 'string'
  storefrontAccessToken: process.env.SHOPIFY_STOREFRONT_API_TOKEN; // Fixed: 'process.env.SHOPIFY_STOREFRONT_API_TOKEN' was a string literal, changed to just 'string'
}

// Function to fetch Shopify configuration data
const accountConfig = async (configKey: process.env.SHOPIFY_STOREFRONT_API_TOKEN): Promise<shopifyConfig> => {
  // Placeholder for fetching Shopify configuration data
  const response = await fetch(`/api/shopify/config/${configKey}`);
  const data = await response.json();
  return data;
};

// Define the Props interface for the Account component
interface Props {
  className?: string;
  id?: string;
}

// Define the Account component as a Functional Component (FC) with Props
const Account: FC<Props> = () => {
  // Get the router object from Next.js
  const router = useRouter();

  // State variables for managing the component's behavior
  const [isSwitch, setIsSwitch] = useState(false); // Toggle between login and sign up forms
  const buttonRef = useRef<HTMLButtonElement>(null); // Reference to the button element
  const [accountPageData, setAccountPageData] = useState<shopifyConfig | null>(null); // Store data related to the account page

  // Effect hook to fetch data when the route changes
  useEffect(() => {
    const fetchAccountPageData = async () => {
      try {
        // Fetch account page data using the accountConfig function
        const data = await accountConfig('account-page');
        // Set the fetched data and update the switch state
        setAccountPageData(data);
        setIsSwitch(false);
      } catch (error) {
        console.error('Error fetching account page data:', error);
      }
    };

    // Trigger the fetch when the route changes (excluding query parameters)
    fetchAccountPageData();
  }, [router.asPath.split('?')[0]])

  // Function to toggle between login and sign up forms
  const switchTab = () => {
    setIsSwitch(!isSwitch);
  }

  // Render the Account component
  return (
    <>
      {/* Display a welcome message with the user's name */}
      {/* Note: Uncomment the line below when user data is available */}
      {/* <h1>Welcome, {accountPageData?.user?.name}!</h1> */}

      {accountPageData && (
        <h1>Welcome, {accountPageData.user.name}!</h1>
      )}

      {/* Button to toggle between login and sign up forms */}
      <button ref={buttonRef} onClick={switchTab}>
        {isSwitch ? "Log in to your account" : "Create an account"}
      </button>

      {/* Conditional rendering based on the switch state */}
      {isSwitch ? (
        <div>
          {/* Render the login form here */}
        </div>
      ) : (
        <div>
          {/* Render the sign-up form here */}
        </div>
      )}
    </>
  );
}

// Export the Account component as the default export
export default Account;

Hello @xbrandonpowell,

To fix this error, you should move the useRouter hook outside of the useEffect hook and use it directly in the component body. Here’s the modified code:

import React, { FC, useState, useEffect, useRef } from 'react';
import { useRouter } from 'next/router';
import { jsx } from '@emotion/react';
import shopifyConfig from '@config/shopify';

// ... (rest of the code)

const Account: FC<Props> = () => {
  // Get the router object from Next.js
  const router = useRouter();

  // ... (rest of the code)

  // Effect hook to fetch data when the route changes
  useEffect(() => {
    const fetchAccountPageData = async () => {
      try {
        // Fetch account page data using the accountConfig function
        const data = await accountConfig('account-page');
        // Set the fetched data and update the switch state
        setAccountPageData(data);
        setIsSwitch(false);
      } catch (error) {
        console.error('Error fetching account page data:', error);
      }
    };

    // Trigger the fetch when the route changes (excluding query parameters)
    fetchAccountPageData();
  }, [router.asPath.split('?')[0]]);

  // ... (rest of the code)

  return (
    <>
      {/* Display a welcome message with the user's name */}
      {/* Note: Uncomment the line below when user data is available */}
      {/* <h1>Welcome, {accountPageData?.user?.name}!</h1> */}

      {accountPageData && <h1>Welcome, {accountPageData.user.name}!</h1>}

      {/* Button to toggle between login and sign up forms */}
      <button ref={buttonRef} onClick={switchTab}>
        {isSwitch ? 'Log in to your account' : 'Create an account'}
      </button>

      {/* Conditional rendering based on the switch state */}
      {isSwitch ? (
        <div>
          {/* Render the login form here */}
        </div>
      ) : (
        <div>
          {/* Render the sign-up form here */}
        </div>
      )}
    </>
  );
};

// Export the Account component as the default export
export default Account;

Hi @manish-sharma,

Thank you for your reply. I’m trying to understand your code. Are you suggesting that I need to move or reorganize the code to the top-level component? I’m trying to grasp the concept, but I’m having difficulty figuring out what you’re showing.

I’ve watched videos on this topic, but I can’t seem to comprehend why I’m struggling with this. It’s as if my mind is lost in understanding or is blinded to what you’re trying to teach. If you could provide an explanation without explicitly revealing the answer, that would be great.

Thank you,
Brandon Powell

Hello @xbrandonpowell,

Are you still getting the same error “Invalid hook call …” ?

Yes, @manish-sharma because him stuck on figure out what you have modified in the code just very lost right now and lol cannot figure out why.

Hello @xbrandonpowell,

I think I might have been mistaken with the updated code, the idea was to move the useRouter hook outside of the useEffect hook. I reviewed the shared code and there is no change so kindly ignore that.

Hey @manish-sharma,

I have created video maybe this would help for explain it hope I explain better to you Loom | Free Screen & Video Recording Software | Loom

Hello @xbrandonpowell,

Can you push the changes to GitHub repo?

Hey @manish-sharma ,

THank you again GitHub - brandonpowell/sbr-shopify: Just another Shopify Headless Build with Builder.io.

Hello @xbrandonpowell,

I reviewed your code, and the code you provided seems mostly correct in terms of React Hooks usage. However, the issue might be related to the usage of process.env in TypeScript interfaces, as TypeScript doesn’t support process.env as a type.

  1. Adjust the ShopifyConfig Interface: Update the shopifyConfig interface to use string literals directly instead of process.env .

    interface ShopifyConfig {
      domain: string;
      storefrontAccessToken: string;
    }
    
  2. Function Argument Type: Modify the argument type in the accountConfig function to be a string directly.

    const accountConfig = async (configKey: string): Promise<ShopifyConfig> => {
      // ...
    };
    

Here is the modified code:

// ...
// Define the expected response structure from Shopify configuration
interface ShopifyConfig {
  domain: string;
  storefrontAccessToken: string;
}

// Function to fetch Shopify configuration data
const accountConfig = async (configKey: string): Promise<ShopifyConfig> => {
  // Placeholder for fetching Shopify configuration data
  const response = await fetch(`/api/shopify/config/${configKey}`);
  const data = await response.json();
  return data;
};

// ... 

1 Like

This are setup we have created so far:

interface shopifyConfig {
  apiKey: string;
  apiSecret: string;
}

const config: shopifyConfig = {
  apiKey: process.env.SHOPIFY_API_KEY || '',
  apiSecret: process.env.SHOPIFY_STOREFRONT_API_TOKEN || '',
};

// Function to fetch Shopify configuration data
const accountConfig = async (configKey: string): Promise<shopifyConfig> => {
  // Placeholder for fetching Shopify configuration data
  const response = await fetch(`/api/shopify/config/${configKey}`);
  const data = await response.json();
  return data;
};

But we are still getting the same React Hook issues that begin called.

Hello @xbrandonpowell,

For troubleshooting purposes, consider removing or commenting out the useRouter usage in your code. After making this adjustment, check if the “invalid hook call” error persists. This step should help identify the source of the issue.

If do that, the error message will go down to the next line. After commenting out the useRouter, now go to the switch. There, he is calling the switch where we are building out the switch for the tabs button.

Now I think in my mind it’s might be the whole code that causing the issues or did write my code correctly but going to keep figuring this out till out get these issues correctly.

Thank You @manish-sharma