| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 | 
							- 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 { getUser } from "@/actions/auth";
 
- import Menu from "./Menu.js";
 
- import MenuLLDIKTI from "./MenuLLDIKTI.js";
 
- import MenuPT from "./MenuPT.js";
 
- // localStorage.getItem("user");
 
- // import Menu from './MenuPT.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 {
 
- 	menu = [];
 
- 	state = {
 
- 		collapse: {},
 
- 		showSidebarBackdrop: false,
 
- 		currentFloatingItem: null,
 
- 		currentFloatingItemTarget: null,
 
- 		pathname: this.props.router.pathname,
 
- 	};
 
- 	async componentDidMount() {
 
- 		// const user = await getUser();
 
- 		const user = this.props.user;
 
- 		this.menu = user.role.id === 2022 ? MenuPT : user.role.id === 2021 ? MenuLLDIKTI : Menu;
 
- 		// 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 = {};
 
- 		this.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 */}
 
- 								{this.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, user: state.user });
 
- const mapDispatchToProps = (dispatch) => ({
 
- 	actions: bindActionCreators(actions, dispatch),
 
- });
 
- export default connect(mapStateToProps, mapDispatchToProps)(withRouter(withTranslation(Sidebar)));
 
 
  |