From ccd1b3108922ee0d87c9fe1a0c89c08f40a578dd Mon Sep 17 00:00:00 2001
From: Nikhil Vats <nikvats5499@gmail.com>
Date: Wed, 4 Oct 2023 01:19:15 +0530
Subject: [PATCH 1/4] Fix popover position for payment buttons

---
 src/components/AddPaymentMethodMenu.js           | 12 ++++++++++++
 src/components/ButtonWithDropdownMenu.js         |  1 +
 src/components/KYCWall/BaseKYCWall.js            | 13 +++++++------
 src/components/KYCWall/kycWallPropTypes.js       | 16 ++++++++++++----
 src/components/MoneyReportHeader.js              |  4 ++++
 src/components/ReportActionItem/ReportPreview.js |  4 ++++
 src/components/SettlementButton.js               |  1 +
 .../settings/Wallet/WalletPage/BaseWalletPage.js |  5 ++++-
 8 files changed, 45 insertions(+), 11 deletions(-)

diff --git a/src/components/AddPaymentMethodMenu.js b/src/components/AddPaymentMethodMenu.js
index 399247a35676..2c3af95a3fad 100644
--- a/src/components/AddPaymentMethodMenu.js
+++ b/src/components/AddPaymentMethodMenu.js
@@ -1,3 +1,4 @@
+import _ from 'underscore';
 import React from 'react';
 import PropTypes from 'prop-types';
 import {withOnyx} from 'react-native-onyx';
@@ -24,6 +25,12 @@ const propTypes = {
         vertical: PropTypes.number,
     }),
 
+    /** Where the popover should be positioned relative to the anchor points. */
+    anchorAlignment: PropTypes.shape({
+        horizontal: PropTypes.oneOf(_.values(CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL)),
+        vertical: PropTypes.oneOf(_.values(CONST.MODAL.ANCHOR_ORIGIN_VERTICAL)),
+    }),
+
     /** List of betas available to current user */
     betas: PropTypes.arrayOf(PropTypes.string),
 
@@ -35,6 +42,10 @@ const propTypes = {
 
 const defaultProps = {
     anchorPosition: {},
+    anchorAlignment: {
+        horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT,
+        vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM,
+    },
     betas: [],
     anchorRef: () => {},
 };
@@ -45,6 +56,7 @@ function AddPaymentMethodMenu(props) {
             isVisible={props.isVisible}
             onClose={props.onClose}
             anchorPosition={props.anchorPosition}
+            anchorAlignment={props.anchorAlignment}
             anchorRef={props.anchorRef}
             onItemSelected={props.onClose}
             menuItems={[
diff --git a/src/components/ButtonWithDropdownMenu.js b/src/components/ButtonWithDropdownMenu.js
index a0a6e276bc28..04bc3f6fb54a 100644
--- a/src/components/ButtonWithDropdownMenu.js
+++ b/src/components/ButtonWithDropdownMenu.js
@@ -143,6 +143,7 @@ function ButtonWithDropdownMenu(props) {
             ) : (
                 <Button
                     success
+                    ref={props.buttonRef}
                     pressOnEnter={props.pressOnEnter}
                     isDisabled={props.isDisabled}
                     style={[styles.w100, ...props.style]}
diff --git a/src/components/KYCWall/BaseKYCWall.js b/src/components/KYCWall/BaseKYCWall.js
index ebf115c5de59..b00e32db63d3 100644
--- a/src/components/KYCWall/BaseKYCWall.js
+++ b/src/components/KYCWall/BaseKYCWall.js
@@ -62,9 +62,9 @@ class KYCWall extends React.Component {
      * @returns {Object}
      */
     getAnchorPosition(domRect) {
-        if (this.props.popoverPlacement === 'bottom') {
+        if (this.props.anchorAlignment.vertical === CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP) {
             return {
-                anchorPositionVertical: domRect.top + (domRect.height - 2),
+                anchorPositionVertical: domRect.top + domRect.height + CONST.MODAL.POPOVER_MENU_PADDING,
                 anchorPositionHorizontal: domRect.left + 20,
             };
         }
@@ -92,15 +92,15 @@ class KYCWall extends React.Component {
      * If they do have a valid payment method they are navigated to the "enable payments" route to complete KYC checks.
      * If they are already KYC'd we will continue whatever action is gated behind the KYC wall.
      *
-     * @param {Event} event
+     * @param {Event} _event
      * @param {String} iouPaymentType
      */
-    continue(event, iouPaymentType) {
+    continue(_event, iouPaymentType) {
         if (this.state.shouldShowAddPaymentMenu) {
             this.setState({shouldShowAddPaymentMenu: false});
             return;
         }
-        this.setState({transferBalanceButton: event.nativeEvent.target});
+        this.setState({transferBalanceButton: this.anchorRef.current});
         const isExpenseReport = ReportUtils.isExpenseReport(this.props.iouReport);
         const paymentCardList = this.props.fundList || {};
 
@@ -110,7 +110,7 @@ class KYCWall extends React.Component {
             (!isExpenseReport && !PaymentUtils.hasExpensifyPaymentMethod(paymentCardList, this.props.bankAccountList))
         ) {
             Log.info('[KYC Wallet] User does not have valid payment method');
-            const clickedElementLocation = getClickedTargetLocation(event.nativeEvent.target);
+            const clickedElementLocation = getClickedTargetLocation(this.anchorRef.current);
             const position = this.getAnchorPosition(clickedElementLocation);
             this.setPositionAddPaymentMenu(position);
             this.setState({
@@ -142,6 +142,7 @@ class KYCWall extends React.Component {
                         vertical: this.state.anchorPositionVertical,
                         horizontal: this.state.anchorPositionHorizontal,
                     }}
+                    anchorAlignment={this.props.anchorAlignment}
                     onItemSelected={(item) => {
                         this.setState({shouldShowAddPaymentMenu: false});
                         if (item === CONST.PAYMENT_METHODS.BANK_ACCOUNT) {
diff --git a/src/components/KYCWall/kycWallPropTypes.js b/src/components/KYCWall/kycWallPropTypes.js
index 482d61f7232a..6c117eb67f5b 100644
--- a/src/components/KYCWall/kycWallPropTypes.js
+++ b/src/components/KYCWall/kycWallPropTypes.js
@@ -1,9 +1,11 @@
+import _ from 'underscore';
 import PropTypes from 'prop-types';
 import userWalletPropTypes from '../../pages/EnablePayments/userWalletPropTypes';
 import bankAccountPropTypes from '../bankAccountPropTypes';
 import cardPropTypes from '../cardPropTypes';
 import iouReportPropTypes from '../../pages/iouReportPropTypes';
 import reimbursementAccountPropTypes from '../../pages/ReimbursementAccount/ReimbursementAccountDraftPropTypes';
+import CONST from '../../CONST';
 
 const propTypes = {
     /** Route for the Add Bank Account screen for a given navigation stack */
@@ -15,9 +17,6 @@ const propTypes = {
     /** Route for the KYC enable payments screen for a given navigation stack */
     enablePaymentsRoute: PropTypes.string.isRequired,
 
-    /** Where to place the popover */
-    popoverPlacement: PropTypes.string,
-
     /** Listen for window resize event on web and desktop */
     shouldListenForResize: PropTypes.bool,
 
@@ -44,11 +43,16 @@ const propTypes = {
 
     /** The reimbursement account linked to the Workspace */
     reimbursementAccount: reimbursementAccountPropTypes,
+
+    /** Where the popover should be positioned relative to the anchor points. */
+    anchorAlignment: PropTypes.shape({
+        horizontal: PropTypes.oneOf(_.values(CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL)),
+        vertical: PropTypes.oneOf(_.values(CONST.MODAL.ANCHOR_ORIGIN_VERTICAL)),
+    }),
 };
 
 const defaultProps = {
     userWallet: {},
-    popoverPlacement: 'top',
     shouldListenForResize: false,
     isDisabled: false,
     chatReportID: '',
@@ -58,6 +62,10 @@ const defaultProps = {
     reimbursementAccount: {},
     addDebitCardRoute: '',
     iouReport: {},
+    anchorAlignment: {
+        horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT,
+        vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM,
+    },
 };
 
 export {propTypes, defaultProps};
diff --git a/src/components/MoneyReportHeader.js b/src/components/MoneyReportHeader.js
index 6182226a5a78..1dfd866600cc 100644
--- a/src/components/MoneyReportHeader.js
+++ b/src/components/MoneyReportHeader.js
@@ -107,6 +107,10 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, report
                             shouldShowPaymentOptions
                             style={[styles.pv2]}
                             formattedAmount={formattedAmount}
+                            anchorAlignment={{
+                                horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT,
+                                vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP,
+                            }}
                         />
                     </View>
                 )}
diff --git a/src/components/ReportActionItem/ReportPreview.js b/src/components/ReportActionItem/ReportPreview.js
index a79cfd315b12..401e70e2e3ac 100644
--- a/src/components/ReportActionItem/ReportPreview.js
+++ b/src/components/ReportActionItem/ReportPreview.js
@@ -230,6 +230,10 @@ function ReportPreview(props) {
                                 enablePaymentsRoute={ROUTES.ENABLE_PAYMENTS}
                                 addBankAccountRoute={bankAccountRoute}
                                 style={[styles.requestPreviewBox]}
+                                anchorAlignment={{
+                                    horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT,
+                                    vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM,
+                                }}
                             />
                         )}
                     </View>
diff --git a/src/components/SettlementButton.js b/src/components/SettlementButton.js
index 088b296b343a..3bf8aa4c111d 100644
--- a/src/components/SettlementButton.js
+++ b/src/components/SettlementButton.js
@@ -201,6 +201,7 @@ function SettlementButton({
             isDisabled={isOffline}
             chatReportID={chatReportID}
             iouReport={iouReport}
+            anchorAlignment={anchorAlignment}
         >
             {(triggerKYCFlow, buttonRef) => (
                 <ButtonWithDropdownMenu
diff --git a/src/pages/settings/Wallet/WalletPage/BaseWalletPage.js b/src/pages/settings/Wallet/WalletPage/BaseWalletPage.js
index 74f0137fa26d..2b53f96df010 100644
--- a/src/pages/settings/Wallet/WalletPage/BaseWalletPage.js
+++ b/src/pages/settings/Wallet/WalletPage/BaseWalletPage.js
@@ -268,7 +268,10 @@ function BaseWalletPage(props) {
                                     enablePaymentsRoute={ROUTES.SETTINGS_ENABLE_PAYMENTS}
                                     addBankAccountRoute={ROUTES.SETTINGS_ADD_BANK_ACCOUNT}
                                     addDebitCardRoute={ROUTES.SETTINGS_ADD_DEBIT_CARD}
-                                    popoverPlacement="bottom"
+                                    anchorAlignment={{
+                                        horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT,
+                                        vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP,
+                                    }}
                                 >
                                     {(triggerKYCFlow, buttonRef) => (
                                         <MenuItem

From 46c304570be6ba6419e85b1312a752fc0dfbdd2e Mon Sep 17 00:00:00 2001
From: Nikhil Vats <nikvats5499@gmail.com>
Date: Thu, 5 Oct 2023 22:42:22 +0530
Subject: [PATCH 2/4] Add safety check for target element

---
 src/components/KYCWall/BaseKYCWall.js | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/components/KYCWall/BaseKYCWall.js b/src/components/KYCWall/BaseKYCWall.js
index b00e32db63d3..3aa1f11f5bca 100644
--- a/src/components/KYCWall/BaseKYCWall.js
+++ b/src/components/KYCWall/BaseKYCWall.js
@@ -92,15 +92,16 @@ class KYCWall extends React.Component {
      * If they do have a valid payment method they are navigated to the "enable payments" route to complete KYC checks.
      * If they are already KYC'd we will continue whatever action is gated behind the KYC wall.
      *
-     * @param {Event} _event
+     * @param {Event} event
      * @param {String} iouPaymentType
      */
-    continue(_event, iouPaymentType) {
+    continue(event, iouPaymentType) {
         if (this.state.shouldShowAddPaymentMenu) {
             this.setState({shouldShowAddPaymentMenu: false});
             return;
         }
-        this.setState({transferBalanceButton: this.anchorRef.current});
+        const targetElement = this.anchorRef.current || event.nativeEvent.target; // safety check - use target from event if anchorRef is null
+        this.setState({transferBalanceButton: targetElement});
         const isExpenseReport = ReportUtils.isExpenseReport(this.props.iouReport);
         const paymentCardList = this.props.fundList || {};
 
@@ -110,7 +111,7 @@ class KYCWall extends React.Component {
             (!isExpenseReport && !PaymentUtils.hasExpensifyPaymentMethod(paymentCardList, this.props.bankAccountList))
         ) {
             Log.info('[KYC Wallet] User does not have valid payment method');
-            const clickedElementLocation = getClickedTargetLocation(this.anchorRef.current);
+            const clickedElementLocation = getClickedTargetLocation(targetElement);
             const position = this.getAnchorPosition(clickedElementLocation);
             this.setPositionAddPaymentMenu(position);
             this.setState({

From 5b7f43960ac67835133483a2ecbeebea96c6f678 Mon Sep 17 00:00:00 2001
From: Nikhil Vats <nikvats5499@gmail.com>
Date: Thu, 5 Oct 2023 23:00:47 +0530
Subject: [PATCH 3/4] Improve comment

---
 src/components/KYCWall/BaseKYCWall.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/components/KYCWall/BaseKYCWall.js b/src/components/KYCWall/BaseKYCWall.js
index 3aa1f11f5bca..d2cdda809b82 100644
--- a/src/components/KYCWall/BaseKYCWall.js
+++ b/src/components/KYCWall/BaseKYCWall.js
@@ -100,7 +100,8 @@ class KYCWall extends React.Component {
             this.setState({shouldShowAddPaymentMenu: false});
             return;
         }
-        const targetElement = this.anchorRef.current || event.nativeEvent.target; // safety check - use target from event if anchorRef is null
+        // Use event target as fallback if anchorRef is null for safety
+        const targetElement = this.anchorRef.current || event.nativeEvent.target;
         this.setState({transferBalanceButton: targetElement});
         const isExpenseReport = ReportUtils.isExpenseReport(this.props.iouReport);
         const paymentCardList = this.props.fundList || {};

From 3ba03d1d8fcd281e7fc8974117b585b50af6c02e Mon Sep 17 00:00:00 2001
From: Nikhil Vats <nikvats5499@gmail.com>
Date: Thu, 5 Oct 2023 23:33:13 +0530
Subject: [PATCH 4/4] Add empty line before comment

---
 src/components/KYCWall/BaseKYCWall.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/components/KYCWall/BaseKYCWall.js b/src/components/KYCWall/BaseKYCWall.js
index d2cdda809b82..1c1552d55844 100644
--- a/src/components/KYCWall/BaseKYCWall.js
+++ b/src/components/KYCWall/BaseKYCWall.js
@@ -100,6 +100,7 @@ class KYCWall extends React.Component {
             this.setState({shouldShowAddPaymentMenu: false});
             return;
         }
+
         // Use event target as fallback if anchorRef is null for safety
         const targetElement = this.anchorRef.current || event.nativeEvent.target;
         this.setState({transferBalanceButton: targetElement});
