diff --git a/src/components/ShowContextMenuContext.js b/src/components/ShowContextMenuContext.js index df522dec8f10..fff233162d74 100644 --- a/src/components/ShowContextMenuContext.js +++ b/src/components/ShowContextMenuContext.js @@ -2,6 +2,7 @@ import React from 'react'; import * as ReportActionContextMenu from '../pages/home/report/ContextMenu/ReportActionContextMenu'; import * as ContextMenuActions from '../pages/home/report/ContextMenu/ContextMenuActions'; import * as DeviceCapabilities from '../libs/DeviceCapabilities'; +import * as ReportUtils from '../libs/ReportUtils'; const ShowContextMenuContext = React.createContext({ anchor: null, @@ -32,7 +33,8 @@ function showContextMenuForReport(event, anchor, reportID, action, checkIfContex '', anchor, reportID, - action, + action.reportActionID, + ReportUtils.getOriginalReportID(reportID, action), '', checkIfContextMenuActive, checkIfContextMenuActive, diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js index 362ce23f72ba..3f4a5fe3ac4c 100755 --- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js +++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js @@ -1,7 +1,9 @@ -import React, {useState} from 'react'; +import React, {useMemo, useState, memo} from 'react'; import {InteractionManager, View} from 'react-native'; +import lodashGet from 'lodash/get'; import _ from 'underscore'; import PropTypes from 'prop-types'; +import {withOnyx} from 'react-native-onyx'; import getReportActionContextMenuStyles from '../../../../styles/getReportActionContextMenuStyles'; import ContextMenuItem from '../../../../components/ContextMenuItem'; import {propTypes as genericReportActionContextMenuPropTypes, defaultProps as GenericReportActionContextMenuDefaultProps} from './genericReportActionContextMenuPropTypes'; @@ -12,6 +14,7 @@ import withWindowDimensions, {windowDimensionsPropTypes} from '../../../../compo import {withBetas} from '../../../../components/OnyxProvider'; import * as Session from '../../../../libs/actions/Session'; import {hideContextMenu} from './ReportActionContextMenu'; +import ONYXKEYS from '../../../../ONYXKEYS'; const propTypes = { /** String representing the context menu type [LINK, REPORT_ACTION] which controls context menu choices */ @@ -44,18 +47,14 @@ const defaultProps = { function BaseReportActionContextMenu(props) { const [shouldKeepOpen, setShouldKeepOpen] = useState(false); const wrapperStyle = getReportActionContextMenuStyles(props.isMini, props.isSmallScreenWidth); + + const reportAction = useMemo(() => { + if (_.isEmpty(props.reportActions) || props.reportActionID === '0') return {}; + return props.reportActions[props.reportActionID] || {}; + }, [props.reportActions, props.reportActionID]); + const shouldShowFilter = (contextAction) => - contextAction.shouldShow( - props.type, - props.reportAction, - props.isArchivedRoom, - props.betas, - props.anchor, - props.isChronosReport, - props.reportID, - props.isPinnedChat, - props.isUnreadChat, - ); + contextAction.shouldShow(props.type, reportAction, props.isArchivedRoom, props.betas, props.anchor, props.isChronosReport, props.reportID, props.isPinnedChat, props.isUnreadChat); /** * Checks if user is anonymous. If true and the action doesn't accept for anonymous user, hides the context menu and @@ -85,7 +84,7 @@ function BaseReportActionContextMenu(props) { {_.map(_.filter(ContextMenuActions, shouldShowFilter), (contextAction) => { const closePopup = !props.isMini; const payload = { - reportAction: props.reportAction, + reportAction, reportID: props.reportID, draftMessage: props.draftMessage, selection: props.selection, @@ -106,7 +105,7 @@ function BaseReportActionContextMenu(props) { return ( `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${originalReportID}`, + canEvict: false, + }, + }), +)( + memo(BaseReportActionContextMenu, (prevProps, nextProps) => { + const prevReportAction = lodashGet(prevProps.reportActions, prevProps.reportActionID, ''); + const nextReportAction = lodashGet(nextProps.reportActions, nextProps.reportActionID, ''); + + // We only want to re-render when the report action that is attached to is changed + if (prevReportAction !== nextReportAction) { + return false; + } + return _.isEqual(_.omit(prevProps, 'reportActions'), _.omit(nextProps, 'reportActions')); + }), +); diff --git a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js index 81858564b416..3633fb99fc32 100644 --- a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js +++ b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js @@ -21,7 +21,8 @@ class PopoverReportActionContextMenu extends React.Component { this.state = { reportID: '0', - reportAction: {}, + reportActionID: '0', + originalReportID: '0', selection: '', reportActionDraftMessage: '', isPopoverVisible: false, @@ -112,7 +113,7 @@ class PopoverReportActionContextMenu extends React.Component { * @return {Boolean} */ isActiveReportAction(actionID) { - return Boolean(actionID) && this.state.reportAction.reportActionID === actionID; + return Boolean(actionID) && this.state.reportActionID === actionID; } /** @@ -123,7 +124,8 @@ class PopoverReportActionContextMenu extends React.Component { * @param {String} [selection] - Copied content. * @param {Element} contextMenuAnchor - popoverAnchor * @param {String} reportID - Active Report Id - * @param {Object} reportAction - ReportAction for ContextMenu + * @param {Object} reportActionID - ReportAction for ContextMenu + * @param {String} originalReportID - The currrent Report Id of the reportAction * @param {String} draftMessage - ReportAction Draftmessage * @param {Function} [onShow] - Run a callback when Menu is shown * @param {Function} [onHide] - Run a callback when Menu is hidden @@ -138,7 +140,8 @@ class PopoverReportActionContextMenu extends React.Component { selection, contextMenuAnchor, reportID, - reportAction, + reportActionID, + originalReportID, draftMessage, onShow = () => {}, onHide = () => {}, @@ -170,7 +173,8 @@ class PopoverReportActionContextMenu extends React.Component { }, type, reportID, - reportAction, + reportActionID, + originalReportID, selection, isPopoverVisible: true, reportActionDraftMessage: draftMessage, @@ -216,7 +220,7 @@ class PopoverReportActionContextMenu extends React.Component { * After Popover hides, call the registered onPopoverHide & onPopoverHideActionCallback callback and reset it */ runAndResetOnPopoverHide() { - this.setState({reportID: '0', reportAction: {}}, () => { + this.setState({reportID: '0', reportActionID: '0', originalReportID: '0'}, () => { this.onPopoverHide = this.runAndResetCallback(this.onPopoverHide); this.onPopoverHideActionCallback = this.runAndResetCallback(this.onPopoverHideActionCallback); }); @@ -310,7 +314,7 @@ class PopoverReportActionContextMenu extends React.Component { isVisible type={this.state.type} reportID={this.state.reportID} - reportAction={this.state.reportAction} + reportActionID={this.state.reportActionID} draftMessage={this.state.reportActionDraftMessage} selection={this.state.selection} isArchivedRoom={this.state.isArchivedRoom} @@ -319,6 +323,7 @@ class PopoverReportActionContextMenu extends React.Component { isUnreadChat={this.state.isUnreadChat} anchor={this.contextMenuTargetNode} contentRef={this.contentRef} + originalReportID={this.state.originalReportID} /> {}) { * @param {String} [selection] - Copied content. * @param {Element} contextMenuAnchor - popoverAnchor * @param {String} reportID - Active Report Id - * @param {Object} reportAction - ReportAction for ContextMenu + * @param {String} reportActionID - ReportActionID for ContextMenu + * @param {String} originalReportID - The currrent Report Id of the reportAction * @param {String} draftMessage - ReportAction Draftmessage * @param {Function} [onShow=() => {}] - Run a callback when Menu is shown * @param {Function} [onHide=() => {}] - Run a callback when Menu is hidden @@ -54,7 +55,8 @@ function showContextMenu( selection, contextMenuAnchor, reportID = '0', - reportAction = {}, + reportActionID = '0', + originalReportID = '0', draftMessage = '', onShow = () => {}, onHide = () => {}, @@ -72,13 +74,15 @@ function showContextMenu( hideContextMenu(); contextMenuRef.current.runAndResetOnPopoverHide(); } + contextMenuRef.current.showContextMenu( type, event, selection, contextMenuAnchor, reportID, - reportAction, + reportActionID, + originalReportID, draftMessage, onShow, onHide, diff --git a/src/pages/home/report/ContextMenu/genericReportActionContextMenuPropTypes.js b/src/pages/home/report/ContextMenu/genericReportActionContextMenuPropTypes.js index f62873031c54..3d8667e44e62 100644 --- a/src/pages/home/report/ContextMenu/genericReportActionContextMenuPropTypes.js +++ b/src/pages/home/report/ContextMenu/genericReportActionContextMenuPropTypes.js @@ -1,12 +1,14 @@ import PropTypes from 'prop-types'; -import reportActionPropTypes from '../reportActionPropTypes'; const propTypes = { /** The ID of the report this report action is attached to. */ reportID: PropTypes.string.isRequired, - /** The report action this context menu is attached to. */ - reportAction: PropTypes.shape(reportActionPropTypes).isRequired, + /** The ID of the report action this context menu is attached to. */ + reportActionID: PropTypes.string.isRequired, + + /** The ID of the original report from which the given reportAction is first created. */ + originalReportID: PropTypes.string.isRequired, /** If true, this component will be a small, row-oriented menu that displays icons but not text. If false, this component will be a larger, column-oriented menu that displays icons alongside text in each row. */ diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 8425f78a3a10..ef4df360e2b9 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -223,7 +223,8 @@ function ReportActionItem(props) { selection, popoverAnchorRef, props.report.reportID, - props.action, + props.action.reportActionID, + originalReportID, props.draftMessage, () => {}, toggleContextMenuFromActiveReportAction, @@ -231,7 +232,7 @@ function ReportActionItem(props) { ReportUtils.chatIncludesChronos(originalReport), ); }, - [props.draftMessage, props.action, props.report.reportID, toggleContextMenuFromActiveReportAction, originalReport], + [props.draftMessage, props.action, props.report.reportID, toggleContextMenuFromActiveReportAction, originalReport, originalReportID], ); const toggleReaction = useCallback( @@ -561,8 +562,9 @@ function ReportActionItem(props) { {props.shouldDisplayNewMarker && }