Home > database >  How can I change this Navbar dropdown item to update from "Login" to "Logout" wh
How can I change this Navbar dropdown item to update from "Login" to "Logout" wh

Time:03-16

I am trying to update my Navbar component so that when a user logs in, the navbar dropdown item "Login" changes to "Logout" but I am having issues. I am new to react and JS but learning as I go, so I apologize for any confusion in this question. I have jsx components for my Navbar, Dropdown, Footer, and for each page that a user wants to view which is rendered in my App.js file.

Navbar.jsx:

import React, {useState, useEffect} from 'react';
import {Link} from 'react-router-dom'; 
import './Navbar.css';
import Dropdown from './Dropdown';
import {NavItemsList} from './NavItemsList';
import NavItems from './NavItems';

function Navbar() {
    const [click, setClick] = useState(false); 
    const [button, setButton] = useState(true);
    const [dropdown, setDropdown] = useState(false);

    const handleClick = () => setClick(!click);
    const closeMobileMenu = () => setClick(false);

    const onm ouseEnter = () => {
        if (window.innerWidth < 960) {
            setDropdown(false);
        } else {
            setDropdown(true);
        }
    };

    const onm ouseLeave = () => {
        if (window.innerWidth < 960) {
            setDropdown(false);
        } else {
            setDropdown(false);
        }
    };

    return (
        <>
            <nav className='navbar'>
                <div className='navbar-container-whole'>
                    <div className='left-nav-container'>
                        {/* Link in react-router-dom essentially replaces a tag.*/}
                        <Link to='/' className='navbar-logo'>
                            <img src='/images/logo.png' className='hashtek-logo' alt='logo' />
                            <h1 className='navbar-name'>HashTek</h1>
                        </Link>
                    </div>
                    {/* .navbar-container will create a div with that class name. */}
                    <div className='center-nav-container'>
                        <form action='./' method='get' id='search-form'>
                            <div class='searchbar'>
                                <input
                                    class='searchbar_input'
                                    type='search'
                                    name='search'
                                    placeholder='Search..'
                                />

                                <button type='submit' class='searchbar_button'>
                                    <i class='material-icons'>search</i>
                                </button>
                            </div>
                        </form>
                    </div>
                    <div className='right-nav-container'>
                        <ul className={click ? 'nav-menu active' : 'nav-menu'}>
                            <div className='text-links'>
                                {/* This line above is for when you are on mobile, and an item is clicked, the nav menu will disappear */}
                                {NavItemsList.slice(0, 4).map((menu, index) => {
                                    return <NavItems items={menu} key={index} />;
                                })}
                            </div>
                            <div className='logo-links'>
                                {NavItemsList.slice(4, 6).map((menu, index) => {
                                    return <NavItems items={menu} key={index} />;
                                })}
                            </div>
                        </ul>
                        <div className='menu-icon' onClick={handleClick}>
                            <i className={click ? 'fas fa-times' : 'fas fa-bars'} />
                        </div>
                    </div>
                </div>
            </nav>
        </>
    );
}

export default Navbar;

NavItemsList.js:

export const NavItemsList = [
    {
        title: 'Products',
        path: '/products',
        cName: 'nav-links',
    },
    {
        title: 'Stats',
        path: '/stats',
        cName: 'nav-links',
    },
    {
        title: 'Contacts',
        path: '/contacts',
        cName: 'nav-links',
        subNav: [
            {
                title: 'About',
                path: '/contacts/about',
                cName: 'dropdown-link',
                menuName: 'contacts-menu',
            },
            {
                title: 'How To',
                path: '/contacts/how-to',
                cName: 'dropdown-link',
                menuName: 'contacts-menu',
            },
            {
                title: 'Developers',
                path: '/contacts/developers',
                cName: 'dropdown-link',
                menuName: 'contacts-menu',
            },
            {
                title: 'Designers',
                path: '/contacts/designers',
                cName: 'dropdown-link',
                menuName: 'contacts-menu',
            },
            {
                title: 'Mentors',
                path: '/contacts/mentors',
                cName: 'dropdown-link',
                menuName: 'contacts-menu',
            },
        ],
    },
    {
        title: 'Services',
        path: '/services',
        cName: 'nav-links',
        subNav: [
            {
                title: 'Streaming',
                path: '/services/streaming',
                cName: 'dropdown-link',
                menuName: 'services-menu',
            },
            {
                title: 'Editing',
                path: '/services/editing',
                cName: 'dropdown-link',
                menuName: 'services-menu',
            },
        ],
    },
    {
        title: Account,
        path: '/my-account',
        cName: 'nav-links',
        subNav: [
            {
                title: 'Login',
                path: '/login',
                cName: 'dropdown-link',
                menuName: 'account-menu',
            },
            {
                title: 'Profile',
                path: '/profile',
                cName: 'dropdown-link',
                menuName: 'account-menu',
            },
        ],
    },
    {
        title: Help,
        path: '/help',
        cName: 'nav-links',
    },
];

Dropdown.jsx:

import React, {useState} from 'react';
import {Link} from 'react-router-dom';
import './Dropdown.css';

function Dropdown(props) {
    const [click, setClick] = useState(false);
    const handleClick = () => setClick(!click);
    const submenus = props.submenus;

    return (
        <ul
            onClick={handleClick}
            className={click ? 'dropdown-menu clicked' : 'dropdown-menu'}
        >
            {submenus.map((subNav, index) => (
                <div className={subNav.menuName}>
                    <li key={index} className='dropdown-links'>
                        <Link
                            className={subNav.cName}
                            to={subNav.path}
                            onClick={() => setClick(false)}
                        >
                            {subNav.title}
                        </Link>
                    </li>
                </div>
            ))}
        </ul>
    );
}

export default Dropdown;

NavItems.jsx:

import React, {useState} from 'react';
import Dropdown from './Dropdown';
import {Link} from 'react-router-dom';

function NavItems(props) {
    const items = props.items;
    const [click, setClick] = useState(false);
    const handleClick = () => setClick(!click);
    const [dropdown, setDropdown] = useState(false);

    const onm ouseEnter = () => {
        if (window.innerWidth < 960) {
            setDropdown(false);
        } else {
            setDropdown(true);
        }
    };

    const onm ouseLeave = () => {
        if (window.innerWidth < 960) {
            setDropdown(false);
        } else {
            setDropdown(false);
        }
    };

    return (
        <div className='link-container' onm ouseLeave={onMouseLeave}>
            <li className='nav-item'>
                {items.subNav ? (
                    <>
                        <Link
                            className={items.cName}
                            to={items.path}
                            onClick={() => setClick(false)}
                            onm ouseEnter={onMouseEnter}
                        >
                            {items.title}
                        </Link>

                        {dropdown && <Dropdown submenus={items.subNav} />}
                    </>
                ) : (
                    <Link
                        className={items.cName}
                        to={items.path}
                        onClick={() => setClick(false)}
                    >
                        {items.title}
                    </Link>
                )}
            </li>
        </div>
    );
}

export default NavItems;

I am following a tutorial that implements the navbar in their App.js file as follows:

import React, { useState, useEffect, useCallback } from "react";
import { useDispatch, useSelector } from "react-redux";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css";
import Login from "./components/Login";
import Register from "./components/Register";
import Home from "./components/Home";
import Profile from "./components/Profile";
import BoardUser from "./components/BoardUser";
import BoardModerator from "./components/BoardModerator";
import BoardAdmin from "./components/BoardAdmin";
import { logout } from "./slices/auth";
import EventBus from "./common/EventBus";
const App = () => {
  const [showModeratorBoard, setShowModeratorBoard] = useState(false);
  const [showAdminBoard, setShowAdminBoard] = useState(false);
  const { user: currentUser } = useSelector((state) => state.auth);
  const dispatch = useDispatch();
  const logOut = useCallback(() => {
    dispatch(logout());
  }, [dispatch]);
  useEffect(() => {
    if (currentUser) {
      setShowModeratorBoard(currentUser.roles.includes("ROLE_MODERATOR"));
      setShowAdminBoard(currentUser.roles.includes("ROLE_ADMIN"));
    } else {
      setShowModeratorBoard(false);
      setShowAdminBoard(false);
    }
    EventBus.on("logout", () => {
      logOut();
    });
    return () => {
      EventBus.remove("logout");
    };
  }, [currentUser, logOut]);
  return (
    <Router>
      <div>
        <nav className="navbar navbar-expand navbar-dark bg-dark">
          <Link to={"/"} className="navbar-brand">
            bezKoder
          </Link>
          <div className="navbar-nav mr-auto">
            <li className="nav-item">
              <Link to={"/home"} className="nav-link">
                Home
              </Link>
            </li>
            {showModeratorBoard && (
              <li className="nav-item">
                <Link to={"/mod"} className="nav-link">
                  Moderator Board
                </Link>
              </li>
            )}
            {showAdminBoard && (
              <li className="nav-item">
                <Link to={"/admin"} className="nav-link">
                  Admin Board
                </Link>
              </li>
            )}
            {currentUser && (
              <li className="nav-item">
                <Link to={"/user"} className="nav-link">
                  User
                </Link>
              </li>
            )}
          </div>
          {currentUser ? (
            <div className="navbar-nav ml-auto">
              <li className="nav-item">
                <Link to={"/profile"} className="nav-link">
                  {currentUser.username}
                </Link>
              </li>
              <li className="nav-item">
                //INTERESTED IN THIS
                <a href="/login" className="nav-link" onClick={logOut}> 
                </a>
              </li>
            </div>
          ) : (
            <div className="navbar-nav ml-auto">
              <li className="nav-item">
                <Link to={"/login"} className="nav-link">
                  Login
                </Link>
              </li>
              <li className="nav-item">
                <Link to={"/register"} className="nav-link">
                  Sign Up
                </Link>
              </li>
            </div>
          )}
        </nav>
        <div className="container mt-3">
          <Switch>
            <Route exact path={["/", "/home"]} component={Home} />
            <Route exact path="/login" component={Login} />
            <Route exact path="/register" component={Register} />
            <Route exact path="/profile" component={Profile} />
            <Route path="/user" component={BoardUser} />
            <Route path="/mod" component={BoardModerator} />
            <Route path="/admin" component={BoardAdmin} />
          </Switch>
        </div>
      </div>
    </Router>
  );
};
export default App;

From what I can tell, they are checking the state of the currentUser and if there is one, then the Navbar will be updated to display LogOut and the current user's username. This is where I am having trouble, since I have decided to import an array into my Navbar instead. Do I need to change my Navbar so that it renders the items in the Navbar component directly without the use of the NavItemsList, or is there a way for me to check the state and change "Login" to "Logout" without changing my NavItemsList component too much? Any help would be appreciated, I have been scratching my head on how to go about this without refactoring my hard work.

CodePudding user response:

I suggest you should add an "auth status" property to your links and routing configs so as you are mapping them into the UI you can check the current authentication status and render the appropriate content.

Example:

export const NavItemsList = [
    ...
    {
        title: Account,
        path: '/my-account',
        cName: 'nav-links',
        subNav: [
            {
                title: 'Login',
                path: '/login',
                cName: 'dropdown-link',
                menuName: 'account-menu',
                authenticated: false,
            },
            {
                title: 'Logout',
                path: '/logout',
                cName: 'dropdown-link',
                menuName: 'account-menu',
                authenticated: true,
            },
            {
                title: 'Profile',
                path: '/profile',
                cName: 'dropdown-link',
                menuName: 'account-menu',
            },
        ],
    },
    ...
];

...

function Dropdown({ submenus }) {
  const { user: currentUser } = useSelector((state) => state.auth);

  const [click, setClick] = useState(false);

  const handleClick = () => setClick(click => !click);

  return (
    <ul
      onClick={handleClick}
      className={click ? 'dropdown-menu clicked' : 'dropdown-menu'}
    >
      {submenus
        .filter(({ authenticated }) => {
          if (authenticated !== undefined) {
            return !!currentUser === authenticated;
          }
          return true;
        })
        .map((subNav) => (
          <div key={subNav.path} className={subNav.menuName}>
            <li className='dropdown-links'>
              <Link
                className={subNav.cName}
                to={subNav.path}
                onClick={() => setClick(false)}
              >
                {subNav.title}
              </Link>
            </li>
          </div>
        ))
      }
    </ul>
  );
}

CodePudding user response:

I would Ideally do something like this in the NavItem

{subNav.title==='Login'?(userLoggedIn?'Logout':'Login'):subNav.title}
  • Related