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
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
Issue
The
rootReducer
is theauthReducer
, e.g.import rootReducer from './reducers';
, so there is nostate.auth
to select from.reducers.js:
store.js
Solution
store.js
should import the default exported reducer function from"./rootreducer"
.The
Navbar
component should then be able to correctly selectisAuthenticated
directly fromstate.auth
.Your
rootReducer
is actually yourauthReducer
, sostate.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