diff --git a/src/components/EmojiPicker/EmojiPicker.js b/src/components/EmojiPicker/EmojiPicker.js index ed1a349f4ea2..f87d08f3c02b 100644 --- a/src/components/EmojiPicker/EmojiPicker.js +++ b/src/components/EmojiPicker/EmojiPicker.js @@ -34,6 +34,7 @@ class EmojiPicker extends React.Component { this.onEmojiSelected = () => {}; this.state = { + reportAction: {}, isEmojiPickerVisible: false, // The horizontal and vertical position (relative to the window) where the emoji popover will display. @@ -100,6 +101,16 @@ class EmojiPicker extends React.Component { this.setState({isEmojiPickerVisible: false}); } + /** + * Whether Context Menu is active for the Report Action. + * + * @param {Number|String} actionID + * @return {Boolean} + */ + isActiveReportAction(actionID) { + return Boolean(actionID) && this.state.reportAction.reportActionID === actionID; + } + /** * Show the emoji picker menu. * @@ -108,8 +119,9 @@ class EmojiPicker extends React.Component { * @param {Element} emojiPopoverAnchor - Element to which Popover is anchored * @param {Object} [anchorOrigin=DEFAULT_ANCHOR_ORIGIN] - Anchor origin for Popover * @param {Function} [onWillShow=() => {}] - Run a callback when Popover will show + * @param {Object} reportAction - ReportAction for EmojiPicker */ - showEmojiPicker(onModalHide, onEmojiSelected, emojiPopoverAnchor, anchorOrigin, onWillShow = () => {}) { + showEmojiPicker(onModalHide, onEmojiSelected, emojiPopoverAnchor, anchorOrigin, onWillShow = () => {}, reportAction) { this.onModalHide = onModalHide; this.onEmojiSelected = onEmojiSelected; this.emojiPopoverAnchor = emojiPopoverAnchor; @@ -121,7 +133,7 @@ class EmojiPicker extends React.Component { this.measureEmojiPopoverAnchorPosition().then((emojiPopoverAnchorPosition) => { onWillShow(); - this.setState({isEmojiPickerVisible: true, emojiPopoverAnchorPosition, emojiPopoverAnchorOrigin: anchorOrigin || DEFAULT_ANCHOR_ORIGIN}); + this.setState({reportAction, isEmojiPickerVisible: true, emojiPopoverAnchorPosition, emojiPopoverAnchorOrigin: anchorOrigin || DEFAULT_ANCHOR_ORIGIN}); }); } diff --git a/src/components/Reactions/AddReactionBubble.js b/src/components/Reactions/AddReactionBubble.js index 7048bc9735cf..113968e8b9ad 100644 --- a/src/components/Reactions/AddReactionBubble.js +++ b/src/components/Reactions/AddReactionBubble.js @@ -35,6 +35,13 @@ const propTypes = { */ onSelectEmoji: PropTypes.func.isRequired, + /** + * ReportAction for EmojiPicker. + */ + reportAction: PropTypes.shape({ + reportActionID: PropTypes.string.isRequired, + }), + ...withLocalizePropTypes, }; @@ -42,6 +49,7 @@ const defaultProps = { isContextMenu: false, onWillShowPicker: () => {}, onPressOpenPicker: undefined, + reportAction: {}, }; function AddReactionBubble(props) { @@ -57,6 +65,7 @@ function AddReactionBubble(props) { refParam || ref.current, anchorOrigin, props.onWillShowPicker, + props.reportAction, ); }; diff --git a/src/components/Reactions/MiniQuickEmojiReactions.js b/src/components/Reactions/MiniQuickEmojiReactions.js index 91fa8817172c..5c77726d8070 100644 --- a/src/components/Reactions/MiniQuickEmojiReactions.js +++ b/src/components/Reactions/MiniQuickEmojiReactions.js @@ -28,6 +28,13 @@ const propTypes = { */ onEmojiPickerClosed: PropTypes.func, + /** + * ReportAction for EmojiPicker. + */ + reportAction: PropTypes.shape({ + reportActionID: PropTypes.string.isRequired, + }), + ...withLocalizePropTypes, preferredSkinTone: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), }; @@ -35,6 +42,7 @@ const propTypes = { const defaultProps = { onEmojiPickerClosed: () => {}, preferredSkinTone: CONST.EMOJI_DEFAULT_SKIN_TONE, + reportAction: {}, }; /** @@ -56,6 +64,9 @@ function MiniQuickEmojiReactions(props) { props.onEmojiSelected(emojiObject); }, ref.current, + undefined, + () => {}, + props.reportAction, ); }; diff --git a/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.js b/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.js index 7a0eb42a0ebd..e237083232d4 100644 --- a/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.js +++ b/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.js @@ -29,11 +29,17 @@ const baseQuickEmojiReactionsPropTypes = { * to actually open the emoji picker. */ onPressOpenPicker: PropTypes.func, + + /** + * ReportAction for EmojiPicker. + */ + reportAction: PropTypes.object, }; const baseQuickEmojiReactionsDefaultProps = { onWillShowPicker: () => {}, onPressOpenPicker: () => {}, + reportAction: {}, }; const propTypes = { @@ -68,6 +74,7 @@ function BaseQuickEmojiReactions(props) { onPressOpenPicker={props.onPressOpenPicker} onWillShowPicker={props.onWillShowPicker} onSelectEmoji={props.onEmojiSelected} + reportAction={props.reportAction} /> ); diff --git a/src/components/Reactions/ReportActionItemReactions.js b/src/components/Reactions/ReportActionItemReactions.js index a770032d3049..8a818e1c7bff 100644 --- a/src/components/Reactions/ReportActionItemReactions.js +++ b/src/components/Reactions/ReportActionItemReactions.js @@ -98,7 +98,12 @@ function ReportActionItemReactions(props) { ); })} - {reactionsWithCount.length > 0 && } + {reactionsWithCount.length > 0 && ( + + )} ); } diff --git a/src/libs/actions/EmojiPickerAction.js b/src/libs/actions/EmojiPickerAction.js index 6aba8e43bd23..9d4ef0b2e98c 100644 --- a/src/libs/actions/EmojiPickerAction.js +++ b/src/libs/actions/EmojiPickerAction.js @@ -10,13 +10,39 @@ const emojiPickerRef = React.createRef(); * @param {Element} emojiPopoverAnchor - Element on which EmojiPicker is anchored * @param {Object} [anchorOrigin] - Anchor origin for Popover * @param {Function} [onWillShow=() => {}] - Run a callback when Popover will show + * @param {Object} reportAction - ReportAction for EmojiPicker */ -function showEmojiPicker(onModalHide = () => {}, onEmojiSelected = () => {}, emojiPopoverAnchor, anchorOrigin = undefined, onWillShow = () => {}) { +function showEmojiPicker(onModalHide = () => {}, onEmojiSelected = () => {}, emojiPopoverAnchor, anchorOrigin = undefined, onWillShow = () => {}, reportAction = {}) { if (!emojiPickerRef.current) { return; } - emojiPickerRef.current.showEmojiPicker(onModalHide, onEmojiSelected, emojiPopoverAnchor, anchorOrigin, onWillShow); + emojiPickerRef.current.showEmojiPicker(onModalHide, onEmojiSelected, emojiPopoverAnchor, anchorOrigin, onWillShow, reportAction); } -export {emojiPickerRef, showEmojiPicker}; +/** + * Hide the Emoji Picker modal. + * + * @param {Boolean} isNavigating + */ +function hideEmojiPicker(isNavigating) { + if (!emojiPickerRef.current) { + return; + } + emojiPickerRef.current.hideEmojiPicker(isNavigating); +} + +/** + * Whether Emoji Picker is active for the Report Action. + * + * @param {Number|String} actionID + * @return {Boolean} + */ +function isActiveReportAction(actionID) { + if (!emojiPickerRef.current) { + return; + } + return emojiPickerRef.current.isActiveReportAction(actionID); +} + +export {emojiPickerRef, showEmojiPicker, hideEmojiPicker, isActiveReportAction}; diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 32ce2c244c78..d4b35ffd3a47 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -69,6 +69,7 @@ export default [ onEmojiSelected={onEmojiSelected} onPressOpenPicker={openContextMenu} onEmojiPickerClosed={closeContextMenu} + reportAction={reportAction} /> ); } @@ -78,6 +79,7 @@ export default [ key="BaseQuickEmojiReactions" closeContextMenu={closeContextMenu} onEmojiSelected={onEmojiSelected} + reportAction={reportAction} /> ); }, diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 802d0d9aa164..8db8a19dd84c 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -27,6 +27,7 @@ import * as DeviceCapabilities from '../../../libs/DeviceCapabilities'; import MiniReportActionContextMenu from './ContextMenu/MiniReportActionContextMenu'; import * as ReportActionContextMenu from './ContextMenu/ReportActionContextMenu'; import * as ContextMenuActions from './ContextMenu/ContextMenuActions'; +import * as EmojiPickerAction from '../../../libs/actions/EmojiPickerAction'; import {withBlockedFromConcierge, withNetwork, withPersonalDetails, withReportActionsDrafts} from '../../../components/OnyxProvider'; import RenameAction from '../../../components/ReportActionItem/RenameAction'; import InlineSystemMessage from '../../../components/InlineSystemMessage'; @@ -110,6 +111,22 @@ function ReportActionItem(props) { const popoverAnchorRef = useRef(); const downloadedPreviews = useRef([]); + useEffect( + () => () => { + // ReportActionContextMenu and EmojiPicker are global component, + // we use showContextMenu and showEmojiPicker to show them, + // so we should also hide them when the current component is destroyed + if (ReportActionContextMenu.isActiveReportAction(props.action.reportActionID)) { + ReportActionContextMenu.hideContextMenu(); + ReportActionContextMenu.hideDeleteModal(); + } + if (EmojiPickerAction.isActiveReportAction(props.action.reportActionID)) { + EmojiPickerAction.hideEmojiPicker(true); + } + }, + [props.action.reportActionID], + ); + const isDraftEmpty = !props.draftMessage; useEffect(() => { if (isDraftEmpty) {