diff --git a/src/components/ScreenWrapper/BaseScreenWrapper.js b/src/components/ScreenWrapper/BaseScreenWrapper.js index 56a0c30b2ecf..a80a013a1c66 100644 --- a/src/components/ScreenWrapper/BaseScreenWrapper.js +++ b/src/components/ScreenWrapper/BaseScreenWrapper.js @@ -44,23 +44,6 @@ class BaseScreenWrapper extends React.Component { }); } - /** - * We explicitly want to ignore if props.modal changes, and only want to rerender if - * any of the other props **used for the rendering output** is changed. - * @param {Object} nextProps - * @param {Object} nextState - * @returns {boolean} - */ - shouldComponentUpdate(nextProps, nextState) { - return this.state !== nextState - || this.props.children !== nextProps.children - || this.props.network.isOffline !== nextProps.network.isOffline - || this.props.includePaddingBottom !== nextProps.includePaddingBottom - || this.props.includePaddingTop !== nextProps.includePaddingTop - || this.props.isSmallScreenWidth !== nextProps.isSmallScreenWidth - || this.props.keyboardAvoidingViewBehavior !== nextProps.keyboardAvoidingViewBehavior; - } - componentWillUnmount() { if (this.unsubscribeEscapeKey) { this.unsubscribeEscapeKey(); diff --git a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js index 2f9eb5c4c2bc..6dfb496cb28f 100644 --- a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js +++ b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js @@ -1,31 +1,56 @@ import lodashGet from 'lodash/get'; +import _ from 'underscore'; import React, {Component} from 'react'; import {View} from 'react-native'; +import PropTypes from 'prop-types'; import styles from '../../../../styles/styles'; import SidebarLinks from '../SidebarLinks'; +import PopoverMenu from '../../../../components/PopoverMenu'; +import FloatingActionButton from '../../../../components/FloatingActionButton'; import ScreenWrapper from '../../../../components/ScreenWrapper'; import Navigation from '../../../../libs/Navigation/Navigation'; import ROUTES from '../../../../ROUTES'; import Timing from '../../../../libs/actions/Timing'; import CONST from '../../../../CONST'; +import * as Expensicons from '../../../../components/Icon/Expensicons'; +import Permissions from '../../../../libs/Permissions'; +import * as Policy from '../../../../libs/actions/Policy'; import Performance from '../../../../libs/Performance'; import * as Welcome from '../../../../libs/actions/Welcome'; +import {sidebarPropTypes, sidebarDefaultProps} from './sidebarPropTypes'; import withDrawerState from '../../../../components/withDrawerState'; -import withWindowDimensions, {windowDimensionsPropTypes} from '../../../../components/withWindowDimensions'; -import compose from '../../../../libs/compose'; -import sidebarPropTypes from './sidebarPropTypes'; const propTypes = { + + /** Callback function when the menu is shown */ + onShowCreateMenu: PropTypes.func, + + /** Callback function before the menu is hidden */ + onHideCreateMenu: PropTypes.func, + + /** reportID in the current navigation state */ + reportIDFromRoute: PropTypes.string, + ...sidebarPropTypes, - ...windowDimensionsPropTypes, +}; +const defaultProps = { + onHideCreateMenu: () => {}, + onShowCreateMenu: () => {}, + ...sidebarDefaultProps, }; class BaseSidebarScreen extends Component { constructor(props) { super(props); + this.hideCreateMenu = this.hideCreateMenu.bind(this); this.startTimer = this.startTimer.bind(this); this.navigateToSettings = this.navigateToSettings.bind(this); + this.showCreateMenu = this.showCreateMenu.bind(this); + + this.state = { + isCreateMenuActive: false, + }; } componentDidMount() { @@ -36,6 +61,16 @@ class BaseSidebarScreen extends Component { Welcome.show({routes, showCreateMenu: this.showCreateMenu}); } + /** + * Method called when we click the floating action button + */ + showCreateMenu() { + this.setState({ + isCreateMenuActive: true, + }); + this.props.onShowCreateMenu(); + } + /** * Method called when avatar is clicked */ @@ -43,6 +78,18 @@ class BaseSidebarScreen extends Component { Navigation.navigate(ROUTES.SETTINGS); } + /** + * Method called either when: + * Pressing the floating action button to open the CreateMenu modal + * Selecting an item on CreateMenu or closing it by clicking outside of the modal component + */ + hideCreateMenu() { + this.props.onHideCreateMenu(); + this.setState({ + isCreateMenuActive: false, + }); + } + /** * Method called when a pinned chat is selected. */ @@ -52,22 +99,89 @@ class BaseSidebarScreen extends Component { } render() { + // Workspaces are policies with type === 'free' + const workspaces = _.filter(this.props.allPolicies, policy => policy && policy.type === CONST.POLICY.TYPE.FREE); return ( {({insets}) => ( - - + + + + + Navigation.navigate(ROUTES.NEW_CHAT), + }, + { + icon: Expensicons.Users, + text: this.props.translate('sidebarScreen.newGroup'), + onSelected: () => Navigation.navigate(ROUTES.NEW_GROUP), + }, + ...(Permissions.canUsePolicyRooms(this.props.betas) && workspaces.length ? [ + { + icon: Expensicons.Hashtag, + text: this.props.translate('sidebarScreen.newRoom'), + onSelected: () => Navigation.navigate(ROUTES.WORKSPACE_NEW_ROOM), + }, + ] : []), + ...(Permissions.canUseIOUSend(this.props.betas) ? [ + { + icon: Expensicons.Send, + text: this.props.translate('iou.sendMoney'), + onSelected: () => Navigation.navigate(ROUTES.IOU_SEND), + }, + ] : []), + ...(Permissions.canUseIOU(this.props.betas) ? [ + { + icon: Expensicons.MoneyCircle, + text: this.props.translate('iou.requestMoney'), + onSelected: () => Navigation.navigate(ROUTES.IOU_REQUEST), + }, + ] : []), + ...(Permissions.canUseIOU(this.props.betas) ? [ + { + icon: Expensicons.Receipt, + text: this.props.translate('iou.splitBill'), + onSelected: () => Navigation.navigate(ROUTES.IOU_BILL), + }, + ] : []), + ...(!Policy.isAdminOfFreePolicy(this.props.allPolicies) ? [ + { + icon: Expensicons.NewWorkspace, + iconWidth: 46, + iconHeight: 40, + text: this.props.translate('workspace.new.newWorkspace'), + description: this.props.translate('workspace.new.getTheExpensifyCardAndMore'), + onSelected: () => Policy.createWorkspace(), + }, + ] : []), + ]} /> - + )} ); @@ -75,8 +189,6 @@ class BaseSidebarScreen extends Component { } BaseSidebarScreen.propTypes = propTypes; +BaseSidebarScreen.defaultProps = defaultProps; -export default compose( - withWindowDimensions, - withDrawerState, -)(BaseSidebarScreen); +export default withDrawerState(BaseSidebarScreen); diff --git a/src/pages/home/sidebar/SidebarScreen/PopoverModal.js b/src/pages/home/sidebar/SidebarScreen/PopoverModal.js index 6b62f5875dd2..e69de29bb2d1 100644 --- a/src/pages/home/sidebar/SidebarScreen/PopoverModal.js +++ b/src/pages/home/sidebar/SidebarScreen/PopoverModal.js @@ -1,170 +0,0 @@ -import React from 'react'; -import _ from 'underscore'; -import {withOnyx} from 'react-native-onyx'; -import PropTypes from 'prop-types'; -import styles from '../../../../styles/styles'; -import * as Expensicons from '../../../../components/Icon/Expensicons'; -import Navigation from '../../../../libs/Navigation/Navigation'; -import ROUTES from '../../../../ROUTES'; -import Permissions from '../../../../libs/Permissions'; -import * as Policy from '../../../../libs/actions/Policy'; -import PopoverMenu from '../../../../components/PopoverMenu'; -import CONST from '../../../../CONST'; -import FloatingActionButton from '../../../../components/FloatingActionButton'; -import compose from '../../../../libs/compose'; -import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize'; -import withWindowDimensions from '../../../../components/withWindowDimensions'; -import ONYXKEYS from '../../../../ONYXKEYS'; - -const propTypes = { - /* Callback function when the menu is shown */ - onShowCreateMenu: PropTypes.func, - - /* Callback function before the menu is hidden */ - onHideCreateMenu: PropTypes.func, - - /** The list of policies the user has access to. */ - allPolicies: PropTypes.shape({ - /** The policy name */ - name: PropTypes.string, - }), - - /* Beta features list */ - betas: PropTypes.arrayOf(PropTypes.string), - - ...withLocalizePropTypes, -}; -const defaultProps = { - onHideCreateMenu: () => {}, - onShowCreateMenu: () => {}, - allPolicies: {}, - betas: [], -}; - -/** - * Responsible for rendering the {@link PopoverMenu}, and the accompanying - * FAB that can open or close the menu. - */ -class PopoverModal extends React.Component { - constructor(props) { - super(props); - - this.showCreateMenu = this.showCreateMenu.bind(this); - this.hideCreateMenu = this.hideCreateMenu.bind(this); - - this.state = { - isCreateMenuActive: false, - }; - } - - /** - * Method called when we click the floating action button - */ - showCreateMenu() { - this.setState({ - isCreateMenuActive: true, - }); - this.props.onShowCreateMenu(); - } - - /** - * Method called either when: - * - Pressing the floating action button to open the CreateMenu modal - * - Selecting an item on CreateMenu or closing it by clicking outside of the modal component - */ - hideCreateMenu() { - this.props.onHideCreateMenu(); - this.setState({ - isCreateMenuActive: false, - }); - } - - render() { - // Workspaces are policies with type === 'free' - const workspaces = _.filter(this.props.allPolicies, policy => policy && policy.type === CONST.POLICY.TYPE.FREE); - - return ( - <> - Navigation.navigate(ROUTES.NEW_CHAT), - }, - { - icon: Expensicons.Users, - text: this.props.translate('sidebarScreen.newGroup'), - onSelected: () => Navigation.navigate(ROUTES.NEW_GROUP), - }, - ...(Permissions.canUsePolicyRooms(this.props.betas) && workspaces.length ? [ - { - icon: Expensicons.Hashtag, - text: this.props.translate('sidebarScreen.newRoom'), - onSelected: () => Navigation.navigate(ROUTES.WORKSPACE_NEW_ROOM), - }, - ] : []), - ...(Permissions.canUseIOUSend(this.props.betas) ? [ - { - icon: Expensicons.Send, - text: this.props.translate('iou.sendMoney'), - onSelected: () => Navigation.navigate(ROUTES.IOU_SEND), - }, - ] : []), - ...(Permissions.canUseIOU(this.props.betas) ? [ - { - icon: Expensicons.MoneyCircle, - text: this.props.translate('iou.requestMoney'), - onSelected: () => Navigation.navigate(ROUTES.IOU_REQUEST), - }, - ] : []), - ...(Permissions.canUseIOU(this.props.betas) ? [ - { - icon: Expensicons.Receipt, - text: this.props.translate('iou.splitBill'), - onSelected: () => Navigation.navigate(ROUTES.IOU_BILL), - }, - ] : []), - ...(!Policy.isAdminOfFreePolicy(this.props.allPolicies) ? [ - { - icon: Expensicons.NewWorkspace, - iconWidth: 46, - iconHeight: 40, - text: this.props.translate('workspace.new.newWorkspace'), - description: this.props.translate('workspace.new.getTheExpensifyCardAndMore'), - onSelected: () => Policy.createWorkspace(), - }, - ] : []), - ]} - /> - - - ); - } -} - -PopoverModal.propTypes = propTypes; -PopoverModal.defaultProps = defaultProps; - -export default compose( - withLocalize, - withWindowDimensions, - withOnyx({ - allPolicies: { - key: ONYXKEYS.COLLECTION.POLICY, - }, - betas: { - key: ONYXKEYS.BETAS, - }, - }), -)(PopoverModal); diff --git a/src/pages/home/sidebar/SidebarScreen/index.js b/src/pages/home/sidebar/SidebarScreen/index.js index 75b5e07e7150..584bcc49f8e4 100755 --- a/src/pages/home/sidebar/SidebarScreen/index.js +++ b/src/pages/home/sidebar/SidebarScreen/index.js @@ -1,41 +1,52 @@ import React from 'react'; -import sidebarPropTypes from './sidebarPropTypes'; +import {withOnyx} from 'react-native-onyx'; +import compose from '../../../../libs/compose'; +import withWindowDimensions from '../../../../components/withWindowDimensions'; +import withLocalize from '../../../../components/withLocalize'; +import ONYXKEYS from '../../../../ONYXKEYS'; +import {sidebarPropTypes, sidebarDefaultProps} from './sidebarPropTypes'; import BaseSidebarScreen from './BaseSidebarScreen'; -import PopoverModal from './PopoverModal'; const SidebarScreen = (props) => { - let popoverModal = null; + let baseSidebarScreen = null; /** * Method create event listener */ const createDragoverListener = () => { - document.addEventListener('dragover', popoverModal.hideCreateMenu); + document.addEventListener('dragover', baseSidebarScreen.hideCreateMenu); }; /** * Method remove event listener. */ const removeDragoverListener = () => { - document.removeEventListener('dragover', popoverModal.hideCreateMenu); + document.removeEventListener('dragover', baseSidebarScreen.hideCreateMenu); }; - return ( - <> - - popoverModal = el} - onShowCreateMenu={createDragoverListener} - onHideCreateMenu={removeDragoverListener} - /> - + baseSidebarScreen = el} + onShowCreateMenu={createDragoverListener} + onHideCreateMenu={removeDragoverListener} + // eslint-disable-next-line react/jsx-props-no-spreading + {...props} + /> ); }; SidebarScreen.propTypes = sidebarPropTypes; +SidebarScreen.defaultProps = sidebarDefaultProps; SidebarScreen.displayName = 'SidebarScreen'; -export default SidebarScreen; +export default compose( + withLocalize, + withWindowDimensions, + withOnyx({ + allPolicies: { + key: ONYXKEYS.COLLECTION.POLICY, + }, + betas: { + key: ONYXKEYS.BETAS, + }, + }), +)(SidebarScreen); diff --git a/src/pages/home/sidebar/SidebarScreen/index.native.js b/src/pages/home/sidebar/SidebarScreen/index.native.js index cbf0d5c085a0..e2cb2838efe8 100755 --- a/src/pages/home/sidebar/SidebarScreen/index.native.js +++ b/src/pages/home/sidebar/SidebarScreen/index.native.js @@ -1,19 +1,28 @@ import React from 'react'; -import sidebarPropTypes from './sidebarPropTypes'; +import {withOnyx} from 'react-native-onyx'; +import compose from '../../../../libs/compose'; +import withWindowDimensions from '../../../../components/withWindowDimensions'; +import withLocalize from '../../../../components/withLocalize'; +import ONYXKEYS from '../../../../ONYXKEYS'; +import {sidebarPropTypes, sidebarDefaultProps} from './sidebarPropTypes'; import BaseSidebarScreen from './BaseSidebarScreen'; -import PopoverModal from './PopoverModal'; -const SidebarScreen = props => ( - <> - - - -); +// eslint-disable-next-line react/jsx-props-no-spreading +const SidebarScreen = props => ; SidebarScreen.propTypes = sidebarPropTypes; +SidebarScreen.defaultProps = sidebarDefaultProps; SidebarScreen.displayName = 'SidebarScreen'; -export default SidebarScreen; +export default compose( + withLocalize, + withWindowDimensions, + withOnyx({ + allPolicies: { + key: ONYXKEYS.COLLECTION.POLICY, + }, + betas: { + key: ONYXKEYS.BETAS, + }, + }), +)(SidebarScreen); diff --git a/src/pages/home/sidebar/SidebarScreen/sidebarPropTypes.js b/src/pages/home/sidebar/SidebarScreen/sidebarPropTypes.js index 3affaa2d00be..996bba9d676b 100644 --- a/src/pages/home/sidebar/SidebarScreen/sidebarPropTypes.js +++ b/src/pages/home/sidebar/SidebarScreen/sidebarPropTypes.js @@ -1,8 +1,26 @@ import PropTypes from 'prop-types'; +import {windowDimensionsPropTypes} from '../../../../components/withWindowDimensions'; +import {withLocalizePropTypes} from '../../../../components/withLocalize'; const sidebarPropTypes = { - /** reportID in the current navigation state */ - reportIDFromRoute: PropTypes.string, + /** The list of policies the user has access to. */ + allPolicies: PropTypes.shape({ + /** The policy name */ + name: PropTypes.string, + }), + + /* Beta features list */ + betas: PropTypes.arrayOf(PropTypes.string), + + ...windowDimensionsPropTypes, + + ...withLocalizePropTypes, }; -export default sidebarPropTypes; + +const sidebarDefaultProps = { + allPolicies: {}, + betas: [], +}; + +export {sidebarPropTypes, sidebarDefaultProps};