skip to Main Content

Actually in my navbar I want to show login and logout at a time. And when it shows logout and If user Click on that then It should work accordingly . But is is not working properly. Rather it is showing error. isAuthenticated is available in reducer.js
Error

Navbar.jsx:

import React, { useState } from "react";
import { NavLink, useNavigate } from "react-router-dom";
import { useSelector, useDispatch } from "react-redux";
import { logout } from "../../redux/actions";
import { links } from "../../data";
import "./Navbar.css";

const Navbar = () => {
  const [showMenu, setShowMenu] = useState(false);
  const isAuthenticated = useSelector((state) => state.auth.isAuthenticated);
  const dispatch = useDispatch();
  const navigate = useNavigate();

  const toggleMenu = () => {
    setShowMenu(!showMenu);
  };

  const handleLogout = () => {
    dispatch(logout());
    navigate("/");
  };

  let filteredLinks = links;

  if (isAuthenticated) {
    filteredLinks = links.filter((link) => link.name !== "Login");
  } else {
    filteredLinks = links.filter((link) => link.name !== "Logout");
  }

  return (
    <nav className="nav">
      <div className={`${showMenu ? "nav_menu show-menu" : "nav_menu"}`}>
        <ul className="nav_list">
          {filteredLinks.map(({ id, name, icon, path }) => (
            <li className="nav_item" key={id}>
              {name === "Logout" ? (
                <a className="nav_link" onClick={handleLogout}>
                  {icon}
                  <h3 className="nav_name">{name}</h3>
                </a>
              ) : (
                <NavLink
                  to={path}
                  className={({ isActive }) =>
                    isActive ? "nav_link active-nav" : "nav_link"
                  }
                  onClick={toggleMenu}
                >
                  {icon}
                  <h3 className="nav_name">{name}</h3>
                </NavLink>
              )}
            </li>
          ))}
        </ul>
      </div>

      <div
        className={`${showMenu ? "nav_toggle animate-toggle" : "nav_toggle"}`}
        onClick={toggleMenu}
      >
        <span></span>
        <span></span>
        <span></span>
      </div>
    </nav>
  );
};

export default Navbar;

data.jsx:

import {
  FaHome,
  FaUser,
  FaFolderOpen,
  FaEnvelopeOpen,
  FaBriefcase,
  FaGraduationCap,
  FaCode,
  FaLock,
  FaGithub,
} from "react-icons/fa";
import { FiFileText, FiUser, FiLogIn, FiLogOut, FiExternalLink } from "react-icons/fi";

export const links = [
  {
    id: 1,
    name: "Home",
    icon: <FaHome className="nav_icon" />,
    path: "/",
  },

  {
    id: 2,
    name: "About",
    icon: <FaUser className="nav_icon" />,
    path: "/about",
  },

  {
    id: 3,
    name: "Projects",
    icon: <FaFolderOpen className="nav_icon" />,
    path: "/portfolio",
  },

  {
    id: 4,
    name: "Contact",
    icon: <FaEnvelopeOpen className="nav_icon" />,
    path: "/contact",
  },
  // {
  //   id: 5,
  //   name: "SignUp",
  //   icon: <FiLogIn className="nav_icon" />,
  //   path: "/signup",
  // },
  {
    id: 6,
    name: "Login",
    icon: <FaLock className="nav_icon" />,
    path: "/login",
  },
  {
    id: 7,
    name: "logout",
    icon: <FiLogOut className="nav_icon" />,
    path: "/",
  },
];

Login.jsx:

import React, { useState } from "react";
import axios from "axios";
import { useNavigate } from "react-router-dom";
import { toast, ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import "./Login.css";

const Login = () => {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const navigate = useNavigate();

  const handleEmailChange = (e) => {
    setEmail(e.target.value);
  };

  const handlePasswordChange = (e) => {
    setPassword(e.target.value);
  };

  const handleLogin = async (e) => {
    e.preventDefault();
    try {
      const response = await axios.post("http://localhost:8080/login", {
        email,
        password,
      });

      // Assuming the response contains a token
      const token = response.data.token;

      // Save the token to localStorage
      localStorage.setItem("token", token);

      // Handle successful login here (e.g., redirect to admin dashboard)
      toast.success("Login successful", {
        position: "top-right",
        autoClose: 1000,
        hideProgressBar: false,
        closeOnClick: true,
        pauseOnHover: true,
        draggable: true,
        progress: undefined,
        theme: "light",
        onClose: () => {
          navigate("/admindashboard"); // Navigate after the toast message is closed
          setTimeout(() => {
            window.location.reload();
          }, 1000); // Delay the reload by 1000 milliseconds (1 second)
        },
      });
      // Set isLoggedIn state to true
    } catch (error) {
      // Handle login error here (e.g., display error message)
      toast.error("Login failed");
      console.log("Error:", error.response.data.message);
    }
  };

  return (
    <section className="login section">
      <h2 className="section_title">
        Login For <span>Admin</span>
      </h2>
      <form className="login_form" onSubmit={handleLogin}>
        <div className="login_form_input-group">
          <div className="form_input-div">
            <label className="login_form-title">Email:</label>
            <input
              type="email"
              placeholder="Your Email"
              className="form_control"
              value={email}
              onChange={handleEmailChange}
            />
          </div>
          <div className="form_input-div">
            <label className="login_form-title">Password:</label>
            <input
              type="password"
              placeholder="Your Password"
              className="form_control"
              value={password}
              onChange={handlePasswordChange}
            />
          </div>
        </div>
        <button className="button login_button" type="submit">
          <span className="button_name">Login</span>
        </button>
      </form>
      <ToastContainer />
    </section>
  );
};

export default Login;

actions.js:

// authActions.js

import axios from "axios";
export const REGISTER_SUCCESS = "REGISTER_SUCCESS";
export const REGISTER_FAIL = "REGISTER_FAIL";
export const LOGIN_SUCCESS = "LOGIN_SUCCESS";
export const LOGIN_FAIL = "LOGIN_FAIL";
export const LOGOUT = "LOGOUT";

export const register = (name, email, password) => async (dispatch) => {
  try {
    const response = await axios.post("/register", { name, email, password });
    dispatch({ type: REGISTER_SUCCESS, payload: response.data.token });
  } catch (error) {
    dispatch({ type: REGISTER_FAIL, payload: error.response.data.message });
  }
};

// Login action creator
export const login = (email, password) => async (dispatch) => {
  try {
    const response = await axios.post("/login", { email, password });
    dispatch({ type: LOGIN_SUCCESS, payload: response.data.token });
  } catch (error) {
    dispatch({ type: LOGIN_FAIL, payload: error.response.data.message });
  }
};

// Logout action creator
export const logout = () => ({ type: LOGOUT });

reducers.js:

import {
  REGISTER_SUCCESS,
  REGISTER_FAIL,
  LOGIN_SUCCESS,
  LOGIN_FAIL,
  LOGOUT,
} from "./actions";

const initialState = {
  token: null,
  isAuthenticated: false,
  error: null,
};

const authReducer = (state = initialState, action) => {
  switch (action.type) {
    case REGISTER_SUCCESS:
    case LOGIN_SUCCESS:
      return {
        ...state,
        token: action.payload,
        isAuthenticated: true,
        error: null,
      };
    case REGISTER_FAIL:
    case LOGIN_FAIL:
      return {
        ...state,
        token: null,
        isAuthenticated: false,
        error: action.payload,
      };
    case LOGOUT:
      return {
        ...state,
        token: null,
        isAuthenticated: false,
        error: null,
      };
    default:
      return state;
  }
};

export default authReducer;

rootreducer.js:

import { combineReducers } from "redux";
import authReducer from "./authReducer";

const rootReducer = combineReducers({
  auth: authReducer,
});

export default rootReducer;

store.js:

import { configureStore } from "@reduxjs/toolkit";
import thunk from "redux-thunk";
import rootReducer from "./reducers";

const store = configureStore({
  reducer: rootReducer,
  middleware: [thunk],
});

export default store;

main.jsx:

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import "./index.css";
import { Provider } from "react-redux";
import store from "./redux/store.js";

ReactDOM.createRoot(document.getElementById("root")).render(
  <Provider store={store}>
    <App />
  </Provider>
);

I want a solution which can help me to overcome the problem. It will be very helpful if anyone can help me to get out of this problem. Thanks in advance

2

Answers


  1. Issue

    The rootReducer is the authReducer, e.g. import rootReducer from './reducers';, so there is no state.auth to select from.

    reducers.js:

    const initialState = {
      token: null,
      isAuthenticated: false,
      error: null,
    };
    
    const authReducer = (state = initialState, action) => {
      ...
    };
    
    export default authReducer; // <-- default export
    

    store.js

    import rootReducer from "./reducers"; // <-- default import
    
    const store = configureStore({
      reducer: rootReducer, // <-- authReducer => state
      middleware: [thunk],
    });
    

    Solution

    store.js should import the default exported reducer function from "./rootreducer".

    import { configureStore } from "@reduxjs/toolkit";
    import thunk from "redux-thunk";
    import rootReducer from "./rootreducer";
    
    const store = configureStore({
      reducer: rootReducer, // <-- { auth: authReducer }
      middleware: [thunk],
    });
    
    export default store;
    

    The Navbar component should then be able to correctly select isAuthenticated directly from state.auth.

    const { isAuthenticated } = useSelector((state) => state.auth);
    
    Login or Signup to reply.
  2. Your rootReducer is actually your authReducer, so state.auth is undefined.

    You need to get isAuthenticated from just state.

    It should be something like this in your NavBar.jsx

    state.auth.isAuthenticated ==> state.isAuthenticated

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search