From 72c70b058d91a563fd3554223f972ea681cbbc34 Mon Sep 17 00:00:00 2001 From: tienifr Date: Thu, 29 Feb 2024 21:58:09 +0700 Subject: [PATCH] Hover menu is not dismissed after opening emoji picker --- src/components/Reactions/AddReactionBubble.tsx | 11 +++++++++-- .../BaseQuickEmojiReactions.tsx | 2 ++ .../Reactions/QuickEmojiReactions/types.ts | 5 +++++ .../ReportActionItemEmojiReactions.tsx | 7 +++++++ .../BaseReportActionContextMenu.tsx | 10 +++++++++- .../report/ContextMenu/ContextMenuActions.tsx | 18 ++++++++++++++---- .../PopoverReportActionContextMenu.tsx | 4 ++++ .../ContextMenu/ReportActionContextMenu.ts | 3 +++ src/pages/home/report/ReportActionItem.js | 13 +++++++++++-- 9 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/components/Reactions/AddReactionBubble.tsx b/src/components/Reactions/AddReactionBubble.tsx index 52751368a0ae..6b7aa12b742e 100644 --- a/src/components/Reactions/AddReactionBubble.tsx +++ b/src/components/Reactions/AddReactionBubble.tsx @@ -43,9 +43,12 @@ type AddReactionBubbleProps = { * ReportAction for EmojiPicker. */ reportAction: ReportAction; + + /** Function to update emoji picker state */ + setIsEmojiPickerActive?: (state: boolean) => void; }; -function AddReactionBubble({onSelectEmoji, reportAction, onPressOpenPicker, onWillShowPicker = () => {}, isContextMenu = false}: AddReactionBubbleProps) { +function AddReactionBubble({onSelectEmoji, reportAction, onPressOpenPicker, onWillShowPicker = () => {}, isContextMenu = false, setIsEmojiPickerActive}: AddReactionBubbleProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const ref = useRef(null); @@ -56,7 +59,9 @@ function AddReactionBubble({onSelectEmoji, reportAction, onPressOpenPicker, onWi const onPress = () => { const openPicker = (refParam?: PickerRefElement, anchorOrigin?: AnchorOrigin) => { EmojiPickerAction.showEmojiPicker( - () => {}, + () => { + setIsEmojiPickerActive?.(false); + }, (emojiCode, emojiObject) => { onSelectEmoji(emojiObject); }, @@ -68,12 +73,14 @@ function AddReactionBubble({onSelectEmoji, reportAction, onPressOpenPicker, onWi }; if (!EmojiPickerAction.emojiPickerRef.current?.isEmojiPickerVisible) { + setIsEmojiPickerActive?.(true); if (onPressOpenPicker) { onPressOpenPicker(openPicker); } else { openPicker(); } } else { + setIsEmojiPickerActive?.(false); EmojiPickerAction.emojiPickerRef.current.hideEmojiPicker(); } }; diff --git a/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.tsx b/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.tsx index 58973e90b9c4..87968fa38261 100644 --- a/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.tsx +++ b/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.tsx @@ -20,6 +20,7 @@ function BaseQuickEmojiReactions({ emojiReactions = {}, onPressOpenPicker = () => {}, onWillShowPicker = () => {}, + setIsEmojiPickerActive, }: BaseQuickEmojiReactionsProps) { const styles = useThemeStyles(); @@ -45,6 +46,7 @@ function BaseQuickEmojiReactions({ onWillShowPicker={onWillShowPicker} onSelectEmoji={(emoji) => onEmojiSelected(emoji, emojiReactions)} reportAction={reportAction} + setIsEmojiPickerActive={setIsEmojiPickerActive} /> ); diff --git a/src/components/Reactions/QuickEmojiReactions/types.ts b/src/components/Reactions/QuickEmojiReactions/types.ts index 9c17a87c56c0..7b6558364a55 100644 --- a/src/components/Reactions/QuickEmojiReactions/types.ts +++ b/src/components/Reactions/QuickEmojiReactions/types.ts @@ -32,6 +32,9 @@ type BaseReactionsProps = { /** Id of the ReportAction for EmojiPicker. */ reportActionID: string; + + /** Function to update emoji picker state */ + setIsEmojiPickerActive?: (state: boolean) => void; }; type BaseQuickEmojiReactionsOnyxProps = { @@ -53,6 +56,8 @@ type QuickEmojiReactionsProps = BaseReactionsProps & { * in which this component is rendered. */ closeContextMenu: (callback: CloseContextMenuCallback) => void; + + setIsEmojiPickerActive?: (state: boolean) => void; }; export type {BaseQuickEmojiReactionsProps, BaseQuickEmojiReactionsOnyxProps, QuickEmojiReactionsProps, OpenPickerCallback, CloseContextMenuCallback, PickerRefElement}; diff --git a/src/components/Reactions/ReportActionItemEmojiReactions.tsx b/src/components/Reactions/ReportActionItemEmojiReactions.tsx index ac05432a0555..7e95ab670b7e 100644 --- a/src/components/Reactions/ReportActionItemEmojiReactions.tsx +++ b/src/components/Reactions/ReportActionItemEmojiReactions.tsx @@ -37,6 +37,9 @@ type ReportActionItemEmojiReactionsProps = WithCurrentUserPersonalDetailsProps & /** We disable reacting with emojis on report actions that have errors */ shouldBlockReactions?: boolean; + + /** Function to update emoji picker state */ + setIsEmojiPickerActive?: (state: boolean) => void; }; type PopoverReactionListAnchors = Record; @@ -68,6 +71,8 @@ type FormattedReaction = { /** The type of action that's pending */ pendingAction?: PendingAction; + + setIsEmojiPickerActive?: (state: boolean) => void; }; function ReportActionItemEmojiReactions({ @@ -77,6 +82,7 @@ function ReportActionItemEmojiReactions({ emojiReactions = {}, shouldBlockReactions = false, preferredLocale = CONST.LOCALES.DEFAULT, + setIsEmojiPickerActive, }: ReportActionItemEmojiReactionsProps) { const styles = useThemeStyles(); const reactionListRef = useContext(ReactionListContext); @@ -166,6 +172,7 @@ function ReportActionItemEmojiReactions({ )} diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx index 52b62c2d15b3..4f6e0548eb72 100755 --- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx +++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx @@ -86,6 +86,9 @@ type BaseReportActionContextMenuProps = BaseReportActionContextMenuOnyxProps & { /** List of disabled actions */ disabledActions?: ContextMenuAction[]; + + /** Function to update emoji picker state */ + setIsEmojiPickerActive?: (state: boolean) => void; }; type MenuItemRefs = Record; @@ -108,6 +111,7 @@ function BaseReportActionContextMenu({ reportActions, checkIfContextMenuActive, disabledActions = [], + setIsEmojiPickerActive, }: BaseReportActionContextMenuProps) { const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); @@ -202,7 +206,10 @@ function BaseReportActionContextMenu({ originalReportID, draftMessage, checkIfContextMenuActive, - checkIfContextMenuActive, + () => { + checkIfContextMenuActive?.(); + setShouldKeepOpen(false); + }, ReportUtils.isArchivedRoom(originalReport), ReportUtils.chatIncludesChronos(originalReport), undefined, @@ -229,6 +236,7 @@ function BaseReportActionContextMenu({ openContextMenu: () => setShouldKeepOpen(true), interceptAnonymousUser, openOverflowMenu, + setIsEmojiPickerActive, }; if ('renderContent' in contextAction) { diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx index 51e6b25f1314..d20a75957c87 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx @@ -76,6 +76,7 @@ type ContextMenuActionPayload = { interceptAnonymousUser: (callback: () => void, isAnonymousAction?: boolean) => void; openOverflowMenu: (event: GestureResponderEvent | MouseEvent) => void; event?: GestureResponderEvent | MouseEvent | KeyboardEvent; + setIsEmojiPickerActive?: (state: boolean) => void; }; type OnPress = (closePopover: boolean, payload: ContextMenuActionPayload, selection?: string, reportID?: string, draftMessage?: string) => void; @@ -108,7 +109,7 @@ const ContextMenuActions: ContextMenuAction[] = [ isAnonymousAction: false, shouldShow: (type, reportAction): reportAction is ReportAction => type === CONST.CONTEXT_MENU_TYPES.REPORT_ACTION && !!reportAction && 'message' in reportAction && !ReportActionsUtils.isMessageDeleted(reportAction), - renderContent: (closePopover, {reportID, reportAction, close: closeManually, openContextMenu}) => { + renderContent: (closePopover, {reportID, reportAction, close: closeManually, openContextMenu, setIsEmojiPickerActive}) => { const isMini = !closePopover; const closeContextMenu = (onHideCallback?: () => void) => { @@ -125,6 +126,7 @@ const ContextMenuActions: ContextMenuAction[] = [ const toggleEmojiAndCloseMenu = (emoji: Emoji, existingReactions: OnyxEntry) => { Report.toggleEmojiReaction(reportID, reportAction, emoji, existingReactions); closeContextMenu(); + setIsEmojiPickerActive?.(false); }; if (isMini) { @@ -132,8 +134,14 @@ const ContextMenuActions: ContextMenuAction[] = [ { + openContextMenu(); + setIsEmojiPickerActive?.(true); + }} + onEmojiPickerClosed={() => { + closeContextMenu(); + setIsEmojiPickerActive?.(false); + }} reportActionID={reportAction?.reportActionID} reportAction={reportAction} /> @@ -147,6 +155,7 @@ const ContextMenuActions: ContextMenuAction[] = [ onEmojiSelected={toggleEmojiAndCloseMenu} reportActionID={reportAction?.reportActionID} reportAction={reportAction} + setIsEmojiPickerActive={setIsEmojiPickerActive} /> ); }, @@ -479,8 +488,9 @@ const ContextMenuActions: ContextMenuAction[] = [ textTranslateKey: 'reportActionContextMenu.menu', icon: Expensicons.ThreeDots, shouldShow: (type, reportAction, isArchivedRoom, betas, anchor, isChronosReport, reportID, isPinnedChat, isUnreadChat, isOffline, isMini) => isMini, - onPress: (closePopover, {openOverflowMenu, event}) => { + onPress: (closePopover, {openOverflowMenu, event, openContextMenu}) => { openOverflowMenu(event as GestureResponderEvent | MouseEvent); + openContextMenu(); }, getDescription: () => {}, }, diff --git a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx index 0b4154a15e80..2a86383ad84d 100644 --- a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx +++ b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx @@ -72,6 +72,7 @@ function PopoverReportActionContextMenu(_props: never, ref: ForwardedRef {}); const onPopoverHide = useRef(() => {}); + const onEmojiPickerToggle = useRef void)>(); const onCancelDeleteModal = useRef(() => {}); const onComfirmDeleteModal = useRef(() => {}); @@ -164,6 +165,7 @@ function PopoverReportActionContextMenu(_props: never, ref: ForwardedRef {}, ) => { const {pageX = 0, pageY = 0} = extractPointerEvent(event); contextMenuAnchorRef.current = contextMenuAnchor; @@ -177,6 +179,7 @@ function PopoverReportActionContextMenu(_props: never, ref: ForwardedRef((resolve) => { if (!pageX && !pageY && contextMenuAnchorRef.current) { @@ -329,6 +332,7 @@ function PopoverReportActionContextMenu(_props: never, ref: ForwardedRef void, ) => void; type ReportActionContextMenu = { @@ -115,6 +116,7 @@ function showContextMenu( isUnreadChat = false, disabledActions: ContextMenuAction[] = [], shouldCloseOnTarget = false, + setIsEmojiPickerActive = () => {}, ) { if (!contextMenuRef.current) { return; @@ -143,6 +145,7 @@ function showContextMenu( isUnreadChat, disabledActions, shouldCloseOnTarget, + setIsEmojiPickerActive, ); } diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index c0839cd76da9..97cedeaea9f2 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -144,6 +144,8 @@ function ReportActionItem(props) { const StyleUtils = useStyleUtils(); const personalDetails = usePersonalDetails() || CONST.EMPTY_OBJECT; const [isContextMenuActive, setIsContextMenuActive] = useState(() => ReportActionContextMenu.isActiveReportAction(props.action.reportActionID)); + const [isEmojiPickerActive, setIsEmojiPickerActive] = useState(); + const [isHidden, setIsHidden] = useState(false); const [moderationDecision, setModerationDecision] = useState(CONST.MODERATION.MODERATOR_DECISION_APPROVED); const reactionListRef = useContext(ReactionListContext); @@ -291,6 +293,11 @@ function ReportActionItem(props) { toggleContextMenuFromActiveReportAction, ReportUtils.isArchivedRoom(originalReport), ReportUtils.chatIncludesChronos(originalReport), + false, + false, + [], + false, + setIsEmojiPickerActive, ); }, [props.draftMessage, props.action, props.report.reportID, toggleContextMenuFromActiveReportAction, originalReport, originalReportID], @@ -569,6 +576,7 @@ function ReportActionItem(props) { toggleReaction(emoji); } }} + setIsEmojiPickerActive={setIsEmojiPickerActive} /> )} @@ -597,7 +605,7 @@ function ReportActionItem(props) { * @returns {Object} report action item */ const renderReportActionItem = (hovered, isWhisper, hasErrors) => { - const content = renderItemContent(hovered || isContextMenuActive, isWhisper, hasErrors); + const content = renderItemContent(hovered || isContextMenuActive || isEmojiPickerActive, isWhisper, hasErrors); if (!_.isUndefined(props.draftMessage)) { return {content}; @@ -785,8 +793,9 @@ function ReportActionItem(props) { draftMessage={props.draftMessage} isChronosReport={ReportUtils.chatIncludesChronos(originalReport)} checkIfContextMenuActive={toggleContextMenuFromActiveReportAction} + setIsEmojiPickerActive={setIsEmojiPickerActive} /> - + ReportActions.clearReportActionErrors(props.report.reportID, props.action)} pendingAction={