Folders in the sidebar component (react.js dashboard) doesn't always open when I click them

Viewed 375

Story

I'm using this react.js template http://skote-v-light.react.themesbrand.com/email-read from https://themeforest.net/item/skote-react-admin-dashboard-template/26318700 for building my react app.

I use and modify the sidebar component from the template and name it Sidebar.js.

There is SidebarContent.js for building the content inside the sidebar.

There is MenuComponent.js inside SidebarContent.js for building the menu inside the sidebar.

MenuComponent.js takes a list from menuList.js and renders it.

There are two dummy pages which are Route/Summary page (Summary.js) and Payload page (Payload.js) inside the Sidebar. I combine them all inside PageWithSidebar.js.

Question

Why don't always the ABC, DEF, etc folders in the sidebar open when I click them?

Ideal Condition I Wanted

Every folder (ABC, DEF, etc) inside the sidebar always opens when I click one of them.

Actual Condition

Please watch this demo to understand the context: https://drive.google.com/file/d/1Lig1SKKRtyRqxWm_OYNkuQennrytV0jo/view?usp=sharing

Steps:

  1. Click the Route/Summary option inside the ABC folder -> Summary page is shown (as I wanted)
  2. Click the Payload option inside the ABC folder -> Payload page is shown (as I wanted)
  3. Click another Route/Summary option inside the ABC folder -> Summary page is shown (as I wanted)
  4. Close the ABC folder -> The folder closes (as I wanted)
  5. Click the DEF folder -> The folder doesn't open (not I wanted)

There is no error or warning log in the browser console.

Code

PageWithSidebar.js:

import React from 'react'
import { Route, Switch } from "react-router-dom";

// COMPONENTS
import Sidebar from '../../components/Menu/Sidebar/Sidebar'

// PAGES
// ROUTE
import Summary from '../Routes/Summary/Summary'
// PAYLOAD
import Payload from '../Payload/Payload'

const PageWithSidebar = () => {
    return(
        <div id="layout-wrapper">
            <Sidebar/>
            <div className="main-content">
                <Switch>
                    {/* ROUTE */}
                    <Route path="/route/summary/location=:locationName">
                        <Summary/>
                    </Route>
                    <Route path="/payload/location=:locationName">
                        <Payload/>
                    </Route>
                </Switch>
            </div>
        </div>
    )
}

export default PageWithSidebar

Sidebar.js:

import React from "react"
import { Link } from "react-router-dom"

// COMPONENTS
import SidebarContent from './SidebarContent'

// IMAGES
import IconClose from '../../../images/icons/close.svg'
import IconOpen from '../../../images/icons/open.svg'

const Sidebar = () => {

    const toogleSidebar = () => {
        var body = document.body;
        body.classList.toggle("vertical-collpsed");
        body.classList.toggle("sidebar-enable");
    }

    return (
        <React.Fragment>
            <div className="vertical-menu">
                <div className="navbar-brand-box">
                    <Link to='/' className="logo logo-dark">
                        {/* SIDEBAR IS CLOSED */}
                        <span className="logo-sm">
                            {/* TOOGLE SIDEBAR BUTTON */}
                            <img src={IconOpen} alt='' className='icon-open' onClick={toogleSidebar}/>
                        </span>

                        {/* SIDEBAR IS OPEN */}
                        <span className="logo-lg sidebar-is-open-container">
                            {/* TOOGLE SIDEBAR BUTTON */}
                            <img src={IconClose} alt='' className='icon-close' onClick={toogleSidebar}/>
                        </span>
                    </Link>
                </div>

                {/* SIDEBAR CONTENT */}
                <SidebarContent />

                <div className="sidebar-background"></div>
            </div>
        </React.Fragment>
    )
}

export default Sidebar

SidebarContent.js:

import PropTypes from "prop-types"
import React, { useEffect, useRef, useState } from "react"
import { withRouter, Link, useLocation } from "react-router-dom"

// Import Scrollbar
import SimpleBar from "simplebar-react"

// MetisMenu
import MetisMenu from "metismenujs"

//i18n
import { withTranslation } from "react-i18next"

// COMPONENTS
import MenuComponent from './MenuComponent'

// IMAGES
import IconFolderGray from '../../../images/icons/folder-gray.svg'
import IconFolderRed from '../../../images/icons/folder-red.svg'
import IconLogout from '../../../images/icons/logout.svg'

// MENU ITEMS
import menuList from './menuList/menuList'

// STYLES
import './styles.scss'
import logoutUser from '../../../utils/authentication/logOut'

const SidebarContent = props => {

    // MY OWN CODE SECTION
    const location = useLocation()
    const pathName = location['pathname']
    let locationName = ''
    if(pathName.includes('route')) {
        locationName = pathName.split('/')[3].replace('location=', '')
    }
    else {
        locationName = pathName.split('/')[2].replace('location=', '')
    }
    // console.log('SidebarContent, locationName:', locationName)
    
    // TEMPLATE CODE SECTION
    const ref = useRef()

    useEffect(() => {
        const pathName = props.location.pathname

        const initMenu = () => {
            new MetisMenu("#side-menu")
            let matchingMenuItem = null
            const ul = document.getElementById("side-menu")
            const items = ul.getElementsByTagName("a")

            for (let i = 0; i < items.length; ++i) {
                if (pathName === items[i].pathname) {
                    matchingMenuItem = items[i]
                    break
                }
            }

            if (matchingMenuItem) {
                activateParentDropdown(matchingMenuItem)
            }
        }
        
        initMenu()
    }, [props.location.pathname])

    useEffect(() => {
        ref.current.recalculate()
    })

    function scrollElement(item) {
        if (item) {
            const currentPosition = item.offsetTop
            if (currentPosition > window.innerHeight) {
                ref.current.getScrollElement().scrollTop = currentPosition - 300
            }
        }
    }

    function activateParentDropdown(item) {
        item.classList.add("active")
        const parent = item.parentElement
        const parent2El = parent.childNodes[1]
        if (parent2El && parent2El.id !== "side-menu") {
            parent2El.classList.add("mm-show")
        }

        if (parent) {
            parent.classList.add("mm-active")
            const parent2 = parent.parentElement

            if (parent2) {
                parent2.classList.add("mm-show") // ul tag

                const parent3 = parent2.parentElement // li tag

                if (parent3) {
                    parent3.classList.add("mm-active") // li
                    parent3.childNodes[0].classList.add("mm-active") //a
                    const parent4 = parent3.parentElement // ul
                    if (parent4) {
                        parent4.classList.add("mm-show") // ul
                        const parent5 = parent4.parentElement
                        if (parent5) {
                            parent5.classList.add("mm-show") // li
                            parent5.childNodes[0].classList.add("mm-active") // a tag
                        }
                    }
                }
            }
            scrollElement(item);
            return false
        }
        scrollElement(item);
        return false
    }

    // MY OWN CODE SECTION
    const itemList = ['ABC', 'DEF', 'GHI', 'JKL', 'MNO', 'PQR']

    const [ selectedItem, setSelectedItem ] = useState(itemList.indexOf(locationName.toUpperCase()))

    return (
        <React.Fragment>
            <SimpleBar style={{ maxHeight: "100%" }} ref={ref}>
                <div id="sidebar-menu">
                    <ul className="metismenu list-unstyled sidebar-content-menu-container" id="side-menu">
                        {/* TITLE */}
                        <li className="menu-title sidebar-content-site-profile-title">Dummy Locations</li>

                        {/* ITEMS */}
                        {
                            itemList.map((item, index) => (
                                <li
                                    key={index}
                                    className={selectedItem === index ? 'sidebar-content-dropdown-selected' : 'sidebar-content-dropdown'}
                                    // onClick={() => setSelectedItem(index)}
                                >
                                    {/* TITLE */}
                                    <Link to="/" className="has-arrow dropdown-link">
                                        {/* FOLDER ICON */}
                                        <img 
                                            src={selectedItem === index ? IconFolderRed : IconFolderGray} 
                                            alt='' 
                                            className='bx sidebar-content-icon-folder-gray'
                                        />
                                        
                                        {/* TEXT */}
                                        <span className='dropdown-span'>
                                            {item}
                                        </span>
                                    </Link>

                                    {/* MENU COMPONENT*/}
                                    <ul className="sub-menu" aria-expanded="false">
                                        <div className='border-line'></div>
                                        <MenuComponent list={menuList} pathName={item.toLowerCase()}/>
                                    </ul>
                                </li>
                            ))
                        }

                        {/* PROFILE */}
                        <li className='sidebar-content-single-item-container'>
                            <Link to='/'>
                                <div onClick={logoutUser}>
                                    <img src={IconLogout} alt='' className='sidebar-content-icon-single-item'/>
                                    <span className='sidebar-content-span-single-item'>Logout</span>
                                </div>
                            </Link>
                        </li>
                    </ul>
                </div>
            </SimpleBar>
        </React.Fragment>
    )
}

SidebarContent.propTypes = {
    location: PropTypes.object,
    t: PropTypes.any,
}

export default withRouter(withTranslation()(SidebarContent))

MenuComponent.js:

import React, { useState } from 'react'
import { Link } from "react-router-dom"

const MenuComponent = (props) => {
    const [ selectedItem, setSelectedItem ] = useState(0)

    return(
        props['list'].map((item, index) => (
            <li 
                key={index}
                onClick={() => setSelectedItem(index)}
            >
                <Link 
                    to={`${item['path']}/location=${props['pathName']}`}
                    className='menu-component-root'
                >
                    {/* CIRCLE */}
                    <div className={selectedItem === index ? 'circle-selected' : 'circle'}></div>

                    {/* TEXT */}
                    <p className='text'>
                        {item['text']}
                    </p>
                </Link>
            </li>
        ))
    )
}

export default MenuComponent

menuList.js:

const menuList = [
    {
        path: '/route/summary',
        text: 'Route/Summary'
    },
    {
        path: '/route/summary',
        text: 'Route/Summary'
    },
    {
        path: '/payload',
        text: 'Payload'
    },
    {
        path: '/route/summary',
        text: 'Route/Summary'
    },
    {
        path: '/route/summary',
        text: 'Route/Summary'
    },
    {
        path: '/route/summary',
        text: 'Route/Summary'
    },
    {
        path: '/route/summary',
        text: 'Route/Summary'
    }
]

export default menuList

Summary.js:

import React from "react"

import { Row, Col } from "reactstrap"

// STYLES
import './styles.scss'

const Summary = () => {
    return (
        <React.Fragment>
            <div className="container-fluid route-summary-root">
                <Row>
                    <Col className="col-12">
                        {/* TOP CONTAINER */}
                        <div className='top-container'>

                            {/* LEFT CONTAINER */}
                            <div className='top-left-container'>
                                <h3 className='title'> Route/Summary Page</h3>
                            </div>
                        </div>
                    </Col>
                </Row>
            </div>
        </React.Fragment>
    )
}

export default Summary

Payload.js:

import React from "react"

import { Row, Col } from "reactstrap"

// STYLES
import './styles.scss'

const Payload = () => {
    return (
        <React.Fragment>
            <div className="container-fluid payload-root">
                <Row>
                    <Col className="col-12">
                        {/* TOP CONTAINER */}
                        <div className='top-container'>

                            {/* LEFT CONTAINER */}
                            <div className='top-left-container'>
                                <h3 className='title'>Payload Page</h3>
                            </div>
                        </div>
                    </Col>
                </Row>
            </div>
        </React.Fragment>
    )
}

export default Payload

Note: let me know if the question is confusing. I will try to update it.

0 Answers
Related