Skip to content

Commit

Permalink
Refactor Navigation (#4876)
Browse files Browse the repository at this point in the history
Co-authored-by: Nilesh <[email protected]>
Co-authored-by: Víctor Fernández de Alba <[email protected]>
  • Loading branch information
3 people authored Sep 11, 2023
1 parent d08f92a commit bed71f5
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 171 deletions.
1 change: 1 addition & 0 deletions news/4076.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Refactor Navigation -@Tishasoumya-02
257 changes: 86 additions & 171 deletions src/components/theme/Navigation/Navigation.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
/**
* Navigation components.
* @module components/theme/Navigation/Navigation
*/

import React, { Component } from 'react';
import { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { compose } from 'redux';
import { defineMessages, injectIntl } from 'react-intl';
import { useDispatch, useSelector, shallowEqual } from 'react-redux';
import { defineMessages, useIntl } from 'react-intl';
import { Menu } from 'semantic-ui-react';

import cx from 'classnames';
import { BodyClass, getBaseUrl, hasApiExpander } from '@plone/volto/helpers';
import config from '@plone/volto/registry';
Expand All @@ -27,176 +22,96 @@ const messages = defineMessages({
},
});

/**
* Navigation container class.
* @class Navigation
* @extends Component
*/
class Navigation extends Component {
/**
* Property types.
* @property {Object} propTypes Property types.
* @static
*/
static propTypes = {
getNavigation: PropTypes.func.isRequired,
pathname: PropTypes.string.isRequired,
items: PropTypes.arrayOf(
PropTypes.shape({
title: PropTypes.string,
url: PropTypes.string,
}),
).isRequired,
lang: PropTypes.string.isRequired,
};

static defaultProps = {
token: null,
};

/**
* Constructor
* @method constructor
* @param {Object} props Component properties
* @constructs Navigation
*/
constructor(props) {
super(props);
this.toggleMobileMenu = this.toggleMobileMenu.bind(this);
this.closeMobileMenu = this.closeMobileMenu.bind(this);
this.state = {
isMobileMenuOpen: false,
};
}
const Navigation = (props) => {
const intl = useIntl();
const dispatch = useDispatch();
const { pathname, type } = props;
const [isMobileMenuOpen, setisMobileMenuOpen] = useState(false);
const token = useSelector((state) => state.userSession.token, shallowEqual);
const items = useSelector((state) => state.navigation.items, shallowEqual);
const lang = useSelector((state) => state.intl.locale);

componentDidMount() {
useEffect(() => {
const { settings } = config;
if (!hasApiExpander('navigation', getBaseUrl(this.props.pathname))) {
this.props.getNavigation(
getBaseUrl(this.props.pathname),
settings.navDepth,
);
if (!hasApiExpander('navigation', getBaseUrl(pathname))) {
dispatch(getNavigation(getBaseUrl(pathname), settings.navDepth));
}
}
}, [pathname, token, dispatch]);

/**
* Component will receive props
* @method componentWillReceiveProps
* @param {Object} nextProps Next properties
* @returns {undefined}
*/
UNSAFE_componentWillReceiveProps(nextProps) {
const { settings } = config;
if (
nextProps.pathname !== this.props.pathname ||
nextProps.token !== this.props.token
) {
if (!hasApiExpander('navigation', getBaseUrl(this.props.pathname))) {
this.props.getNavigation(
getBaseUrl(nextProps.pathname),
settings.navDepth,
);
}
}
}

/**
* Toggle mobile menu's open state
* @method toggleMobileMenu
* @returns {undefined}
*/
toggleMobileMenu() {
this.setState({ isMobileMenuOpen: !this.state.isMobileMenuOpen });
}
const toggleMobileMenu = () => {
setisMobileMenuOpen(!isMobileMenuOpen);
};

/**
* Close mobile menu
* @method closeMobileMenu
* @returns {undefined}
*/
closeMobileMenu() {
if (!this.state.isMobileMenuOpen) {
const closeMobileMenu = () => {
if (!isMobileMenuOpen) {
return;
}
this.setState({ isMobileMenuOpen: false });
}
setisMobileMenuOpen(false);
};

/**
* Render method.
* @method render
* @returns {string} Markup for the component.
*/
render() {
return (
<nav className="navigation" id="navigation" aria-label="navigation">
<div className="hamburger-wrapper mobile tablet only">
<button
className={cx('hamburger hamburger--spin', {
'is-active': this.state.isMobileMenuOpen,
})}
aria-label={
this.state.isMobileMenuOpen
? this.props.intl.formatMessage(messages.closeMobileMenu, {
type: this.props.type,
})
: this.props.intl.formatMessage(messages.openMobileMenu, {
type: this.props.type,
})
}
title={
this.state.isMobileMenuOpen
? this.props.intl.formatMessage(messages.closeMobileMenu, {
type: this.props.type,
})
: this.props.intl.formatMessage(messages.openMobileMenu, {
type: this.props.type,
})
}
type="button"
onClick={this.toggleMobileMenu}
>
<span className="hamburger-box">
<span className="hamburger-inner" />
</span>
</button>
</div>
<Menu
stackable
pointing
secondary
className="computer large screen widescreen only"
onClick={this.closeMobileMenu}
return (
<nav className="navigation" id="navigation" aria-label="navigation">
<div className="hamburger-wrapper mobile tablet only">
<button
className={cx('hamburger hamburger--spin', {
'is-active': isMobileMenuOpen,
})}
aria-label={
isMobileMenuOpen
? intl.formatMessage(messages.closeMobileMenu, {
type: type,
})
: intl.formatMessage(messages.openMobileMenu, {
type: type,
})
}
title={
isMobileMenuOpen
? intl.formatMessage(messages.closeMobileMenu, {
type: type,
})
: intl.formatMessage(messages.openMobileMenu, {
type: type,
})
}
type="button"
onClick={toggleMobileMenu}
>
<NavItems items={this.props.items} lang={this.props.lang} />
</Menu>
<CSSTransition
in={this.state.isMobileMenuOpen}
timeout={500}
classNames="mobile-menu"
unmountOnExit
>
<div key="mobile-menu-key" className="mobile-menu">
<BodyClass className="has-mobile-menu-open" />
<div className="mobile-menu-nav">
<Menu stackable pointing secondary onClick={this.closeMobileMenu}>
<NavItems items={this.props.items} lang={this.props.lang} />
</Menu>
</div>
<span className="hamburger-box">
<span className="hamburger-inner" />
</span>
</button>
</div>
<Menu
stackable
pointing
secondary
className="computer large screen widescreen only"
onClick={closeMobileMenu}
>
<NavItems items={items} lang={lang} />
</Menu>
<CSSTransition
in={isMobileMenuOpen}
timeout={500}
classNames="mobile-menu"
unmountOnExit
>
<div key="mobile-menu-key" className="mobile-menu">
<BodyClass className="has-mobile-menu-open" />
<div className="mobile-menu-nav">
<Menu stackable pointing secondary onClick={closeMobileMenu}>
<NavItems items={items} lang={lang} />
</Menu>
</div>
</CSSTransition>
</nav>
);
}
}
</div>
</CSSTransition>
</nav>
);
};

Navigation.propTypes = {
pathname: PropTypes.string.isRequired,
};

export default compose(
injectIntl,
connect(
(state) => ({
token: state.userSession.token,
items: state.navigation.items,
lang: state.intl.locale,
}),
{ getNavigation },
),
)(Navigation);
export default Navigation;

0 comments on commit bed71f5

Please sign in to comment.