import React, { Component } from 'react';
import { connect } from 'react-redux';
import SVGComponent from '../../components/SVG/SVGComponent';
import {
getUser,
getSelectedMenu,
getSelectedMenuItem,
toggleMenu,
checkPermisson,
hasFieldDataModified,
} from '../../selectors/common';
import { PAGES, MENU, SVG_ICONS, MENU_ITEMS, MENU_ROUTES, MENU_ICONS, PERMISSIONS, MODALS } from '../../constants';
import { aSetNavigationInfo, aSetOpenModal, aSetSelectedMenu } from '../../reducers/common';
import { aLogout } from '../../reducers/actions';
import { withRouterHooks } from '../../utils/router';
import { aLocationChange } from '../../reducers/bonus';
const mapToProps = (state) => ({
user: getUser(state),
selectedMenu: getSelectedMenu(state),
selectedMenuItem: getSelectedMenuItem(state),
toggleMenu: toggleMenu(state),
checkPermisson: (payload) => checkPermisson(state, payload),
hasFieldDataModified: hasFieldDataModified(state),
});
const actionsToProps = (dispatch) => ({
logout: (payload) => dispatch(aLogout(payload)),
setSelectedMenu: (payload) => dispatch(aSetSelectedMenu(payload)),
setOpenModal: (payload) => dispatch(aSetOpenModal(payload)),
setNavigationInfo: (payload) => dispatch(aSetNavigationInfo(payload)),
changeLocation: (payload) => dispatch(aLocationChange(payload)),
});
/**
* @class
* @property {object} props
* @property {object} props.user Logged user
* @property {string} props.selectedMenu Selected root item page
* @property {string} props.selectedMenuItem Selected item from dropdown
* @property {boolean} props.toggleMenu Indicate is menu item is changed and
* dropdowns need to recalculate
* @property {boolean} props.checkPermisson Show only allowed menu items
* @property {boolean} props.hasFieldDataModified check for modified field data
*
* @property {Function} props.logout Logout user
* @property {Function} props.setSelectedMenu Change selected root item from sidebar
* @property {Function} props.setOpenModal open modal
* @property {Function} props.setNavigationInfo set link for navigation
*/
class Menu extends Component {
constructor() {
super();
/**
* @member {object}
* @property {boolean} isOpened Indicate is dropdown opened
*/
this.state = {
isOpened: false,
};
}
/**
* Open dropdown on side nav
*
* @returns {void}
*/
componentDidMount() {
this.toggleMenu(this.props.selectedMenu, this.props.selectedMenu);
}
/**
* Toggle menu on toggleMenu flag change
*
* @param {object} prevProps
* @returns {void}
*/
componentDidUpdate(prevProps) {
if (this.props.toggleMenu !== prevProps.toggleMenu && this.props.selectedMenu !== prevProps.selectedMenu) {
this.toggleMenu(this.props.selectedMenu, prevProps.selectedMenu);
}
}
/**
* Return class name for root items
*
* @function
* @param {string} menuName
* @returns {string}
*/
getMenuClass = (menuName) => {
let result = 'side-nav__list-item-link has-dropdown ';
if (menuName === this.props.selectedMenu && this.state.isOpened) {
result += 'active open ';
}
return result;
};
/**
* Return class name for dropdown items
*
* @function
* @param {string} menuItemName
* @returns {string}
*/
getMenuItemClass = (menuItemName) => {
let result = 'side-nav__dropdown-link ';
if (menuItemName === this.props.selectedMenuItem) {
result += 'active ';
}
return result;
};
/**
* Return only autificated routes
*
* @function
* @param {string} route
* @returns {Array}
*/
getAuthItems = (route) => {
const newItems = [];
Object.keys(MENU_ITEMS[route]).map((key) => {
if (this.props.checkPermisson(PERMISSIONS[key])) {
newItems.push(MENU_ITEMS[route][key]);
}
});
return newItems;
};
/**
* Toggle dropdowns
*
* @function
* @param {string} menuName
* @param {string} prevMenu
* @returns {void}
*/
toggleMenu = (menuName, prevMenu) => {
let isOpened = !this.state.isOpened;
if (prevMenu !== menuName) {
isOpened = true;
this.props.setSelectedMenu({ menu: menuName });
const prevElement = document.getElementById(`${prevMenu}-side-nav`);
if (prevElement) {
prevElement.style.maxHeight = '0px';
}
}
const element = document.getElementById(`${menuName}-side-nav`);
if (element) {
if (isOpened) {
element.style.maxHeight = `${element.scrollHeight}px`;
setTimeout(() => {
const selectedElement = document.getElementById(`item-${menuName}`);
selectedElement.scrollIntoView({ block: 'start', behavior: 'smooth' });
}, 400);
} else {
element.style.maxHeight = '0px';
}
}
this.setState({
isOpened,
});
};
/**
* Logout user
*
* @function
* @returns {void}
*/
logout = () => {
this.props.logout({
callAPI: true,
navigate: this.props.navigate,
location: this.props.location,
});
};
/**
* Open confirmation modal before navigating
*
* @function
* @param {string} link
* @returns {void}
*/
handleNavigationClick = (link) => {
if (this.props.hasFieldDataModified) {
this.props.setOpenModal({
modal: MODALS.SAVE_BEFORE_NAVIGATION,
});
this.props.setNavigationInfo({
nextNavigationLink: link,
});
} else if (this.props.location.pathname !== link) {
this.props.changeLocation({ pathname: link });
this.props.navigate(link);
}
};
/**
* Render menu items
*
* @function
* @returns {view}
*/
renderMenu = () => (
<div className="side-nav__list">
{MENU_ROUTES.map((route) => {
const children = this.getAuthItems(route);
return (
children.length > 0 && (
<div id={`item-${MENU[route].key}`} className="side-nav__list-item" key={route}>
<div
className={this.getMenuClass(MENU[route].key)}
onClick={this.toggleMenu.bind(this, MENU[route].key, this.props.selectedMenu)}
>
<SVGComponent className="icon-xs" src={`${SVG_ICONS.homeIcons}#${MENU_ICONS[route]}`} />
<span>{MENU[route].name}</span>
</div>
<div className="side-nav__dropdown" id={`${MENU[route].key}-side-nav`}>
{children.map((item) => (
<div
key={item.path}
className={this.getMenuItemClass(item.path)}
onClick={this.handleNavigationClick.bind(this, item.path)}
>
{item.name}
</div>
))}
</div>
</div>
)
);
})}
</div>
);
/**
* Render home page
*
* @function
* @returns {view}
*/
renderHomePage = () => (
<div className="home d-flex align-item-center">
<div className="info-panel">
<div className="s-logo" />
<div className="info-panel__user">
<div className="info-panel__user-name">{this.props.user && this.props.user.name}</div>
<div
id="myProfileBtn_homepage"
className="side-nav__user-role"
onClick={this.handleNavigationClick.bind(this, PAGES.MY_PROFILE)}
>
{MENU_ITEMS.PROFILE.MY_PROFILE.name}
</div>
</div>
<div className="info-panel__button">
<button id="logout_homepage" type="button" className="btn btn-primary" onClick={this.logout}>
Logout
</button>
</div>
</div>
<div className="home-panel-wrapper">
<div className="home-panel">
<div className="home-panel__txt">
Welcome to the Backoffice,
<span>Choose your option below.</span>
</div>
<div className="side-nav side-nav--home">{this.renderMenu()}</div>
</div>
<div className="login__heading">Backoffice</div>
</div>
</div>
);
/**
* Render side nav
*
* @function
* @returns {view}
*/
renderSideNav = () => (
<div className="side-nav">
<div className="s-logo xs" />
<div className="side-nav__user">
<div className="side-nav__user-name">{this.props.user && this.props.user.name}</div>
<div className="side-nav__user-role" onClick={this.handleNavigationClick.bind(this, PAGES.MY_PROFILE)}>
{MENU_ITEMS.PROFILE.MY_PROFILE.name}
</div>
</div>
<div className="side-nav__button text-center">
<button type="button" className="btn btn-primary" onClick={this.logout}>
Logout
</button>
</div>
{this.renderMenu()}
</div>
);
/**
* Render
*
* @returns {view}
*/
render() {
return this.props.location.pathname === PAGES.HOME ? this.renderHomePage() : this.renderSideNav();
}
}
export default connect(mapToProps, actionsToProps)(withRouterHooks(Menu));