Repository URL to install this package:
|
Version:
8.1.0-rc.5 ▾
|
/* eslint-disable react/no-unused-prop-types */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Wrapper as RAMWrapper, Button as RAMButton, Menu as RAMMenu } from 'react-aria-menubutton';
import classNames from 'classnames';
import Icon from '../../../visuals/Icon';
import HamburgerIcon from '../../../visuals/Icon/svg/ic_menu.svg';
import UserArea from './UserArea';
import Submenu from './Submenu';
import MenuItem from './MenuItem';
import { defaultItems, adminMenuItem } from '../../../user/UserMenu/UserMenu';
import { userPropType, isLoggedIn } from '../../../utils/user';
import { translateMenuItems } from '../../../utils/translate';
import { separatorToken, submenuKey } from '../constants';
import navigateToUrl from '../../../utils/helper';
class HamburgerMenu extends Component {
constructor(props) {
super(props);
this.state = {
openSubmenus: [],
};
this.handleClickLogout = this.handleClickLogout.bind(this);
}
/**
* Handles calling the onClickLogout and passes the default behaviour
* into the onClickLogout callback as an argument.
* To override or add behaviour, see onClickLogout prop.
*/
handleClickLogout() {
const { onClickLogout } = this.props;
onClickLogout(() => navigateToUrl('/logout'));
}
/**
* Callback required by the react-aria-menubutton. This is only used for triggering
* any action props that have been set on menu items.
*
* @param {string} selectedValue - The label of the menu item that was invoked.
*/
handleSelection = finalItems => selectedValue => {
finalItems.forEach(item => {
if (item === separatorToken) {
return;
}
const isSubmenu = submenuKey in item;
let selectedItem;
if (item.label === selectedValue) {
selectedItem = item;
} else if (isSubmenu) {
selectedItem = item.submenu.find(subItem => subItem.label === selectedValue);
}
if (selectedItem && selectedItem.action) {
selectedItem.action();
}
});
};
toggleSubmenu = item => {
const { openSubmenus } = this.state;
const newOpen = openSubmenus.includes(item.label)
? openSubmenus.filter(label => label !== item.label)
: [...openSubmenus, item.label];
this.setState({ openSubmenus: newOpen });
};
createMenuItems = () => {
const { user, items: itemsFromProps, intl, isOrgAdmin } = this.props;
// Add toggleSubmenu action to all submenu heads
const items = itemsFromProps.map(
item =>
submenuKey in item
? {
...item,
action: () => {
this.toggleSubmenu(item);
},
}
: item
);
// Add user items if we're logged in
if (isLoggedIn(user)) {
const userItems = translateMenuItems(defaultItems, intl);
const userMenuItems = [
userItems[0], // Dashboard
userItems[1], // Account settings
separatorToken,
...items,
userItems[2],
separatorToken,
{
// Log out
label: userItems[3].label,
action: this.handleClickLogout,
},
];
if (isOrgAdmin) {
userMenuItems.splice(2, 0, translateMenuItems(adminMenuItem, intl)[0]);
}
return userMenuItems;
}
return items;
};
render() {
const { className, user, onClickLogin, onClickSignup, intl } = this.props;
const { openSubmenus } = this.state;
const finalItems = this.createMenuItems();
let addSeparatorToNext = false;
return (
<RAMWrapper
tag="nav"
className={classNames('Menu', className)}
onSelection={this.handleSelection(finalItems)}
closeOnSelection={false}
>
<RAMButton className={classNames('Button', 'Button--linkDark', 'Button--compact')}>
<Icon icon={HamburgerIcon} />
</RAMButton>
<RAMMenu className="HamburgerMenu-menu" tag="ul">
<UserArea user={user} onClickLogin={onClickLogin} onClickSignup={onClickSignup} intl={intl} />
{finalItems.length > 0 &&
finalItems.map(item => {
if (item === separatorToken) {
addSeparatorToNext = true;
return null;
}
if (submenuKey in item) {
const open = openSubmenus.includes(item.label);
return (
<Submenu
head={item}
items={item.submenu}
open={open}
toggleSubmenu={this.toggleSubmenu}
key={item.label}
/>
);
}
const separatorClass = addSeparatorToNext ? 'u-separatorBefore' : '';
addSeparatorToNext = false;
return <MenuItem item={item} key={item.label} className={separatorClass} />;
})}
</RAMMenu>
</RAMWrapper>
);
}
}
HamburgerMenu.propTypes = {
className: PropTypes.string,
/** Defines the user and the shape of the data. */
user: userPropType,
/** Defines the menu items within the Hamburger Menu */
items: PropTypes.array,
/**
* Callback executed when the user clicks on the "Login" button.
* It can be overridden to add custom functionality such as tracking.
* You can execute the default button behaviour within onClickLogin by running
* the function provided as first parameter. If your custom code is asynchronous,
* run the default behaviour as callback of your asynchronous action. This guarantees
* that your custom action completes before navigating to another page.
* @param {Function} defaultBehaviour - Function to execute the default click behaviour
*/
onClickLogin: PropTypes.func,
/**
* Callback executed when the user clicks on the "Logout" button.
* It can be overridden to add custom functionality such as tracking.
* You can execute the default button behaviour within onClickLogout by running
* the function provided as first parameter. If your custom code is asynchronous,
* run the default behaviour as callback of your asynchronous action. This guarantees
* that your custom action completes before navigating to another page.
* @param {Function} defaultBehaviour - Function to execute the default click behaviour
*/
onClickLogout: PropTypes.func,
/**
* Callback executed when the user clicks on the "Signup" button.
* It can be overridden to add custom functionality such as tracking.
* You can execute the default button behaviour within onClickSignup by running
* the function provided as first parameter. If your custom code is asynchronous,
* run the default behaviour as callback of your asynchronous action. This guarantees
* that your custom action completes before navigating to another page.
* @param {Function} defaultBehaviour - Function to execute the default click behaviour
*/
onClickSignup: PropTypes.func,
/** An object used for internationalization. */
intl: PropTypes.object,
/** Is the logged in user an admin of an organisation
*/
isOrgAdmin: PropTypes.bool,
};
HamburgerMenu.defaultProps = {
className: '',
user: null,
items: [],
onClickLogin: defaultBehaviour => defaultBehaviour(),
onClickLogout: defaultBehaviour => defaultBehaviour(),
onClickSignup: defaultBehaviour => defaultBehaviour(),
intl: null,
isOrgAdmin: false,
};
export default HamburgerMenu;