From 23eb7703d071594286d06b4f5040b2ca765f063e Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Thu, 30 Apr 2026 20:47:56 +0530 Subject: [PATCH] Refactor: migrate convertToDisplayString to useCurrencyListActions hook (part 8) --- .../MoneyReportHeaderSecondaryActions.tsx | 5 ++++- .../MoneyReportHeaderSelectionDropdown.tsx | 4 +++- .../MoneyReportHeaderPrimaryAction/PayPrimaryAction.tsx | 4 +++- .../MoneyRequestReportPreview/PayActionButton.tsx | 4 +++- src/hooks/useSelectionModeReportActions.ts | 4 +++- src/libs/MoneyRequestReportUtils.ts | 3 ++- .../settings/Subscription/SubscriptionSettings/index.tsx | 4 +++- tests/unit/MoneyRequestReportButtonUtils.test.ts | 9 +++++---- 8 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/components/MoneyReportHeaderActions/MoneyReportHeaderSecondaryActions.tsx b/src/components/MoneyReportHeaderActions/MoneyReportHeaderSecondaryActions.tsx index c26042ffa5ff..ed4e970422bf 100644 --- a/src/components/MoneyReportHeaderActions/MoneyReportHeaderSecondaryActions.tsx +++ b/src/components/MoneyReportHeaderActions/MoneyReportHeaderSecondaryActions.tsx @@ -17,6 +17,7 @@ import type {PopoverMenuItem} from '@components/PopoverMenu'; import {useSearchStateContext} from '@components/Search/SearchContext'; import type {PaymentActionParams} from '@components/SettlementButton/types'; import useActiveAdminPolicies from '@hooks/useActiveAdminPolicies'; +import {useCurrencyListActions} from '@hooks/useCurrencyList'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useExpenseActions from '@hooks/useExpenseActions'; import useExportActions from '@hooks/useExportActions'; @@ -111,6 +112,8 @@ function MoneyReportHeaderSecondaryActionsInner({reportID, primaryAction, isRepo const activePolicy = usePolicy(activePolicyID); const lastWorkspaceNumber = useLastWorkspaceNumber(); + const {convertToDisplayString} = useCurrencyListActions(); + const {isBetaEnabled} = usePermissions(); const isASAPSubmitBetaEnabled = isBetaEnabled(CONST.BETAS.ASAP_SUBMIT); @@ -215,7 +218,7 @@ function MoneyReportHeaderSecondaryActionsInner({reportID, primaryAction, isRepo const shouldShowApproveButton = (canApproveIOU(moneyRequestReport, policy, reportMetadata, allTransactions) && !hasOnlyPendingTransactions) || isApprovedAnimationRunning; const isApproveDisabled = shouldShowApproveButton && !isAllowedToApproveExpenseReport(moneyRequestReport); - const totalAmount = getTotalAmountForIOUReportPreviewButton(moneyRequestReport, policy, CONST.REPORT.PRIMARY_ACTIONS.PAY, nonPendingDeleteTransactions); + const totalAmount = getTotalAmountForIOUReportPreviewButton(moneyRequestReport, policy, CONST.REPORT.PRIMARY_ACTIONS.PAY, nonPendingDeleteTransactions, convertToDisplayString); const paymentButtonOptions = usePaymentOptions({ currency: moneyRequestReport?.currency, diff --git a/src/components/MoneyReportHeaderActions/MoneyReportHeaderSelectionDropdown.tsx b/src/components/MoneyReportHeaderActions/MoneyReportHeaderSelectionDropdown.tsx index f56d8fcecc17..6cd1ad61920b 100644 --- a/src/components/MoneyReportHeaderActions/MoneyReportHeaderSelectionDropdown.tsx +++ b/src/components/MoneyReportHeaderActions/MoneyReportHeaderSelectionDropdown.tsx @@ -20,6 +20,7 @@ import {useSearchActionsContext, useSearchStateContext} from '@components/Search import type {PaymentActionParams} from '@components/SettlementButton/types'; import useActiveAdminPolicies from '@hooks/useActiveAdminPolicies'; import useConfirmModal from '@hooks/useConfirmModal'; +import {useCurrencyListActions} from '@hooks/useCurrencyList'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useExportActions from '@hooks/useExportActions'; import useLastWorkspaceNumber from '@hooks/useLastWorkspaceNumber'; @@ -80,6 +81,7 @@ function MoneyReportHeaderSelectionDropdown({reportID, primaryAction, isReportIn const isBulkSubmitApprovePayBetaEnabled = isBetaEnabled(CONST.BETAS.BULK_SUBMIT_APPROVE_PAY); const activeAdminPolicies = useActiveAdminPolicies(); const lastWorkspaceNumber = useLastWorkspaceNumber(); + const {convertToDisplayString} = useCurrencyListActions(); const {selectedTransactionIDs, currentSearchQueryJSON, currentSearchKey, currentSearchResults} = useSearchStateContext(); const {clearSelectedTransactions} = useSearchActionsContext(); @@ -213,7 +215,7 @@ function MoneyReportHeaderSelectionDropdown({reportID, primaryAction, isReportIn }; const canAllowSettlement = hasUpdatedTotal(moneyRequestReport, policy); - const totalAmount = getTotalAmountForIOUReportPreviewButton(moneyRequestReport, policy, CONST.REPORT.PRIMARY_ACTIONS.PAY, nonPendingDeleteTransactions); + const totalAmount = getTotalAmountForIOUReportPreviewButton(moneyRequestReport, policy, CONST.REPORT.PRIMARY_ACTIONS.PAY, nonPendingDeleteTransactions, convertToDisplayString); const canIOUBePaid = canIOUBePaidAction(moneyRequestReport, chatReport, policy, bankAccountList, undefined, false, undefined, invoiceReceiverPolicy); const onlyShowPayElsewhere = !canIOUBePaid && canIOUBePaidAction(moneyRequestReport, chatReport, policy, bankAccountList, undefined, true, undefined, invoiceReceiverPolicy); const isPayable = hasPayAction && canIOUBePaid; diff --git a/src/components/MoneyReportHeaderPrimaryAction/PayPrimaryAction.tsx b/src/components/MoneyReportHeaderPrimaryAction/PayPrimaryAction.tsx index 2dd47cf02318..49f167349866 100644 --- a/src/components/MoneyReportHeaderPrimaryAction/PayPrimaryAction.tsx +++ b/src/components/MoneyReportHeaderPrimaryAction/PayPrimaryAction.tsx @@ -6,6 +6,7 @@ import {usePaymentAnimationsContext} from '@components/PaymentAnimationsContext' import {useSearchStateContext} from '@components/Search/SearchContext'; import AnimatedSettlementButton from '@components/SettlementButton/AnimatedSettlementButton'; import type {PaymentActionParams} from '@components/SettlementButton/types'; +import {useCurrencyListActions} from '@hooks/useCurrencyList'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useLastWorkspaceNumber from '@hooks/useLastWorkspaceNumber'; import useLocalize from '@hooks/useLocalize'; @@ -62,6 +63,7 @@ function PayPrimaryAction({reportID, chatReportID}: PayPrimaryActionProps) { const invoiceReceiverPolicyID = chatReport?.invoiceReceiver && 'policyID' in chatReport.invoiceReceiver ? chatReport.invoiceReceiver.policyID : undefined; const [invoiceReceiverPolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${invoiceReceiverPolicyID}`); const existingB2BInvoiceReport = useParticipantsInvoiceReport(activePolicyID, CONST.REPORT.INVOICE_RECEIVER_TYPE.BUSINESS, chatReport?.policyID); + const {convertToDisplayString} = useCurrencyListActions(); const isInvoiceReport = isInvoiceReportUtil(moneyRequestReport); @@ -77,7 +79,7 @@ function PayPrimaryAction({reportID, chatReportID}: PayPrimaryActionProps) { const shouldShowApproveButton = (canApproveIOU(moneyRequestReport, policy, reportMetadata, transactions) && !hasOnlyPendingTransactions) || isApprovedAnimationRunning; const shouldDisableApproveButton = shouldShowApproveButton && !isAllowedToApproveExpenseReport(moneyRequestReport); const canAllowSettlement = hasUpdatedTotal(moneyRequestReport, policy); - const totalAmount = getTotalAmountForIOUReportPreviewButton(moneyRequestReport, policy, CONST.REPORT.PRIMARY_ACTIONS.PAY, nonPendingDeleteTransactions); + const totalAmount = getTotalAmountForIOUReportPreviewButton(moneyRequestReport, policy, CONST.REPORT.PRIMARY_ACTIONS.PAY, nonPendingDeleteTransactions, convertToDisplayString); const isAnyTransactionOnHold = hasHeldExpensesReportUtils(moneyRequestReport?.reportID); const {currentSearchQueryJSON, currentSearchKey, currentSearchResults} = useSearchStateContext(); diff --git a/src/components/ReportActionItem/MoneyRequestReportPreview/PayActionButton.tsx b/src/components/ReportActionItem/MoneyRequestReportPreview/PayActionButton.tsx index 64f208cf0348..cf4b79de9bba 100644 --- a/src/components/ReportActionItem/MoneyRequestReportPreview/PayActionButton.tsx +++ b/src/components/ReportActionItem/MoneyRequestReportPreview/PayActionButton.tsx @@ -5,6 +5,7 @@ import type {ValueOf} from 'type-fest'; import {useDelegateNoAccessActions, useDelegateNoAccessState} from '@components/DelegateNoAccessModalProvider'; import AnimatedSettlementButton from '@components/SettlementButton/AnimatedSettlementButton'; import type {PaymentActionParams} from '@components/SettlementButton/types'; +import {useCurrencyListActions} from '@hooks/useCurrencyList'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useLastWorkspaceNumber from '@hooks/useLastWorkspaceNumber'; import useLocalize from '@hooks/useLocalize'; @@ -63,6 +64,7 @@ function PayActionButton({ const {isDelegateAccessRestricted} = useDelegateNoAccessState(); const {showDelegateNoAccessModal} = useDelegateNoAccessActions(); const lastWorkspaceNumber = useLastWorkspaceNumber(); + const {convertToDisplayString} = useCurrencyListActions(); const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID); const activePolicy = usePolicy(activePolicyID); @@ -100,7 +102,7 @@ function PayActionButton({ const shouldShowOnlyPayElsewhere = !canIOUBePaid && onlyShowPayElsewhere; const canIOUBePaidAndApproved = canIOUBePaid; - const formattedAmount = getTotalAmountForIOUReportPreviewButton(iouReport, policy, reportPreviewAction, transactions); + const formattedAmount = getTotalAmountForIOUReportPreviewButton(iouReport, policy, reportPreviewAction, transactions, convertToDisplayString); const confirmApproval = () => { if (isDelegateAccessRestricted) { diff --git a/src/hooks/useSelectionModeReportActions.ts b/src/hooks/useSelectionModeReportActions.ts index 07eef2179d7f..d25db6cd55c7 100644 --- a/src/hooks/useSelectionModeReportActions.ts +++ b/src/hooks/useSelectionModeReportActions.ts @@ -47,6 +47,7 @@ import type * as OnyxTypes from '@src/types/onyx'; import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; import useActiveAdminPolicies from './useActiveAdminPolicies'; import useConfirmPendingRTERAndProceed from './useConfirmPendingRTERAndProceed'; +import {useCurrencyListActions} from './useCurrencyList'; import useCurrentUserPersonalDetails from './useCurrentUserPersonalDetails'; import useLastWorkspaceNumber from './useLastWorkspaceNumber'; import {useMemoizedLazyExpensifyIcons} from './useLazyAsset'; @@ -120,6 +121,7 @@ function useSelectionModeReportActions({ const existingB2BInvoiceReport = useParticipantsInvoiceReport(activePolicyID, CONST.REPORT.INVOICE_RECEIVER_TYPE.BUSINESS, chatReport?.policyID); const activeAdminPolicies = useActiveAdminPolicies(); const lastWorkspaceNumber = useLastWorkspaceNumber(); + const {convertToDisplayString} = useCurrencyListActions(); const isChatReportArchived = useReportIsArchived(chatReport?.reportID); @@ -173,7 +175,7 @@ function useSelectionModeReportActions({ const shouldDisableApproveButton = shouldShowApproveButton && !isAllowedToApproveExpenseReport(report); - const totalAmount = getTotalAmountForIOUReportPreviewButton(report, policy, CONST.REPORT.PRIMARY_ACTIONS.PAY, nonPendingDeleteTransactions); + const totalAmount = getTotalAmountForIOUReportPreviewButton(report, policy, CONST.REPORT.PRIMARY_ACTIONS.PAY, nonPendingDeleteTransactions, convertToDisplayString); // confirmPayment is declared below but used by usePaymentOptions; we use a ref to avoid a circular dependency. const confirmPaymentRef = useRef<(params: PaymentActionParams) => void>(() => {}); diff --git a/src/libs/MoneyRequestReportUtils.ts b/src/libs/MoneyRequestReportUtils.ts index 9aab7b890d8d..377c83451e05 100644 --- a/src/libs/MoneyRequestReportUtils.ts +++ b/src/libs/MoneyRequestReportUtils.ts @@ -1,9 +1,9 @@ import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import type {TransactionListItemType} from '@components/Search/SearchList/ListItem/types'; +import type {CurrencyListActionsContextType} from '@hooks/useCurrencyList'; import CONST from '@src/CONST'; import type {OriginalMessageIOU, Policy, Report, ReportAction, ReportLoadingState, Transaction} from '@src/types/onyx'; -import {convertToDisplayString} from './CurrencyUtils'; import {isPaidGroupPolicy} from './PolicyUtils'; import {getIOUActionForTransactionID, getOriginalMessage, isDeletedAction, isDeletedParentAction, isMoneyRequestAction} from './ReportActionsUtils'; import { @@ -159,6 +159,7 @@ const getTotalAmountForIOUReportPreviewButton = ( policy: OnyxEntry, reportPreviewAction: ValueOf, transactions: Transaction[], + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString'], ) => { // Determine whether the non-held amount is appropriate to display for the PAY button. const {nonHeldAmount, hasValidNonHeldAmount} = getNonHeldAndFullAmount(report, reportPreviewAction === CONST.REPORT.REPORT_PREVIEW_ACTIONS.PAY); diff --git a/src/pages/settings/Subscription/SubscriptionSettings/index.tsx b/src/pages/settings/Subscription/SubscriptionSettings/index.tsx index 1246929e355d..c85c778bd51b 100644 --- a/src/pages/settings/Subscription/SubscriptionSettings/index.tsx +++ b/src/pages/settings/Subscription/SubscriptionSettings/index.tsx @@ -15,6 +15,7 @@ import RenderHTML from '@components/RenderHTML'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; import Text from '@components/Text'; +import {useCurrencyListActions} from '@hooks/useCurrencyList'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useEnvironment from '@hooks/useEnvironment'; import useHasTeam2025Pricing from '@hooks/useHasTeam2025Pricing'; @@ -30,7 +31,7 @@ import useTheme from '@hooks/useTheme'; import useThemeIllustrations from '@hooks/useThemeIllustrations'; import useThemeStyles from '@hooks/useThemeStyles'; import {openLink} from '@libs/actions/Link'; -import {convertToDisplayString, convertToShortDisplayString} from '@libs/CurrencyUtils'; +import {convertToShortDisplayString} from '@libs/CurrencyUtils'; import {isPolicyAdmin} from '@libs/PolicyUtils'; import {getSubscriptionPrice, isSubscriptionTypeOfInvoicing, shouldUseSimplifiedCollectSubscriptionUI} from '@libs/SubscriptionUtils'; import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; @@ -48,6 +49,7 @@ import ROUTES from '@src/ROUTES'; function SubscriptionSettings() { const {translate} = useLocalize(); + const {convertToDisplayString} = useCurrencyListActions(); const icons = useMemoizedLazyExpensifyIcons(['Coins']); const styles = useThemeStyles(); const theme = useTheme(); diff --git a/tests/unit/MoneyRequestReportButtonUtils.test.ts b/tests/unit/MoneyRequestReportButtonUtils.test.ts index 743421f63c71..128c8ac50256 100644 --- a/tests/unit/MoneyRequestReportButtonUtils.test.ts +++ b/tests/unit/MoneyRequestReportButtonUtils.test.ts @@ -1,4 +1,5 @@ import Onyx from 'react-native-onyx'; +import {convertToDisplayString} from '@libs/CurrencyUtils'; import {getTotalAmountForIOUReportPreviewButton} from '@libs/MoneyRequestReportUtils'; import {hasOnlyNonReimbursableTransactions} from '@libs/ReportUtils'; import CONST from '@src/CONST'; @@ -45,15 +46,15 @@ describe('ReportButtonUtils', () => { }); it('returns total reimbursable spend for PAY & total value for other buttons', () => { - expect(getTotalAmountForIOUReportPreviewButton(mockReport, mockPolicy, CONST.REPORT.REPORT_PREVIEW_ACTIONS.PAY, [])).toBe(`$50.00`); - expect(getTotalAmountForIOUReportPreviewButton(mockReport, mockPolicy, CONST.REPORT.REPORT_PREVIEW_ACTIONS.APPROVE, [])).toBe(`$100.00`); - expect(getTotalAmountForIOUReportPreviewButton(mockReport, mockPolicy, CONST.REPORT.REPORT_PREVIEW_ACTIONS.SUBMIT, [])).toBe(`$100.00`); + expect(getTotalAmountForIOUReportPreviewButton(mockReport, mockPolicy, CONST.REPORT.REPORT_PREVIEW_ACTIONS.PAY, [], convertToDisplayString)).toBe(`$50.00`); + expect(getTotalAmountForIOUReportPreviewButton(mockReport, mockPolicy, CONST.REPORT.REPORT_PREVIEW_ACTIONS.APPROVE, [], convertToDisplayString)).toBe(`$100.00`); + expect(getTotalAmountForIOUReportPreviewButton(mockReport, mockPolicy, CONST.REPORT.REPORT_PREVIEW_ACTIONS.SUBMIT, [], convertToDisplayString)).toBe(`$100.00`); }); it('returns total display spend for PAY when report has only non-reimbursable transactions', () => { jest.mocked(hasOnlyNonReimbursableTransactions).mockReturnValueOnce(true); - expect(getTotalAmountForIOUReportPreviewButton(mockReport, mockPolicy, CONST.REPORT.REPORT_PREVIEW_ACTIONS.PAY, [])).toBe(`$100.00`); + expect(getTotalAmountForIOUReportPreviewButton(mockReport, mockPolicy, CONST.REPORT.REPORT_PREVIEW_ACTIONS.PAY, [], convertToDisplayString)).toBe(`$100.00`); }); }); });