From b8ae42b6c9d33dfaad8435cb4d6f4a06a9e80723 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Wed, 22 Apr 2026 17:35:56 +0700 Subject: [PATCH 1/6] Part 1: Ensure createDraftWorkspace callers fallback to localCurrencyCode before buildOptimisticDistanceRateCustomUnits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue #66580 step — move the localCurrencyCode fallback from buildOptimisticDistanceRateCustomUnits (which reads deprecated Onyx.connect variables) to the callers of createDraftWorkspace at the UI layer. - IOURequestStepParticipants.tsx: pass currentUserPersonalDetails.localCurrencyCode - WorkspaceConfirmationForTravelPage.tsx: fall back params.currency || localCurrencyCode - ReportUtils.ts (createDraftWorkspaceAndNavigateToConfirmationScreen): add currentUserLocalCurrency param and thread it into createDraftWorkspace - ReportUtils.ts (createDraftTransactionAndNavigateToParticipantSelector): add currentUserLocalCurrency to params type, forward it - Update all callers: ReportDetailsPage, ChatActionableButtons, IOURequestStepAccountant - Update all tests to pass currentUserLocalCurrency: '' (explicit placeholder) - Add unit test verifying explicit currency arg is used, not session user localCurrencyCode Co-Authored-By: Claude Opus 4.6 (1M context) --- src/libs/ReportUtils.ts | 16 ++++++++++++++-- src/pages/ReportDetailsPage.tsx | 3 +++ .../WorkspaceConfirmationForTravelPage.tsx | 2 +- .../actionContents/ChatActionableButtons.tsx | 1 + .../request/step/IOURequestStepAccountant.tsx | 14 +++++++++++--- .../step/IOURequestStepParticipants.tsx | 4 ++++ tests/actions/IOUTest.ts | 4 ++++ tests/actions/IOUTest/TrackExpenseTest.ts | 2 ++ tests/actions/PolicyTest.ts | 19 +++++++++++++++++++ tests/unit/ReportUtilsTest.ts | 10 ++++++++++ 10 files changed, 69 insertions(+), 6 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 6e3e31420a2d..df9b30c058ad 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -11387,9 +11387,19 @@ function createDraftWorkspaceAndNavigateToConfirmationScreen( workspaceName: string, currentUserAccountID: number, currentUserEmail: string, + currentUserLocalCurrency: string, ): void { const isCategorizing = actionName === CONST.IOU.ACTION.CATEGORIZE; - const {expenseChatReportID, policyID, policyName} = createDraftWorkspace(introSelected, workspaceName, currentUserAccountID, currentUserEmail); + const {expenseChatReportID, policyID, policyName} = createDraftWorkspace( + introSelected, + workspaceName, + currentUserAccountID, + currentUserEmail, + '', + false, + undefined, + currentUserLocalCurrency, + ); setMoneyRequestParticipants(transactionID, [ { selected: true, @@ -11423,6 +11433,7 @@ type CreateDraftTransactionParams = { transaction: OnyxEntry; currentUserAccountID: number; currentUserEmail: string; + currentUserLocalCurrency: string; }; function createDraftTransactionAndNavigateToParticipantSelector({ @@ -11440,6 +11451,7 @@ function createDraftTransactionAndNavigateToParticipantSelector({ transaction, currentUserAccountID, currentUserEmail, + currentUserLocalCurrency, }: CreateDraftTransactionParams): void { const transactionID = transaction?.transactionID; if (!transactionID || !reportID) { @@ -11584,7 +11596,7 @@ function createDraftTransactionAndNavigateToParticipantSelector({ return; } - return createDraftWorkspaceAndNavigateToConfirmationScreen(introSelected, transactionID, actionName, '', currentUserAccountID, currentUserEmail); + return createDraftWorkspaceAndNavigateToConfirmationScreen(introSelected, transactionID, actionName, '', currentUserAccountID, currentUserEmail, currentUserLocalCurrency); } /** diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index d936b298a160..ffd59a3557ed 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -476,6 +476,7 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail transaction: iouTransaction, currentUserAccountID: currentUserPersonalDetails.accountID, currentUserEmail: currentUserPersonalDetails.email ?? '', + currentUserLocalCurrency: currentUserPersonalDetails.localCurrencyCode ?? '', }); }, }); @@ -500,6 +501,7 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail transaction: iouTransaction, currentUserAccountID: currentUserPersonalDetails.accountID, currentUserEmail: currentUserPersonalDetails.email ?? '', + currentUserLocalCurrency: currentUserPersonalDetails.localCurrencyCode ?? '', }); }, }); @@ -523,6 +525,7 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail transaction: iouTransaction, currentUserAccountID: currentUserPersonalDetails.accountID, currentUserEmail: currentUserPersonalDetails.email ?? '', + currentUserLocalCurrency: currentUserPersonalDetails.localCurrencyCode ?? '', }); }, }); diff --git a/src/pages/Travel/WorkspaceConfirmationForTravelPage.tsx b/src/pages/Travel/WorkspaceConfirmationForTravelPage.tsx index d463b75d1a40..d916e03017bb 100644 --- a/src/pages/Travel/WorkspaceConfirmationForTravelPage.tsx +++ b/src/pages/Travel/WorkspaceConfirmationForTravelPage.tsx @@ -38,7 +38,7 @@ function WorkspaceConfirmationForTravelPage({route}: WorkspaceConfirmationForTra '', false, params.policyID, - params.currency, + params.currency || (currentUserPersonalDetails.localCurrencyCode ?? ''), params.avatarFile as File, ); createWorkspace({ diff --git a/src/pages/inbox/report/actionContents/ChatActionableButtons.tsx b/src/pages/inbox/report/actionContents/ChatActionableButtons.tsx index 37fbe01aae63..c6077bfd024d 100644 --- a/src/pages/inbox/report/actionContents/ChatActionableButtons.tsx +++ b/src/pages/inbox/report/actionContents/ChatActionableButtons.tsx @@ -166,6 +166,7 @@ function ChatActionableButtons({action, report, originalReport, reportID, origin transaction: trackExpenseTransaction, currentUserAccountID: personalDetail.accountID, currentUserEmail: personalDetail.email ?? '', + currentUserLocalCurrency: personalDetail.localCurrencyCode ?? '', }; const TRACK_EXPENSE_ACTIONS = { submit: CONST.IOU.ACTION.SUBMIT, diff --git a/src/pages/iou/request/step/IOURequestStepAccountant.tsx b/src/pages/iou/request/step/IOURequestStepAccountant.tsx index 82aeb00ea2dc..de2253636328 100644 --- a/src/pages/iou/request/step/IOURequestStepAccountant.tsx +++ b/src/pages/iou/request/step/IOURequestStepAccountant.tsx @@ -26,7 +26,7 @@ function IOURequestStepAccountant({ }, }: IOURequestStepAccountantProps) { const {translate} = useLocalize(); - const {accountID, login, email = ''} = useCurrentUserPersonalDetails(); + const {accountID, login, email = '', localCurrencyCode} = useCurrentUserPersonalDetails(); const selector = useCallback( (policies: OnyxCollection) => { return activeAdminPoliciesSelector(policies, login ?? ''); @@ -49,12 +49,20 @@ function IOURequestStepAccountant({ // Sharing with an accountant involves inviting them to the workspace and that requires admin access. const hasActiveAdminWorkspaces = (adminPolicies?.length ?? 0) > 0; if (!hasActiveAdminWorkspaces) { - createDraftWorkspaceAndNavigateToConfirmationScreen(introSelected, transactionID, action, generateDefaultWorkspaceName(email, lastWorkspaceNumber, translate), accountID, email); + createDraftWorkspaceAndNavigateToConfirmationScreen( + introSelected, + transactionID, + action, + generateDefaultWorkspaceName(email, lastWorkspaceNumber, translate), + accountID, + email, + localCurrencyCode ?? '', + ); return; } Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(iouType, transactionID, reportID, Navigation.getActiveRoute(), action)); - }, [adminPolicies?.length, iouType, transactionID, reportID, action, introSelected, email, lastWorkspaceNumber, translate]); + }, [adminPolicies?.length, iouType, transactionID, reportID, action, introSelected, email, lastWorkspaceNumber, translate, accountID, localCurrencyCode]); const navigateBack = useCallback(() => { Navigation.goBack(backTo); diff --git a/src/pages/iou/request/step/IOURequestStepParticipants.tsx b/src/pages/iou/request/step/IOURequestStepParticipants.tsx index c7536a43de95..29c82460c3c0 100644 --- a/src/pages/iou/request/step/IOURequestStepParticipants.tsx +++ b/src/pages/iou/request/step/IOURequestStepParticipants.tsx @@ -344,6 +344,10 @@ function IOURequestStepParticipants({ generateDefaultWorkspaceName(email, lastWorkspaceNumber, translate), currentUserPersonalDetails.accountID, email, + '', + false, + undefined, + currentUserPersonalDetails.localCurrencyCode ?? '', ); for (const transaction of draftTransactions) { setMoneyRequestParticipants(transaction.transactionID, [ diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index 67a7a95d433c..ccd3c78fdde1 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -491,6 +491,7 @@ describe('actions/IOU', () => { transaction: transactionToCategorize, currentUserAccountID: RORY_ACCOUNT_ID, currentUserEmail: RORY_EMAIL, + currentUserLocalCurrency: '', }); await waitForBatchedUpdates(); @@ -541,6 +542,7 @@ describe('actions/IOU', () => { transaction: originalTransaction, currentUserAccountID: RORY_ACCOUNT_ID, currentUserEmail: RORY_EMAIL, + currentUserLocalCurrency: '', }); await waitForBatchedUpdates(); @@ -580,6 +582,7 @@ describe('actions/IOU', () => { transaction: undefined, currentUserAccountID: RORY_ACCOUNT_ID, currentUserEmail: RORY_EMAIL, + currentUserLocalCurrency: '', }); await waitForBatchedUpdates(); @@ -614,6 +617,7 @@ describe('actions/IOU', () => { amountOwed: 0, currentUserAccountID: RORY_ACCOUNT_ID, currentUserEmail: RORY_EMAIL, + currentUserLocalCurrency: '', }); await waitForBatchedUpdates(); diff --git a/tests/actions/IOUTest/TrackExpenseTest.ts b/tests/actions/IOUTest/TrackExpenseTest.ts index 08ac35dfb120..4b7aa59628d3 100644 --- a/tests/actions/IOUTest/TrackExpenseTest.ts +++ b/tests/actions/IOUTest/TrackExpenseTest.ts @@ -273,6 +273,7 @@ describe('actions/IOU/TrackExpense', () => { transaction, currentUserAccountID: RORY_ACCOUNT_ID, currentUserEmail: RORY_EMAIL, + currentUserLocalCurrency: '', }); await waitForBatchedUpdates(); @@ -848,6 +849,7 @@ describe('actions/IOU/TrackExpense', () => { transaction: createdTransaction, currentUserAccountID: RORY_ACCOUNT_ID, currentUserEmail: RORY_EMAIL, + currentUserLocalCurrency: '', }); await waitForBatchedUpdates(); diff --git a/tests/actions/PolicyTest.ts b/tests/actions/PolicyTest.ts index a0e9b50723e0..924024406969 100644 --- a/tests/actions/PolicyTest.ts +++ b/tests/actions/PolicyTest.ts @@ -2003,6 +2003,25 @@ describe('actions/Policy', () => { expect(draft?.ownerAccountID).not.toBe(ESH_ACCOUNT_ID); expect(draft?.employeeList?.[ESH_EMAIL]).toBeUndefined(); }); + + it('should use the explicit currency argument and not fall back to the deprecated session user localCurrencyCode', async () => { + // Set Onyx session + personal details so localCurrencyCode would be EUR if the fallback were used + await Onyx.set(ONYXKEYS.SESSION, {email: ESH_EMAIL, accountID: ESH_ACCOUNT_ID}); + await Onyx.set(ONYXKEYS.PERSONAL_DETAILS_LIST, { + [ESH_ACCOUNT_ID]: {accountID: ESH_ACCOUNT_ID, login: ESH_EMAIL, localCurrencyCode: CONST.CURRENCY.EUR}, + }); + await waitForBatchedUpdates(); + + const policyID = Policy.generatePolicyID(); + // Pass explicit GBP currency — this should win over the session user's EUR localCurrencyCode + Policy.createDraftWorkspace({choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, WORKSPACE_NAME, ESH_ACCOUNT_ID, ESH_EMAIL, ESH_EMAIL, false, policyID, 'GBP'); + await waitForBatchedUpdates(); + + const draft = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID}`); + + expect(draft?.outputCurrency).toBe('GBP'); + expect(draft?.outputCurrency).not.toBe(CONST.CURRENCY.EUR); + }); }); describe('upgradeToCorporate', () => { diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index 26a7eb541ea8..a43f5190976b 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -14564,6 +14564,7 @@ describe('ReportUtils', () => { transaction: undefined, currentUserAccountID, currentUserEmail, + currentUserLocalCurrency: '', }); expect(Navigation.navigate).not.toHaveBeenCalled(); @@ -14604,6 +14605,7 @@ describe('ReportUtils', () => { transaction, currentUserAccountID, currentUserEmail, + currentUserLocalCurrency: '', }); // Then it should navigate to the restricted action page @@ -14640,6 +14642,7 @@ describe('ReportUtils', () => { transaction, currentUserAccountID, currentUserEmail, + currentUserLocalCurrency: '', }); // Then it should navigate to the restricted action page @@ -14680,6 +14683,7 @@ describe('ReportUtils', () => { transaction, currentUserAccountID, currentUserEmail, + currentUserLocalCurrency: '', }); // Then it should navigate to the category step @@ -14722,6 +14726,7 @@ describe('ReportUtils', () => { transaction, currentUserAccountID, currentUserEmail, + currentUserLocalCurrency: '', }); // Then it should automatically pick the available policy and navigate to the category step @@ -14751,6 +14756,7 @@ describe('ReportUtils', () => { transaction, currentUserAccountID, currentUserEmail, + currentUserLocalCurrency: '', }); // Then it should navigate to the upgrade page because no policies were found to categorize with @@ -14801,6 +14807,7 @@ describe('ReportUtils', () => { transaction, currentUserAccountID, currentUserEmail, + currentUserLocalCurrency: '', }); // Then it should navigate to the upgrade page because it's ambiguous which policy to use @@ -14847,6 +14854,7 @@ describe('ReportUtils', () => { transaction, currentUserAccountID, currentUserEmail, + currentUserLocalCurrency: '', }); // Then it should log a warning and not navigate @@ -14893,6 +14901,7 @@ describe('ReportUtils', () => { transaction, currentUserAccountID, currentUserEmail, + currentUserLocalCurrency: '', }); // Then it should NOT navigate to restricted action page, but to category step @@ -14931,6 +14940,7 @@ describe('ReportUtils', () => { transaction, currentUserAccountID, currentUserEmail, + currentUserLocalCurrency: '', }); // Then it should navigate to restricted action page From 084d80c7f289731d7bf0465f0dc7dc5864114844 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Wed, 22 Apr 2026 17:36:35 +0700 Subject: [PATCH 2/6] chore --- src/libs/actions/Policy/Policy.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index 791eb2347ec1..c3a38fcc170a 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -3137,7 +3137,7 @@ function buildDuplicatePolicyData(policy: Policy, options: DuplicatePolicyDataOp const isTravelOptionSelected = parts?.travel; const isCodingRulesOptionSelected = parts?.codingRules; - const outputCurrency = isOverviewOptionSelected ? policy?.outputCurrency : localCurrency; + const outputCurrency = (isOverviewOptionSelected && policy?.outputCurrency) ? policy?.outputCurrency : localCurrency; const policyMemberAccountIDs = isMemberOptionSelected ? Object.values(getMemberAccountIDsForWorkspace(policy?.employeeList, false, false)) : []; const {customUnitID: distanceCustomUnitID, customUnitRateID} = buildOptimisticDistanceRateCustomUnits(outputCurrency); @@ -3963,7 +3963,8 @@ function createWorkspaceFromIOUPayment( const policyID = generatePolicyID(); const workspaceName = generateDefaultWorkspaceName(currentUserEmail, lastWorkspaceNumber, localeTranslate); const employeeAccountID = iouReport?.ownerAccountID; - const {customUnits, customUnitID, customUnitRateID} = buildOptimisticDistanceRateCustomUnits(iouReport?.currency ?? currentUserLocalCurrency); + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- Disabling this line for safeness as nullish coalescing works only if the value is undefined or null + const {customUnits, customUnitID, customUnitRateID} = buildOptimisticDistanceRateCustomUnits(iouReport?.currency || currentUserLocalCurrency); const oldPersonalPolicyID = iouReport?.policyID; const iouReportID = iouReport?.reportID; From cf57d77037fb770f85bf4ed6323032e3b1b35ff7 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Wed, 22 Apr 2026 17:51:57 +0700 Subject: [PATCH 3/6] Default currentUserLocalCurrency to USD and fix exhaustive-deps Co-Authored-By: Claude Opus 4.7 (1M context) --- src/pages/ReportDetailsPage.tsx | 7 ++++--- src/pages/Travel/WorkspaceConfirmationForTravelPage.tsx | 3 ++- .../inbox/report/actionContents/ChatActionableButtons.tsx | 2 +- src/pages/iou/request/step/IOURequestStepAccountant.tsx | 3 ++- src/pages/iou/request/step/IOURequestStepParticipants.tsx | 3 ++- 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index ffd59a3557ed..41fbd9182ed0 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -476,7 +476,7 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail transaction: iouTransaction, currentUserAccountID: currentUserPersonalDetails.accountID, currentUserEmail: currentUserPersonalDetails.email ?? '', - currentUserLocalCurrency: currentUserPersonalDetails.localCurrencyCode ?? '', + currentUserLocalCurrency: currentUserPersonalDetails.localCurrencyCode ?? CONST.CURRENCY.USD, }); }, }); @@ -501,7 +501,7 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail transaction: iouTransaction, currentUserAccountID: currentUserPersonalDetails.accountID, currentUserEmail: currentUserPersonalDetails.email ?? '', - currentUserLocalCurrency: currentUserPersonalDetails.localCurrencyCode ?? '', + currentUserLocalCurrency: currentUserPersonalDetails.localCurrencyCode ?? CONST.CURRENCY.USD, }); }, }); @@ -525,7 +525,7 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail transaction: iouTransaction, currentUserAccountID: currentUserPersonalDetails.accountID, currentUserEmail: currentUserPersonalDetails.email ?? '', - currentUserLocalCurrency: currentUserPersonalDetails.localCurrencyCode ?? '', + currentUserLocalCurrency: currentUserPersonalDetails.localCurrencyCode ?? CONST.CURRENCY.USD, }); }, }); @@ -641,6 +641,7 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail moneyRequestReport?.reportID, currentUserPersonalDetails.accountID, currentUserPersonalDetails.email, + currentUserPersonalDetails.localCurrencyCode, isTaskActionable, isRootGroupChat, leaveChat, diff --git a/src/pages/Travel/WorkspaceConfirmationForTravelPage.tsx b/src/pages/Travel/WorkspaceConfirmationForTravelPage.tsx index d916e03017bb..671291b37c75 100644 --- a/src/pages/Travel/WorkspaceConfirmationForTravelPage.tsx +++ b/src/pages/Travel/WorkspaceConfirmationForTravelPage.tsx @@ -10,6 +10,7 @@ import useOnyx from '@hooks/useOnyx'; import {createDraftWorkspace, createWorkspace} from '@libs/actions/Policy/Policy'; import Navigation from '@libs/Navigation/Navigation'; import type {TravelNavigatorParamList} from '@libs/Navigation/types'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; @@ -38,7 +39,7 @@ function WorkspaceConfirmationForTravelPage({route}: WorkspaceConfirmationForTra '', false, params.policyID, - params.currency || (currentUserPersonalDetails.localCurrencyCode ?? ''), + params.currency || (currentUserPersonalDetails.localCurrencyCode ?? CONST.CURRENCY.USD), params.avatarFile as File, ); createWorkspace({ diff --git a/src/pages/inbox/report/actionContents/ChatActionableButtons.tsx b/src/pages/inbox/report/actionContents/ChatActionableButtons.tsx index c6077bfd024d..534e799a1678 100644 --- a/src/pages/inbox/report/actionContents/ChatActionableButtons.tsx +++ b/src/pages/inbox/report/actionContents/ChatActionableButtons.tsx @@ -166,7 +166,7 @@ function ChatActionableButtons({action, report, originalReport, reportID, origin transaction: trackExpenseTransaction, currentUserAccountID: personalDetail.accountID, currentUserEmail: personalDetail.email ?? '', - currentUserLocalCurrency: personalDetail.localCurrencyCode ?? '', + currentUserLocalCurrency: personalDetail.localCurrencyCode ?? CONST.CURRENCY.USD, }; const TRACK_EXPENSE_ACTIONS = { submit: CONST.IOU.ACTION.SUBMIT, diff --git a/src/pages/iou/request/step/IOURequestStepAccountant.tsx b/src/pages/iou/request/step/IOURequestStepAccountant.tsx index de2253636328..898677f6ce41 100644 --- a/src/pages/iou/request/step/IOURequestStepAccountant.tsx +++ b/src/pages/iou/request/step/IOURequestStepAccountant.tsx @@ -9,6 +9,7 @@ import {generateDefaultWorkspaceName} from '@libs/actions/Policy/Policy'; import Navigation from '@libs/Navigation/Navigation'; import {createDraftWorkspaceAndNavigateToConfirmationScreen} from '@libs/ReportUtils'; import MoneyRequestAccountantSelector from '@pages/iou/request/MoneyRequestAccountantSelector'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; @@ -56,7 +57,7 @@ function IOURequestStepAccountant({ generateDefaultWorkspaceName(email, lastWorkspaceNumber, translate), accountID, email, - localCurrencyCode ?? '', + localCurrencyCode ?? CONST.CURRENCY.USD, ); return; } diff --git a/src/pages/iou/request/step/IOURequestStepParticipants.tsx b/src/pages/iou/request/step/IOURequestStepParticipants.tsx index 29c82460c3c0..e3ccd6832183 100644 --- a/src/pages/iou/request/step/IOURequestStepParticipants.tsx +++ b/src/pages/iou/request/step/IOURequestStepParticipants.tsx @@ -347,7 +347,7 @@ function IOURequestStepParticipants({ '', false, undefined, - currentUserPersonalDetails.localCurrencyCode ?? '', + currentUserPersonalDetails.localCurrencyCode ?? CONST.CURRENCY.USD, ); for (const transaction of draftTransactions) { setMoneyRequestParticipants(transaction.transactionID, [ @@ -414,6 +414,7 @@ function IOURequestStepParticipants({ policyForMovingExpenses, currentUserPersonalDetails.email, currentUserPersonalDetails.accountID, + currentUserPersonalDetails.localCurrencyCode, introSelected, translate, backTo, From 8c6e91855c7b077b8051a235ef1e72b11923540d Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Thu, 23 Apr 2026 21:37:40 +0700 Subject: [PATCH 4/6] refactor: convert createDraftWorkspace to options object Callers no longer pass placeholder positional args (''/false/undefined) to reach the currency parameter. Addresses CONSISTENCY-2 review feedback. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/libs/ReportUtils.ts | 9 ++-- src/libs/actions/Policy/Policy.ts | 28 +++++++---- .../WorkspaceConfirmationForTravelPage.tsx | 18 ++++--- .../step/IOURequestStepParticipants.tsx | 15 +++--- tests/actions/PolicyTest.ts | 47 ++++++++++++++----- 5 files changed, 72 insertions(+), 45 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index df9b30c058ad..5a2d854b7103 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -11390,16 +11390,13 @@ function createDraftWorkspaceAndNavigateToConfirmationScreen( currentUserLocalCurrency: string, ): void { const isCategorizing = actionName === CONST.IOU.ACTION.CATEGORIZE; - const {expenseChatReportID, policyID, policyName} = createDraftWorkspace( + const {expenseChatReportID, policyID, policyName} = createDraftWorkspace({ introSelected, workspaceName, currentUserAccountID, currentUserEmail, - '', - false, - undefined, - currentUserLocalCurrency, - ); + currency: currentUserLocalCurrency, + }); setMoneyRequestParticipants(transactionID, [ { selected: true, diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index c3a38fcc170a..98a7c110d7ba 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -2983,17 +2983,29 @@ function createWorkspace(options: CreateWorkspaceDataOptions): CreateWorkspacePa /** * Creates a draft workspace for various money request flows */ -function createDraftWorkspace( - introSelected: OnyxEntry, - workspaceName: string, - currentUserAccountID: number, - currentUserEmail: string, +type CreateDraftWorkspaceParams = { + introSelected: OnyxEntry; + workspaceName: string; + currentUserAccountID: number; + currentUserEmail: string; + policyOwnerEmail?: string; + makeMeAdmin?: boolean; + policyID?: string; + currency?: string; + file?: File; +}; + +function createDraftWorkspace({ + introSelected, + workspaceName, + currentUserAccountID, + currentUserEmail, policyOwnerEmail = '', makeMeAdmin = false, policyID = generatePolicyID(), currency = '', - file?: File, -): CreateWorkspaceParams { + file, +}: CreateDraftWorkspaceParams): CreateWorkspaceParams { const {customUnits, customUnitID, customUnitRateID, outputCurrency} = buildOptimisticDistanceRateCustomUnits(currency); const {expenseChatData, adminsChatReportID, adminsCreatedReportActionID, expenseChatReportID, expenseCreatedReportActionID} = ReportUtils.buildOptimisticWorkspaceChats( @@ -3137,7 +3149,7 @@ function buildDuplicatePolicyData(policy: Policy, options: DuplicatePolicyDataOp const isTravelOptionSelected = parts?.travel; const isCodingRulesOptionSelected = parts?.codingRules; - const outputCurrency = (isOverviewOptionSelected && policy?.outputCurrency) ? policy?.outputCurrency : localCurrency; + const outputCurrency = isOverviewOptionSelected && policy?.outputCurrency ? policy?.outputCurrency : localCurrency; const policyMemberAccountIDs = isMemberOptionSelected ? Object.values(getMemberAccountIDsForWorkspace(policy?.employeeList, false, false)) : []; const {customUnitID: distanceCustomUnitID, customUnitRateID} = buildOptimisticDistanceRateCustomUnits(outputCurrency); diff --git a/src/pages/Travel/WorkspaceConfirmationForTravelPage.tsx b/src/pages/Travel/WorkspaceConfirmationForTravelPage.tsx index 671291b37c75..cb18c7b3d9a1 100644 --- a/src/pages/Travel/WorkspaceConfirmationForTravelPage.tsx +++ b/src/pages/Travel/WorkspaceConfirmationForTravelPage.tsx @@ -31,17 +31,15 @@ function WorkspaceConfirmationForTravelPage({route}: WorkspaceConfirmationForTra }; const onSubmit = (params: WorkspaceConfirmationSubmitFunctionParams) => { - createDraftWorkspace( + createDraftWorkspace({ introSelected, - params.name, - currentUserPersonalDetails.accountID, - currentUserPersonalDetails.email ?? '', - '', - false, - params.policyID, - params.currency || (currentUserPersonalDetails.localCurrencyCode ?? CONST.CURRENCY.USD), - params.avatarFile as File, - ); + workspaceName: params.name, + currentUserAccountID: currentUserPersonalDetails.accountID, + currentUserEmail: currentUserPersonalDetails.email ?? '', + policyID: params.policyID, + currency: params.currency || (currentUserPersonalDetails.localCurrencyCode ?? CONST.CURRENCY.USD), + file: params.avatarFile as File, + }); createWorkspace({ policyName: params.name, policyID: params.policyID, diff --git a/src/pages/iou/request/step/IOURequestStepParticipants.tsx b/src/pages/iou/request/step/IOURequestStepParticipants.tsx index e3ccd6832183..b9f366eba80a 100644 --- a/src/pages/iou/request/step/IOURequestStepParticipants.tsx +++ b/src/pages/iou/request/step/IOURequestStepParticipants.tsx @@ -339,16 +339,13 @@ function IOURequestStepParticipants({ if ((isCategorizing || isShareAction) && numberOfParticipants.current === 0) { const email = currentUserPersonalDetails.email ?? ''; const lastWorkspaceNumber = lastWorkspaceNumberSelector(allPolicies, email); - const {expenseChatReportID, policyID, policyName} = createDraftWorkspace( + const {expenseChatReportID, policyID, policyName} = createDraftWorkspace({ introSelected, - generateDefaultWorkspaceName(email, lastWorkspaceNumber, translate), - currentUserPersonalDetails.accountID, - email, - '', - false, - undefined, - currentUserPersonalDetails.localCurrencyCode ?? CONST.CURRENCY.USD, - ); + workspaceName: generateDefaultWorkspaceName(email, lastWorkspaceNumber, translate), + currentUserAccountID: currentUserPersonalDetails.accountID, + currentUserEmail: email, + currency: currentUserPersonalDetails.localCurrencyCode ?? CONST.CURRENCY.USD, + }); for (const transaction of draftTransactions) { setMoneyRequestParticipants(transaction.transactionID, [ { diff --git a/tests/actions/PolicyTest.ts b/tests/actions/PolicyTest.ts index 924024406969..0c74dc254b84 100644 --- a/tests/actions/PolicyTest.ts +++ b/tests/actions/PolicyTest.ts @@ -1924,16 +1924,16 @@ describe('actions/Policy', () => { await waitForBatchedUpdates(); const policyID = Policy.generatePolicyID(); - const params = Policy.createDraftWorkspace( - {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, - WORKSPACE_NAME, - ESH_ACCOUNT_ID, - ESH_EMAIL, - ESH_EMAIL, - true, + const params = Policy.createDraftWorkspace({ + introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, + workspaceName: WORKSPACE_NAME, + currentUserAccountID: ESH_ACCOUNT_ID, + currentUserEmail: ESH_EMAIL, + policyOwnerEmail: ESH_EMAIL, + makeMeAdmin: true, policyID, - CONST.CURRENCY.USD, - ); + currency: CONST.CURRENCY.USD, + }); await waitForBatchedUpdates(); const draft = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID}`); @@ -1961,7 +1961,15 @@ describe('actions/Policy', () => { await waitForBatchedUpdates(); const policyID = Policy.generatePolicyID(); - Policy.createDraftWorkspace({choice: CONST.ONBOARDING_CHOICES.TRACK_WORKSPACE}, WORKSPACE_NAME, ESH_ACCOUNT_ID, ESH_EMAIL, ESH_EMAIL, false, policyID, CONST.CURRENCY.EUR); + Policy.createDraftWorkspace({ + introSelected: {choice: CONST.ONBOARDING_CHOICES.TRACK_WORKSPACE}, + workspaceName: WORKSPACE_NAME, + currentUserAccountID: ESH_ACCOUNT_ID, + currentUserEmail: ESH_EMAIL, + policyOwnerEmail: ESH_EMAIL, + policyID, + currency: CONST.CURRENCY.EUR, + }); await waitForBatchedUpdates(); const draft = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID}`); @@ -1982,7 +1990,14 @@ describe('actions/Policy', () => { const customEmail = 'custom@example.com'; const policyID = Policy.generatePolicyID(); - Policy.createDraftWorkspace({choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, WORKSPACE_NAME, customAccountID, customEmail, customEmail, false, policyID); + Policy.createDraftWorkspace({ + introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, + workspaceName: WORKSPACE_NAME, + currentUserAccountID: customAccountID, + currentUserEmail: customEmail, + policyOwnerEmail: customEmail, + policyID, + }); await waitForBatchedUpdates(); const draft = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID}`); @@ -2014,7 +2029,15 @@ describe('actions/Policy', () => { const policyID = Policy.generatePolicyID(); // Pass explicit GBP currency — this should win over the session user's EUR localCurrencyCode - Policy.createDraftWorkspace({choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, WORKSPACE_NAME, ESH_ACCOUNT_ID, ESH_EMAIL, ESH_EMAIL, false, policyID, 'GBP'); + Policy.createDraftWorkspace({ + introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, + workspaceName: WORKSPACE_NAME, + currentUserAccountID: ESH_ACCOUNT_ID, + currentUserEmail: ESH_EMAIL, + policyOwnerEmail: ESH_EMAIL, + policyID, + currency: 'GBP', + }); await waitForBatchedUpdates(); const draft = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID}`); From c8795830dcff1d295b3cae62c7a06088aac97946 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Thu, 23 Apr 2026 21:49:55 +0700 Subject: [PATCH 5/6] refactor: extract repeated currentUserLocalCurrency fallback in ReportDetailsPage Addresses CONSISTENCY-3 review feedback. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/pages/ReportDetailsPage.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 41fbd9182ed0..9533e0619e0f 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -454,6 +454,7 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail const actionReportID = getOriginalReportID(report.reportID, parentReportAction, reportActionsForOriginalReportID); const whisperAction = getTrackExpenseActionableWhisper(iouTransactionID, moneyRequestReport?.reportID); const actionableWhisperReportActionID = whisperAction?.reportActionID; + const currentUserLocalCurrency = currentUserPersonalDetails.localCurrencyCode ?? CONST.CURRENCY.USD; items.push({ key: CONST.REPORT_DETAILS_MENU_ITEM.TRACK.SUBMIT, translationKey: 'actionableMentionTrackExpense.submit', @@ -476,7 +477,7 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail transaction: iouTransaction, currentUserAccountID: currentUserPersonalDetails.accountID, currentUserEmail: currentUserPersonalDetails.email ?? '', - currentUserLocalCurrency: currentUserPersonalDetails.localCurrencyCode ?? CONST.CURRENCY.USD, + currentUserLocalCurrency, }); }, }); @@ -501,7 +502,7 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail transaction: iouTransaction, currentUserAccountID: currentUserPersonalDetails.accountID, currentUserEmail: currentUserPersonalDetails.email ?? '', - currentUserLocalCurrency: currentUserPersonalDetails.localCurrencyCode ?? CONST.CURRENCY.USD, + currentUserLocalCurrency, }); }, }); @@ -525,7 +526,7 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail transaction: iouTransaction, currentUserAccountID: currentUserPersonalDetails.accountID, currentUserEmail: currentUserPersonalDetails.email ?? '', - currentUserLocalCurrency: currentUserPersonalDetails.localCurrencyCode ?? CONST.CURRENCY.USD, + currentUserLocalCurrency, }); }, }); From 4cd5cf3a194d927abceffad9dc5679143b5a70e9 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Fri, 24 Apr 2026 23:59:50 +0700 Subject: [PATCH 6/6] chore --- src/libs/actions/Policy/Policy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index 71ea25f46a04..4aeaa6a0bf32 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -3976,7 +3976,7 @@ function createWorkspaceFromIOUPayment( const policyID = generatePolicyID(); const workspaceName = generateDefaultWorkspaceName(currentUserEmail, lastWorkspaceNumber, localeTranslate); const employeeAccountID = iouReport?.ownerAccountID; - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- Disabling this line for safeness as nullish coalescing works only if the value is undefined or null + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- Disabling this line for safeness as iouReport?.currency could be an empty string const {customUnits, customUnitID, customUnitRateID} = buildOptimisticDistanceRateCustomUnits(iouReport?.currency || currentUserLocalCurrency); const oldPersonalPolicyID = iouReport?.policyID; const iouReportID = iouReport?.reportID;