Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Sidebar #4965

Merged
merged 13 commits into from
Sep 19, 2023
Merged
1 change: 1 addition & 0 deletions news/4964.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Refactor Sidebar component-@Tishasoumya-02
349 changes: 135 additions & 214 deletions src/components/manage/Sidebar/Sidebar.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
/**
* Sidebar component.
* @module components/manage/Sidebar/Sidebar
*/

import React, { Component, Fragment } from 'react';
import React, { useState, Fragment, useCallback } from 'react';
import PropTypes from 'prop-types';
import { Button, Tab } from 'semantic-ui-react';
import { connect } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';
import { compose } from 'redux';
import { withCookies } from 'react-cookie';
import { defineMessages, injectIntl } from 'react-intl';
import { defineMessages, useIntl } from 'react-intl';
import cx from 'classnames';
import { BodyClass, getCookieOptions } from '@plone/volto/helpers';
import { Icon } from '@plone/volto/components';
Expand Down Expand Up @@ -41,101 +36,47 @@ const messages = defineMessages({
},
});

/**
* Sidebar container class.
* @class Sidebar
* @extends Component
*/
class Sidebar extends Component {
/**
* Property types.
* @property {Object} propTypes Property types.
* @static
*/
static propTypes = {
documentTab: PropTypes.bool,
blockTab: PropTypes.bool,
settingsTab: PropTypes.bool,
};

/**
* Default properties.
* @property {Object} defaultProps Default properties.
* @static
*/
static defaultProps = {
documentTab: true,
blockTab: true,
settingsTab: false,
};
const Sidebar = (props) => {
const dispatch = useDispatch();
const intl = useIntl();
const { cookies, content, documentTab, blockTab, settingsTab } = props;
const [expanded, setExpanded] = useState(
cookies.get('sidebar_expanded') !== 'false',
);
const [size] = useState(0);
const [showFull, setshowFull] = useState(true);

/**
* Constructor
* @method constructor
* @param {Object} props Component properties
* @constructs Sidebar
*/
constructor(props) {
super(props);
const { cookies } = props;
this.onToggleExpanded = this.onToggleExpanded.bind(this);
this.onToggleFullSize = this.onToggleFullSize.bind(this);
this.onTabChange = this.onTabChange.bind(this);
this.state = {
expanded: cookies.get('sidebar_expanded') !== 'false',
size: 0,
showFull: true,
showFullToolbarExpanded: true,
};
}
const tab = useSelector((state) => state.sidebar.tab);
const toolbarExpanded = useSelector((state) => state.toolbar.expanded);
const type = useSelector((state) => state.schema?.schema?.title);

/**
* On toggle expanded handler
* also reset sidebar since this has mimized it
* @method onToggleExpanded
* @returns {undefined}
*/
onToggleExpanded() {
const { cookies } = this.props;
cookies.set('sidebar_expanded', !this.state.expanded, getCookieOptions());
this.setState({
expanded: !this.state.expanded,
});
this.resetFullSizeSidebar();
}
const onToggleExpanded = () => {
cookies.set('sidebar_expanded', !expanded, getCookieOptions());
setExpanded(!expanded);
resetFullSizeSidebar();
};

/**
* Remove fullsize classes
* Reset state
*/
resetFullSizeSidebar() {
if (!this.state.expanded) {
const resetFullSizeSidebar = useCallback(() => {
if (!expanded) {
const currentResizer = document.querySelector('#sidebar');
const sidebarContainer = currentResizer.getElementsByClassName(
'sidebar-container',
)[0];
sidebarContainer.classList.remove('full-size');
sidebarContainer.classList.remove('no-toolbar');

this.setState({
showFull: true,
});
setshowFull(true);
}
}
}, [expanded]);

/**
* Set width of sibar to 100% minus the width of the toolbar or reset to
* initial size, by adding css classes
*/
onToggleFullSize() {
const onToggleFullSize = useCallback(() => {
const currentResizer = document.querySelector('#sidebar');
const sidebarContainer = currentResizer.getElementsByClassName(
'sidebar-container',
)[0];

if (this.state.showFull) {
if (showFull) {
sidebarContainer.classList.add('full-size');
if (!this.props.toolbarExpanded) {
if (!toolbarExpanded) {
sidebarContainer.classList.add('no-toolbar');
} else {
sidebarContainer.classList.remove('no-toolbar');
Expand All @@ -144,139 +85,119 @@ class Sidebar extends Component {
sidebarContainer.classList.remove('full-size');
sidebarContainer.classList.remove('no-toolbar');
}
setshowFull(!showFull);
}, [showFull, toolbarExpanded]);

this.setState((prevState) => ({
showFull: !prevState.showFull,
}));
}

/**
* On tab change
* @method onTabChange
* @param {Object} event Event object
* @param {Object} data Data object
* @returns {undefined}
*/
onTabChange(event, data) {
const onTabChange = (event, data) => {
event.nativeEvent.stopImmediatePropagation();
this.props.setSidebarTab(data.activeIndex);
}

/**
* Render method.
* @method render
* @returns {string} Markup for the component.
*/
render() {
const { expanded } = this.state;
dispatch(setSidebarTab(data.activeIndex));
};

return (
<Fragment>
<BodyClass
className={expanded ? 'has-sidebar' : 'has-sidebar-collapsed'}
return (
<Fragment>
<BodyClass
className={expanded ? 'has-sidebar' : 'has-sidebar-collapsed'}
/>
<div
className={cx('sidebar-container', { collapsed: !expanded })}
style={size > 0 ? { width: size } : null}
>
<Button
aria-label={
expanded
? intl.formatMessage(messages.shrinkSidebar)
: intl.formatMessage(messages.expandSidebar)
}
className={
content && content.review_state
? `${content.review_state} trigger`
: 'trigger'
}
onClick={onToggleExpanded}
/>
<div
className={cx('sidebar-container', { collapsed: !expanded })}
style={this.state.size > 0 ? { width: this.state.size } : null}
<Button
className="full-size-sidenav-btn"
onClick={onToggleFullSize}
aria-label="full-screen-sidenav"
>
<Button
aria-label={
expanded
? this.props.intl.formatMessage(messages.shrinkSidebar)
: this.props.intl.formatMessage(messages.expandSidebar)
}
className={
this.props.content && this.props.content.review_state
? `${this.props.content.review_state} trigger`
: 'trigger'
}
onClick={this.onToggleExpanded}
<Icon
className="full-size-icon"
name={showFull ? expandSVG : collapseSVG}
/>
<Button
className="full-size-sidenav-btn"
onClick={this.onToggleFullSize}
aria-label="full-screen-sidenav"
>
<Icon
className="full-size-icon"
name={this.state.showFull ? expandSVG : collapseSVG}
/>
</Button>
<Tab
menu={{
secondary: true,
pointing: true,
attached: true,
tabular: true,
className: 'formtabs',
}}
className="tabs-wrapper"
renderActiveOnly={false}
activeIndex={this.props.tab}
onTabChange={this.onTabChange}
panes={[
!!this.props.documentTab && {
menuItem:
this.props.type ||
this.props.intl.formatMessage(messages.document),
pane: (
<Tab.Pane
key="metadata"
className="tab-wrapper"
id="sidebar-metadata"
</Button>
<Tab
menu={{
secondary: true,
pointing: true,
attached: true,
tabular: true,
className: 'formtabs',
}}
className="tabs-wrapper"
renderActiveOnly={false}
activeIndex={tab}
onTabChange={onTabChange}
panes={[
!!documentTab && {
menuItem: type || intl.formatMessage(messages.document),
pane: (
<Tab.Pane
key="metadata"
className="tab-wrapper"
id="sidebar-metadata"
/>
),
},
!!blockTab && {
menuItem: intl.formatMessage(messages.block),
pane: (
<Tab.Pane
key="properties"
className="tab-wrapper"
id="sidebar-properties"
>
<Icon
className="tab-forbidden"
name={forbiddenSVG}
size="48px"
/>
),
},
!!this.props.blockTab && {
menuItem: this.props.intl.formatMessage(messages.block),
pane: (
<Tab.Pane
key="properties"
className="tab-wrapper"
id="sidebar-properties"
>
<Icon
className="tab-forbidden"
name={forbiddenSVG}
size="48px"
/>
</Tab.Pane>
),
},
!!this.props.settingsTab && {
menuItem: this.props.intl.formatMessage(messages.settings),
pane: (
<Tab.Pane
key="settings"
className="tab-wrapper"
id="sidebar-settings"
>
<Icon
className="tab-forbidden"
name={forbiddenSVG}
size="48px"
/>
</Tab.Pane>
),
},
].filter((tab) => tab)}
/>
</div>
<div className={this.state.expanded ? 'pusher expanded' : 'pusher'} />
</Fragment>
);
}
}
</Tab.Pane>
),
},
!!settingsTab && {
menuItem: intl.formatMessage(messages.settings),
pane: (
<Tab.Pane
key="settings"
className="tab-wrapper"
id="sidebar-settings"
>
<Icon
className="tab-forbidden"
name={forbiddenSVG}
size="48px"
/>
</Tab.Pane>
),
},
].filter((tab) => tab)}
/>
</div>
<div className={expanded ? 'pusher expanded' : 'pusher'} />
</Fragment>
);
};

Sidebar.propTypes = {
documentTab: PropTypes.bool,
blockTab: PropTypes.bool,
settingsTab: PropTypes.bool,
};

Sidebar.defaultProps = {
documentTab: true,
blockTab: true,
settingsTab: false,
};

export default compose(
injectIntl,
withCookies,
connect(
(state) => ({
tab: state.sidebar.tab,
toolbarExpanded: state.toolbar.expanded,
type: state.schema?.schema?.title,
}),
{ setSidebarTab },
),
)(Sidebar);
export default compose(withCookies)(Sidebar);