skip to Main Content

I am developing a system, that system has login function and it is working successfully. That login process takes username and role. When I check it on Login.jsx it is fine, I can see role and username correctly. The problem is that I have a Sidebar component and I want to render that sidebar after successfull login, not before login. When I check username and role inside App.js, they are undefined. Why is that happening. Btw, If I add Sidebar without conditional rendering, I can see 3 different Sidebar for 3 users, I can set it using roles. I believe it happens because Login and Sidebar are on the same hierarchy. Please help me

AuthProvider.js:

import { createContext, useState } from "react";

const AuthContext = createContext({});

export const AuthProvider = ({ children }) => {
    const [auth, setAuth] = useState({
        username: null,
        password: null,
        role: null,
        accessToken: null,
    });

    const login = ({ username, password, role, accessToken }) => {
        setAuth({
            username,
            password,
            role,
            accessToken,
        })
    }

    const logout = () => {
        setAuth({
            username: null,
            password: null,
            role: null,
            accessToken: null,
        })
    }

    return (
        <AuthContext.Provider value={{ auth, setAuth, login, logout }}>
            {children}
        </AuthContext.Provider>
    )
}

export default AuthContext;

Login.jsx:

import React, { useEffect, useState, useRef } from 'react';
import { useNavigate, Link, useLocation } from 'react-router-dom'; // Import useNavigate
import useAuth from './hooks/useAuth';

// Img
import LoginBg from "../assets/img/upg-bg.jpg";

const Login = (props) => {
    const { setAuth, login } = useAuth();

    const navigate = useNavigate();
    const location = useLocation();
    const from = location.state?.from?.pathname || "/";

    const userRef = useRef();
    const errRef = useRef();

    const [username, setUsername] = useState("");
    const [password, setPassword] = useState("");
    const [errMsg, setErrMsg] = useState("");

    // const { login } = useAuth();

    const handleLogin = async (e) => {
        e.preventDefault();
        try {
            const response = await fetch(`some url in here`, {
                method: "POST",
                headers: {
                    "Content-Type": "application/json"
                },
                body: JSON.stringify({ username, password }),
            })
            const data = await response.json();
            const role = data.role[0].roleName;
            const accessToken = data.token;
            console.log("role from login", role)
            // login(data.token, data.role[0].roleName);
            // setAuth({ username, password, role, accesToken })
            login({
                username: username,
                password: password,
                role: role,
                accessToken: accessToken,
            })
            setUsername("");
            setPassword("");
            navigate("/", { replace: true });

        } catch (error) {
            if (error.response?.status === 400) {
                setErrMsg("Yanlış kullanıcı adı ya da şifre!");
            } else if (error.response?.status === 401) {
                setErrMsg("Yetkiniz Yok!");
            } else {
                setErrMsg("Giriş başarısız!");
            }
            errRef.current?.focus();
        }
    }

    // To login on press Enter
    const handleKeyPress = e => {
        if (e.keyCode === 13) {
            handleLogin();
        }
    }

    useEffect(() => {
        userRef.current?.focus();
    }, [])

    useEffect(() => {
        setErrMsg("");
    }, [username, password])

    useEffect(() => {
        console.log("user context updated", login)
    }, [login]) 

    return (
        <div onKeyDown={handleKeyPress} id='login-page' className=' absolute z-30 w-screen h-screen'>
         // some divs etc...
        </div>
    )
}

export default Login

App.js:

import React, { useState, useEffect } from "react";
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import { AuthProvider } from "./components/auth/AuthProvider";

import Login from "./components/Login";
import Sidebar from "./components/Sidebar";


function App() {
  const { auth, login } = useAuth();
  console.log("role from app", auth?.role)
  console.log("login", login.role)

  return (
    <AuthProvider>
      <div className="App">
        <Routes>
           <Route path="/login" element={<Login />} />
         </Routes>

         <div className="flex">
           {auth?.role === 'admin' && <Sidebar />}
         </div>
      </div>
    </AuthProvider>
  )
}

Sidebar.jsx:

import React from 'react'
import { Link } from 'react-router-dom';
import useAuth from './hooks/useAuth';

import { MdTableView, MdOutlineLogout } from 'react-icons/md';
import { AiOutlineQuestionCircle, AiOutlinePlusCircle } from 'react-icons/ai';
import { TbCircleLetterC } from 'react-icons/tb';

const Sidebar = (props) => {
    const { auth } = useAuth();

    const logOut = () => {
        // props.setIsLoggedIn(false);
    }

    const sidebarSelect = (id) => {
        const link = document.getElementById(id);

        // Deselect link if there is any
        const previouslySelectedLinks = document.querySelectorAll(".selected");
        previouslySelectedLinks.forEach((div) => {
            div.classList?.remove("selected", "bg-zinc-600");
            div.classList?.add("hover:bg-zinc-600");
        });

        // Select new link
        link.classList?.add("bg-zinc-600", "selected");
        link.classList?.remove("hover:bg-zinc-600");
    }

    return (
        <div id="sidebar" className='flex-none bg-gradient-to-b from-zinc-700 to-zinc-900 fixed w-full top-0 bottom-0 max-w-[16rem] -ms-[16.5rem] md:ms-3 my-3 rounded-lg text-white duration-300 z-10'>
            <div id="sidebar-header" className='py-6 text-center'>
                {/* <Link to="/">
                    </Link> */}
                <h1 id='sidebar-title' className='font-bold'>İstanbul Medeniyet Universitesi</h1>
            </div>

            <hr className='mx-4' />

            <div className='py-6 mx-4'>
                <ul className='flex flex-col'>

                    {auth?.role === 'admin' && (<Link id='0' onClick={() => sidebarSelect(0)} to="/admin-dashboard" className='flex items-center gap-2 hover:bg-zinc-600 p-2 rounded-lg duration-300'> <MdTableView size={25} /> Admin Paneli</Link>)}


                    <Link id='1' onClick={() => sidebarSelect(1)} to="/" className='flex items-center gap-2 hover:bg-zinc-600 p-2 rounded-lg duration-300 mt-2 selected bg-zinc-600'> <AiOutlineQuestionCircle size={25} /> Birim Sorular</Link>

                    {(auth.role === 'admin' || auth?.role === 'upg') && (<Link id='2' onClick={() => sidebarSelect(2)} to="/upg-soru-ekle" className='flex items-center gap-2 hover:bg-zinc-600 p-2 rounded-lg duration-300 mt-2'>
                        <div className='relative'>
                            <AiOutlineQuestionCircle size={25} />

                            <AiOutlinePlusCircle className='absolute top-3 -right-1 rounded-full bg-zinc-700 ' size={15} />
                        </div>
                        UPG Soru Ekle</Link>)}

                    {(auth.role === 'admin' || auth?.role === 'upg') && (<Link id='3' onClick={() => sidebarSelect(3)} to="/upg-cevaplar" className='flex items-center gap-2 hover:bg-zinc-600 p-2 rounded-lg duration-300 mt-2'> <TbCircleLetterC size={25} />UPG Cevaplar</Link>)}

                    {(auth.role === 'admin' || auth?.role === 'upg') && (<Link id='4' onClick={() => sidebarSelect(4)} to="/upg-cevap-basligi-ekle" className='flex items-center gap-2 hover:bg-zinc-600 p-2 rounded-lg duration-300 mt-2'>
                        <div className='relative'>
                            <TbCircleLetterC size={25} />

                            <AiOutlinePlusCircle className='absolute top-3 -right-1 rounded-full bg-zinc-700 ' size={15} />
                        </div>
                        UPG Cevap Başlığı Ekle</Link>)}

                    {/* <Link id='5' onClick={() => { logOut(); }} to="/" className='flex items-center gap-2 hover:bg-zinc-600 p-2 rounded-lg duration-300 mt-2'> <MdOutlineLogout size={25} /> Çıkış Yap</Link> */}
                    <Logout />
                </ul>
            </div>
        </div>
    )
}

I try to get username and role after immediately log in

2

Answers


  1. Chosen as BEST ANSWER

    I added my Sidebar inside AuthProvider, that fixed my problem, I can see Sidebar after I login system

    import { createContext, useState } from "react";
    import Sidebar from "../Sidebar";
    
    const AuthContext = createContext({});
    
    export const AuthProvider = ({ children }) => {
        const [auth, setAuth] = useState({
            username: null,
            password: null,
            role: null,
            accessToken: null,
        });
    
        const login = ({ username, password, role, accessToken }) => {
            setAuth({
                username,
                password,
                role,
                accessToken,
            })
        }
    
        const logout = () => {
            setAuth({
                username: null,
                password: null,
                role: null,
                accessToken: null,
            })
        }
    
        return (
            <AuthContext.Provider value={{ auth, setAuth, login, logout }}>
                {auth.username && <Sidebar/>}
                {children}
            </AuthContext.Provider>
        )
    }
    
    export default AuthContext;
    

  2. It seems useAuth hook is calling useContext(AuthContext) internally. If it is true, it means you are trying to get AuthContext outside of AuthProvider in App.js. As a result, you get a default value of the context, which is an empty object {}, and get undefined for its properties. To solve this problem, I think you should find a way to call useAuth under AuthProvider. Below is a simple version of what I think your code should be.

    function App() {
      return (
        <AuthProvider>
          <Sidebar />
        </AuthProvider>
      );
    }
    
    const Sidebar = () => {
      const { auth } = useAuth();
    
      if (auth?.role !== "admin") {
        return null;
      }
    
      // ...
    };
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search