Contradicted
Contradicted

Reputation: 21

Location is not defined - NextJS 13 + React

I am trying to created protected routes by going to my protected pages and making sure that the page can only be visible to users that have logged in. I've setup AuthProvider using Firebase and everything works fine just getting this error when I try to visit the protected routes whilst logged out and get redirected to the 'signin' page.

The error I'm getting:

error node_modules/next/dist/client/components/app-router.js (144:65) @ location

error ReferenceError: location is not defined
    at Profile (./src/app/profile/page.js:32:20)

Here is the code in question:

'use client'

import Navbar from '@/components/UI/Navbar'
import React, { useState } from 'react'
import { UserAuth } from '../context/AuthContext'
import { useRouter } from 'next/navigation';
import Modal from '@/components/UI/Modal';

const Profile = () => {

    const [hasData, setHasData] = useState(false)
    const [showModal, setShowModal] = useState(false)
    const [data, setData] = useState()

    const { user } = UserAuth()
    const router = useRouter()

    if (!user) {
        if (!user) {
            router.push('/signin')
        }
        return ""
    }

    return (
        <div>
            <Navbar />
            <main>
                <div className="mx-auto max-w-7xl py-6 sm:px-6 lg:px-8">
                    <h1 className='text-2xl font-bold'>Welcome Back</h1>
                    <p className='text-sm font-normal'>View your submitted forms here</p>

                    {!hasData ? (<p className='text-center mt-10'>You have not submitted any forms.</p>) : (
                        <div className="overflow-x-auto px-5 mx-auto mt-10 w-5/6 ">
                            <table className="table">
                                {/* head */}
                                <thead>
                                    <tr className='grid grid-cols-4'>
                                        <th>Name</th>
                                        <th>Status</th>
                                        <th></th>
                                    </tr>
                                </thead>
                                <tbody>
                                    {/* row 1 */}
                                    <tr className='grid grid-cols-4'>
                                        <td className='flex items-center'>
                                            <div>
                                                <div className="font-bold">Form 1</div>
                                            </div>
                                        </td>
                                        <td className='col-span-2'>
                                            <div className='rounded-md w-fit bg-yellow-400 px-3 py-1 text-sm font-semibold text-white shadow-sm'>{data.status}</div>
                                        </td>
                                        <th>
                                            <button
                                                className="rounded-md w-fit bg-indigo-600 px-3 py-1 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
                                                onClick={() => setShowModal(true)}
                                            >
                                                Details
                                            </button>
                                        </th>
                                    </tr>
                                </tbody>
                            </table>
                        </div>
                    )}
                </div>
            </main>
            <Modal isVisible={showModal} onClose={() => setShowModal(false)} data={data} />
        </div>
    )
}

export default Profile

I've seen a post regarding this error in the past but this is before NextJS 13 was introducted where it is recommended to use 'useRouter' from 'next/navigation' rather than the previous 'next/router'.

Edit: Also including the code for 'UserAuth':

import { useContext, createContext, useState, useEffect } from "react";
import {
    signInWithPopup,
    signOut,
    onAuthStateChanged,
    GoogleAuthProvider,
    signInWithEmailAndPassword
} from "firebase/auth";

import { auth } from "@/config/firebase";

const AuthContext = createContext();

export const AuthContextProvider = ({ children }) => {
    const [user, setUser] = useState(null);

    const googleSignIn = () => {
        const provider = new GoogleAuthProvider();
        signInWithPopup(auth, provider);
    };

    const logOut = () => {
        return signOut(auth);
    };

    const login = (email, password) => {
        return signInWithEmailAndPassword(auth, email, password)
    }

    useEffect(() => {
        const unsubscribe = onAuthStateChanged(auth, (currentUser) => {

            if (currentUser) {
                currentUser.getIdTokenResult().then(idTokenResult => {
                    currentUser.admin = idTokenResult.claims.admin
                })
                localStorage.setItem('authUser', JSON.stringify(currentUser))
                setUser(currentUser);
            } else {
                localStorage.removeItem('authUser')
                setUser(null)
            }
        });
        return () => unsubscribe();
    }, []);

    return (
        <AuthContext.Provider value={{ user, googleSignIn, logOut, login }}>
            {children}
        </AuthContext.Provider>
    );
};

export const UserAuth = () => {
    return useContext(AuthContext);
};

Any help in tacking this error would be greatly appreciated.

Upvotes: 2

Views: 3545

Answers (1)

Victor Fu
Victor Fu

Reputation: 174

Move router.push into useEffect.

useEffect(() => {
    if (!user) {
      router.push('/signin');
    }
  }, [user]);

The client side routing needs to depend on the component is mounted.

Upvotes: 5

Related Questions