diff --git a/src/components/ButtonWithDropdownMenu/index.tsx b/src/components/ButtonWithDropdownMenu/index.tsx index 094c26a2b387..d4ee3e10914a 100644 --- a/src/components/ButtonWithDropdownMenu/index.tsx +++ b/src/components/ButtonWithDropdownMenu/index.tsx @@ -31,6 +31,8 @@ function ButtonWithDropdownMenu({ onPress, options, onOptionSelected, + onOptionsMenuShow, + onOptionsMenuHide, enterKeyEventListenerPriority = 0, wrapperStyle, }: ButtonWithDropdownMenuProps) { @@ -136,7 +138,11 @@ function ButtonWithDropdownMenu({ {(shouldAlwaysShowDropdownMenu || options.length > 1) && popoverAnchorPosition && ( setIsMenuVisible(false)} + onClose={() => { + setIsMenuVisible(false); + onOptionsMenuHide?.(); + }} + onModalShow={onOptionsMenuShow} onItemSelected={() => setIsMenuVisible(false)} anchorPosition={popoverAnchorPosition} anchorRef={caretButton} diff --git a/src/components/ButtonWithDropdownMenu/types.ts b/src/components/ButtonWithDropdownMenu/types.ts index baac60190ce5..f20729380b60 100644 --- a/src/components/ButtonWithDropdownMenu/types.ts +++ b/src/components/ButtonWithDropdownMenu/types.ts @@ -45,6 +45,12 @@ type ButtonWithDropdownMenuProps = { /** Callback to execute when a dropdown option is selected */ onOptionSelected?: (option: DropdownOption) => void; + /** Callback when the options popover is shown */ + onOptionsMenuShow?: () => void; + + /** Callback when the options popover is shown */ + onOptionsMenuHide?: () => void; + /** Call the onPress function on main button when Enter key is pressed */ pressOnEnter?: boolean; diff --git a/src/components/EmojiPicker/EmojiPicker.tsx b/src/components/EmojiPicker/EmojiPicker.tsx index a1b496838529..777d77a2411b 100644 --- a/src/components/EmojiPicker/EmojiPicker.tsx +++ b/src/components/EmojiPicker/EmojiPicker.tsx @@ -41,7 +41,7 @@ function EmojiPicker({viewportOffsetTop}: EmojiPickerProps, ref: ForwardedRef {}); + const onModalHide = useRef(() => {}); const onEmojiSelected = useRef(() => {}); const activeEmoji = useRef(); const emojiSearchInput = useRef(); @@ -112,13 +112,10 @@ function EmojiPicker({viewportOffsetTop}: EmojiPickerProps, ref: ForwardedRef { - if (isNavigating) { - onModalHide.current = () => {}; - } const currOnModalHide = onModalHide.current; onModalHide.current = () => { if (currOnModalHide) { - currOnModalHide(); + currOnModalHide(!!isNavigating); } // eslint-disable-next-line react-compiler/react-compiler emojiPopoverAnchorRef.current = null; diff --git a/src/components/PopoverMenu.tsx b/src/components/PopoverMenu.tsx index bcec153491c9..066b7dea3a03 100644 --- a/src/components/PopoverMenu.tsx +++ b/src/components/PopoverMenu.tsx @@ -42,6 +42,9 @@ type PopoverMenuProps = Partial & { /** Callback method fired when the user requests to close the modal */ onClose: () => void; + /** Callback method fired when the modal is shown */ + onModalShow?: () => void; + /** State that determines whether to display the modal or not */ isVisible: boolean; @@ -89,6 +92,7 @@ function PopoverMenu({ anchorPosition, anchorRef, onClose, + onModalShow, headerText, fromSidebarMediumScreen, anchorAlignment = { @@ -211,6 +215,7 @@ function PopoverMenu({ }} isVisible={isVisible} onModalHide={onModalHide} + onModalShow={onModalShow} animationIn={animationIn} animationOut={animationOut} animationInTiming={animationInTiming} diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index 91b1d30ab51a..0618437a936d 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -84,6 +84,12 @@ type ReportPreviewProps = ReportPreviewOnyxProps & { /** Callback for updating context menu active state, used for showing context menu */ checkIfContextMenuActive?: () => void; + /** Callback when the payment options popover is shown */ + onPaymentOptionsShow?: () => void; + + /** Callback when the payment options popover is closed */ + onPaymentOptionsHide?: () => void; + /** Whether a message is a whisper */ isWhisper?: boolean; @@ -106,6 +112,8 @@ function ReportPreview({ isHovered = false, isWhisper = false, checkIfContextMenuActive = () => {}, + onPaymentOptionsShow, + onPaymentOptionsHide, userWallet, }: ReportPreviewProps) { const theme = useTheme(); @@ -432,6 +440,8 @@ function ReportPreview({ chatReportID={chatReportID} iouReport={iouReport} onPress={confirmPayment} + onPaymentOptionsShow={onPaymentOptionsShow} + onPaymentOptionsHide={onPaymentOptionsHide} confirmApproval={confirmApproval} enablePaymentsRoute={ROUTES.ENABLE_PAYMENTS} addBankAccountRoute={bankAccountRoute} diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index 7c3c021a08eb..d1803f403469 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -43,6 +43,12 @@ type SettlementButtonProps = SettlementButtonOnyxProps & { /** Callback to execute when this button is pressed. Receives a single payment type argument. */ onPress: (paymentType?: PaymentMethodType) => void; + /** Callback when the payment options popover is shown */ + onPaymentOptionsShow?: () => void; + + /** Callback when the payment options popover is closed */ + onPaymentOptionsHide?: () => void; + /** The route to redirect if user does not have a payment method setup */ enablePaymentsRoute: EnablePaymentsRoute; @@ -140,6 +146,8 @@ function SettlementButton({ enterKeyEventListenerPriority = 0, confirmApproval, policy, + onPaymentOptionsShow, + onPaymentOptionsHide, }: SettlementButtonProps) { const {translate} = useLocalize(); const {isOffline} = useNetwork(); @@ -273,6 +281,8 @@ function SettlementButton({ {(triggerKYCFlow, buttonRef) => ( success + onOptionsMenuShow={onPaymentOptionsShow} + onOptionsMenuHide={onPaymentOptionsHide} buttonRef={buttonRef} shouldAlwaysShowDropdownMenu={isInvoiceReport} customText={isInvoiceReport ? translate('iou.settlePayment', {formattedAmount}) : undefined} diff --git a/src/libs/actions/EmojiPickerAction.ts b/src/libs/actions/EmojiPickerAction.ts index 787f105e4939..e6123733b0e8 100644 --- a/src/libs/actions/EmojiPickerAction.ts +++ b/src/libs/actions/EmojiPickerAction.ts @@ -16,7 +16,7 @@ type EmojiPopoverAnchor = MutableRefObject void; -type OnModalHideValue = () => void; +type OnModalHideValue = (isNavigating?: boolean) => void; type EmojiPickerRef = { showEmojiPicker: ( diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index 6ff163f6ec37..47b318fd61cb 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -482,7 +482,12 @@ function ReportActionCompose({ {DeviceCapabilities.canUseTouchScreen() && isMediumScreenWidth ? null : ( { + if (isNavigating) { + return; + } + focus(); + }} onEmojiSelected={(...args) => composerRef.current?.replaceSelectionWithText(...args)} emojiPickerID={report?.reportID} shiftVertical={emojiShiftVertical} diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index 0cd9329da9d6..8c876bb7e241 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -90,9 +90,6 @@ const getDraftMessage = (drafts: OnyxCollection, }; type ReportActionItemOnyxProps = { - /** Get modal status */ - modal: OnyxEntry; - /** IOU report for this action, if any */ iouReport: OnyxEntry; @@ -161,7 +158,6 @@ type ReportActionItemProps = { } & ReportActionItemOnyxProps; function ReportActionItem({ - modal, action, report, transactionThreadReport, @@ -195,6 +191,7 @@ function ReportActionItem({ const personalDetails = usePersonalDetails() || CONST.EMPTY_OBJECT; const [isContextMenuActive, setIsContextMenuActive] = useState(() => ReportActionContextMenu.isActiveReportAction(action.reportActionID)); const [isEmojiPickerActive, setIsEmojiPickerActive] = useState(); + const [isPaymentMethodPopoverActive, setIsPaymentMethodPopoverActive] = useState(); const [isHidden, setIsHidden] = useState(false); const [moderationDecision, setModerationDecision] = useState(CONST.MODERATION.MODERATOR_DECISION_APPROVED); @@ -566,6 +563,8 @@ function ReportActionItem({ isHovered={hovered} contextMenuAnchor={popoverAnchorRef.current} checkIfContextMenuActive={toggleContextMenuFromActiveReportAction} + onPaymentOptionsShow={() => setIsPaymentMethodPopoverActive(true)} + onPaymentOptionsHide={() => setIsPaymentMethodPopoverActive(false)} isWhisper={isWhisper} /> ); @@ -901,7 +900,6 @@ function ReportActionItem({ accessible > @@ -926,7 +924,7 @@ function ReportActionItem({ )} @@ -998,15 +996,11 @@ export default withOnyx({ `${ONYXKEYS.COLLECTION.TRANSACTION}${ReportActionsUtils.isMoneyRequestAction(action) ? ReportActionsUtils.getOriginalMessage(action)?.IOUTransactionID ?? -1 : -1}`, selector: (transaction: OnyxEntry) => transaction?.errorFields?.route ?? null, }, - modal: { - key: ONYXKEYS.MODAL, - }, })( memo(ReportActionItem, (prevProps, nextProps) => { const prevParentReportAction = prevProps.parentReportAction; const nextParentReportAction = nextProps.parentReportAction; return ( - prevProps.modal?.willAlertModalBecomeVisible === nextProps.modal?.willAlertModalBecomeVisible && prevProps.displayAsGroup === nextProps.displayAsGroup && prevProps.isMostRecentIOUReportAction === nextProps.isMostRecentIOUReportAction && prevProps.shouldDisplayNewMarker === nextProps.shouldDisplayNewMarker && @@ -1035,8 +1029,7 @@ export default withOnyx({ lodashIsEqual(prevProps.transactionThreadReport, nextProps.transactionThreadReport) && lodashIsEqual(prevProps.reportActions, nextProps.reportActions) && lodashIsEqual(prevProps.linkedTransactionRouteError, nextProps.linkedTransactionRouteError) && - lodashIsEqual(prevParentReportAction, nextParentReportAction) && - prevProps.modal?.willAlertModalBecomeVisible === nextProps.modal?.willAlertModalBecomeVisible + lodashIsEqual(prevParentReportAction, nextParentReportAction) ); }), );