| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 | 
							- import React, { Component } from 'react';
 
- import PropTypes from 'prop-types';
 
- import { withTranslation, Trans } from '@/components/Common/Translate';
 
- import Link from 'next/link';
 
- import Router, { withRouter } from 'next/router';
 
- import { Collapse, Badge } from 'reactstrap';
 
- import { connect } from 'react-redux';
 
- import { bindActionCreators } from 'redux';
 
- import * as actions from '../../store/actions/actions';
 
- import SidebarUserBlock from './SidebarUserBlock';
 
- import Menu from './Menu.js';
 
- // Helper to check for parrent of an given elements
 
- const parents = (element, selector) => {
 
-     if (typeof selector !== 'string') {
 
-         return null;
 
-     }
 
-     const parents = [];
 
-     let ancestor = element.parentNode;
 
-     while (
 
-         ancestor &&
 
-         ancestor.nodeType === Node.ELEMENT_NODE &&
 
-         ancestor.nodeType !== 3 /*NODE_TEXT*/
 
-     ) {
 
-         if (ancestor.matches(selector)) {
 
-             parents.push(ancestor);
 
-         }
 
-         ancestor = ancestor.parentNode;
 
-     }
 
-     return parents;
 
- };
 
- // Helper to get outerHeight of a dom element
 
- const outerHeight = (elem, includeMargin) => {
 
-     const style = getComputedStyle(elem);
 
-     const margins = includeMargin
 
-         ? parseInt(style.marginTop, 10) + parseInt(style.marginBottom, 10)
 
-         : 0;
 
-     return elem.offsetHeight + margins;
 
- };
 
- /**
 
-     Component to display headings on sidebar
 
- */
 
- const SidebarItemHeader = ({ item }) => (
 
-     <li className="nav-heading">
 
-         <span>
 
-             <Trans i18nKey={item.translate}>{item.heading}</Trans>
 
-         </span>
 
-     </li>
 
- );
 
- /**
 
-     Normal items for the sidebar
 
- */
 
- const SidebarItem = ({ item, isActive, className, onMouseEnter }) => (
 
-     <li className={isActive ? 'active' : ''} onMouseEnter={onMouseEnter}>
 
-         <Link href={item.path} as={item.as}>
 
-             <a title={item.name}>
 
-                 {item.label && (
 
-                     <Badge tag="div" className="float-right" color={item.label.color}>
 
-                         {item.label.value}
 
-                     </Badge>
 
-                 )}
 
-                 {item.icon && <em className={item.icon} />}
 
-                 <span>
 
-                     <Trans i18nKey={item.translate}>{item.name}</Trans>
 
-                 </span>
 
-             </a>
 
-         </Link>
 
-     </li>
 
- );
 
- /**
 
-     Build a sub menu with items inside and attach collapse behavior
 
- */
 
- const SidebarSubItem = ({ item, isActive, handler, children, isOpen, onMouseEnter }) => (
 
-     <li className={isActive ? 'active' : ''}>
 
-         <div className="nav-item" onClick={handler} onMouseEnter={onMouseEnter}>
 
-             {item.label && (
 
-                 <Badge tag="div" className="float-right" color={item.label.color}>
 
-                     {item.label.value}
 
-                 </Badge>
 
-             )}
 
-             {item.icon && <em className={item.icon} />}
 
-             <span>
 
-                 <Trans i18nKey={item.translate}>{item.name}</Trans>
 
-             </span>
 
-         </div>
 
-         <Collapse isOpen={isOpen}>
 
-             <ul id={item.path} className="sidebar-nav sidebar-subnav">
 
-                 {children}
 
-             </ul>
 
-         </Collapse>
 
-     </li>
 
- );
 
- /**
 
-     Component used to display a header on menu when using collapsed/hover mode
 
- */
 
- const SidebarSubHeader = ({ item }) => <li className="sidebar-subnav-header">{item.name}</li>;
 
- const SidebarBackdrop = ({ closeFloatingNav }) => (
 
-     <div className="sidebar-backdrop" onClick={closeFloatingNav} />
 
- );
 
- const FloatingNav = ({ item, target, routeActive, isFixed, closeFloatingNav }) => {
 
-     let asideContainer = document.querySelector('.aside-container');
 
-     let asideInner = asideContainer.firstElementChild; /*('.aside-inner')*/
 
-     let sidebar = asideInner.firstElementChild; /*('.sidebar')*/
 
-     let mar =
 
-         parseInt(getComputedStyle(asideInner)['padding-top'], 0) +
 
-         parseInt(getComputedStyle(asideContainer)['padding-top'], 0);
 
-     let itemTop = target.parentElement.offsetTop + mar - sidebar.scrollTop;
 
-     let vwHeight = document.body.clientHeight;
 
-     const setPositionStyle = el => {
 
-         if (!el) return;
 
-         el.style.position = isFixed ? 'fixed' : 'absolute';
 
-         el.style.top = itemTop + 'px';
 
-         el.style.bottom = outerHeight(el, true) + itemTop > vwHeight ? 0 : 'auto';
 
-     };
 
-     return (
 
-         <ul
 
-             id={item.path}
 
-             ref={setPositionStyle}
 
-             className="sidebar-nav sidebar-subnav nav-floating"
 
-             onMouseLeave={closeFloatingNav}
 
-         >
 
-             <SidebarSubHeader item={item} />
 
-             {item.submenu.map((subitem, i) => (
 
-                 <SidebarItem key={i} item={subitem} isActive={routeActive(subitem.path)} />
 
-             ))}
 
-         </ul>
 
-     );
 
- };
 
- /**
 
-     The main sidebar component
 
- */
 
- class Sidebar extends Component {
 
-     state = {
 
-         collapse: {},
 
-         showSidebarBackdrop: false,
 
-         currentFloatingItem: null,
 
-         currentFloatingItemTarget: null,
 
-         pathname: this.props.router.pathname
 
-     };
 
-     componentDidMount() {
 
-         // prepare the flags to handle menu collapsed states
 
-         this.buildCollapseList();
 
-         // Listen for routes changes in order to hide the sidebar on mobile
 
-         Router.events.on('routeChangeStart', this.handleRouteChange);
 
-         Router.events.on('routeChangeComplete', this.handleRouteComplete);
 
-         // Attach event listener to automatically close sidebar when click outside
 
-         document.addEventListener('click', this.closeSidebarOnExternalClicks);
 
-     }
 
-     handleRouteComplete = (pathname) => {
 
-         this.setState({
 
-             pathname
 
-         })
 
-     }
 
-     handleRouteChange = () => {
 
-         this.closeFloatingNav();
 
-         this.closeSidebar();
 
-     };
 
-     componentWillUnmount() {
 
-         document.removeEventListener('click', this.closeSidebarOnExternalClicks);
 
-         Router.events.off('routeChangeStart', this.handleRouteChange);
 
-         Router.events.off('routeChangeComplete', this.handleRouteComplete);
 
-     }
 
-     closeSidebar = () => {
 
-         this.props.actions.toggleSetting('asideToggled');
 
-     };
 
-     closeSidebarOnExternalClicks = e => {
 
-         // don't check if sidebar not visible
 
-         if (!this.props.settings.asideToggled) return;
 
-         if (
 
-             !parents(e.target, '.aside-container').length && // if not child of sidebar
 
-             !parents(e.target, '.topnavbar-wrapper').length && // if not child of header
 
-             !e.target.matches('#user-block-toggle') && // user block toggle anchor
 
-             !e.target.parentElement.matches('#user-block-toggle') // user block toggle icon
 
-         ) {
 
-             this.closeSidebar();
 
-         }
 
-     };
 
-     /** prepare initial state of collapse menus.*/
 
-     buildCollapseList = () => {
 
-         let collapse = {};
 
-         Menu.filter(({ heading }) => !heading).forEach(({ name, path, submenu }) => {
 
-             collapse[name] = this.routeActive(submenu ? submenu.map(({ path }) => path) : path);
 
-         });
 
-         this.setState({ collapse });
 
-     };
 
-     routeActive = paths => {
 
-         const currpath = this.state.pathname;
 
-         paths = Array.isArray(paths) ? paths : [paths];
 
-         return paths.some(p => (p === '/' ? currpath === p : currpath.indexOf(p) > -1));
 
-     };
 
-     toggleItemCollapse = stateName => () => {
 
-         for (let c in this.state.collapse) {
 
-             if (this.state.collapse[c] === true && c !== stateName)
 
-                 this.setState({
 
-                     collapse: {
 
-                         [c]: false
 
-                     }
 
-                 });
 
-         }
 
-         this.setState({
 
-             collapse: {
 
-                 [stateName]: !this.state.collapse[stateName]
 
-             }
 
-         });
 
-     };
 
-     getSubRoutes = item => item.submenu.map(({ path }) => path);
 
-     /** map menu config to string to determine which element to render */
 
-     itemType = item => {
 
-         if (item.heading) return 'heading';
 
-         if (!item.submenu) return 'menu';
 
-         if (item.submenu) return 'submenu';
 
-     };
 
-     shouldUseFloatingNav = () => {
 
-         return (
 
-             this.props.settings.isCollapsed ||
 
-             this.props.settings.isCollapsedText ||
 
-             this.props.settings.asideHover
 
-         );
 
-     };
 
-     showFloatingNav = item => e => {
 
-         if (this.shouldUseFloatingNav())
 
-             this.setState({
 
-                 currentFloatingItem: item,
 
-                 currentFloatingItemTarget: e.currentTarget,
 
-                 showSidebarBackdrop: true
 
-             });
 
-     };
 
-     closeFloatingNav = () => {
 
-         this.setState({
 
-             currentFloatingItem: null,
 
-             currentFloatingItemTarget: null,
 
-             showSidebarBackdrop: false
 
-         });
 
-     };
 
-     render() {
 
-         return (
 
-             <>
 
-                 <aside className="aside-container">
 
-                     {/* START Sidebar (left) */}
 
-                     <div className="aside-inner">
 
-                         <nav
 
-                             className={
 
-                                 'sidebar ' +
 
-                                 (this.props.settings.asideScrollbar ? 'show-scrollbar' : '')
 
-                             }
 
-                         >
 
-                             {/* START sidebar nav */}
 
-                             <ul className="sidebar-nav">
 
-                                 {/* START user info */}
 
-                                 <li className="has-user-block">
 
-                                     <SidebarUserBlock />
 
-                                 </li>
 
-                                 {/* END user info */}
 
-                                 {/* Iterates over all sidebar items */}
 
-                                 {Menu.map((item, i) => {
 
-                                     // heading
 
-                                     if (this.itemType(item) === 'heading')
 
-                                         return <SidebarItemHeader item={item} key={i} />;
 
-                                     else {
 
-                                         if (this.itemType(item) === 'menu')
 
-                                             return (
 
-                                                 <SidebarItem
 
-                                                     isActive={this.routeActive(item.path)}
 
-                                                     item={item}
 
-                                                     key={i}
 
-                                                     onMouseEnter={this.closeFloatingNav}
 
-                                                 />
 
-                                             );
 
-                                         if (this.itemType(item) === 'submenu')
 
-                                             return [
 
-                                                 <SidebarSubItem
 
-                                                     item={item}
 
-                                                     isOpen={this.state.collapse[item.name]}
 
-                                                     handler={this.toggleItemCollapse(item.name)}
 
-                                                     isActive={this.routeActive(
 
-                                                         this.getSubRoutes(item)
 
-                                                     )}
 
-                                                     key={i}
 
-                                                     onMouseEnter={this.showFloatingNav(item)}
 
-                                                 >
 
-                                                     <SidebarSubHeader item={item} key={i} />
 
-                                                     {item.submenu.map((subitem, i) => (
 
-                                                         <SidebarItem
 
-                                                             key={i}
 
-                                                             item={subitem}
 
-                                                             isActive={this.routeActive(
 
-                                                                 subitem.path
 
-                                                             )}
 
-                                                         />
 
-                                                     ))}
 
-                                                 </SidebarSubItem>
 
-                                             ];
 
-                                     }
 
-                                     return null; // unrecognized item
 
-                                 })}
 
-                             </ul>
 
-                             {/* END sidebar nav */}
 
-                         </nav>
 
-                     </div>
 
-                     {/* END Sidebar (left) */}
 
-                     {this.state.currentFloatingItem && this.state.currentFloatingItem.submenu && (
 
-                         <FloatingNav
 
-                             item={this.state.currentFloatingItem}
 
-                             target={this.state.currentFloatingItemTarget}
 
-                             routeActive={this.routeActive}
 
-                             isFixed={this.props.settings.isFixed}
 
-                             closeFloatingNav={this.closeFloatingNav}
 
-                         />
 
-                     )}
 
-                 </aside>
 
-                 {this.state.showSidebarBackdrop && (
 
-                     <SidebarBackdrop closeFloatingNav={this.closeFloatingNav} />
 
-                 )}
 
-             </>
 
-         );
 
-     }
 
- }
 
- Sidebar.propTypes = {
 
-     actions: PropTypes.object,
 
-     settings: PropTypes.object
 
- };
 
- const mapStateToProps = state => ({ settings: state.settings });
 
- const mapDispatchToProps = dispatch => ({
 
-     actions: bindActionCreators(actions, dispatch)
 
- });
 
- export default connect(
 
-     mapStateToProps,
 
-     mapDispatchToProps
 
- )(withRouter(withTranslation(Sidebar)));
 
 
  |