From 5b4834943a11d6ef26ef85bcb765502fcb60c5fd Mon Sep 17 00:00:00 2001 From: daledah Date: Tue, 9 Jun 2026 17:14:09 +0700 Subject: [PATCH 1/2] refactor trackExpense function to use hasCompletedGuidedSetupFlow param part 1 --- src/libs/actions/IOU/TrackExpense.ts | 6 ++ .../IOU/types/CreateTrackExpenseParams.ts | 2 + src/libs/actions/Policy/Policy.ts | 4 + src/pages/Share/SubmitDetailsPage.tsx | 9 +- .../iou/request/step/IOURequestStepAmount.tsx | 7 +- .../step/confirmation/useExpenseSubmission.ts | 7 +- tests/actions/IOUTest/TrackExpenseTest.ts | 96 +++++++++++++++++++ 7 files changed, 123 insertions(+), 8 deletions(-) diff --git a/src/libs/actions/IOU/TrackExpense.ts b/src/libs/actions/IOU/TrackExpense.ts index 5bc9c37cb96a..3f7378549e7c 100644 --- a/src/libs/actions/IOU/TrackExpense.ts +++ b/src/libs/actions/IOU/TrackExpense.ts @@ -182,6 +182,8 @@ type GetTrackExpenseInformationParams = { quickAction: OnyxEntry; betas: OnyxEntry; isSelfTourViewed: boolean; + // TODO: Make it required once we complete refactoring the getTrackExpenseInformation function to use hasCompletedGuidedSetupFlow. Refactor issue: https://github.com/Expensify/App/issues/66424 + hasCompletedGuidedSetupFlow?: boolean; defaultWorkspaceName?: string; optimisticChatReportID?: string; // TODO: delegateAccountID will be made required in PR 10 when all callers pass the value (https://github.com/Expensify/App/issues/66425) @@ -830,6 +832,7 @@ function getTrackExpenseInformation(params: GetTrackExpenseInformationParams): T defaultWorkspaceName, optimisticChatReportID, delegateAccountID, + hasCompletedGuidedSetupFlow, } = params; const {payeeAccountID = currentUserAccountIDParam, payeeEmail = currentUserEmailParam, participant} = participantParams; const {policy} = policyParams; @@ -978,6 +981,7 @@ function getTrackExpenseInformation(params: GetTrackExpenseInformationParams): T hasActiveAdminPolicies: undefined, betas, isSelfTourViewed, + hasCompletedGuidedSetupFlow, }); createdWorkspaceParams = workspaceData.params; onyxData.optimisticData?.push(...(workspaceData.optimisticData ?? [])); @@ -2321,6 +2325,7 @@ function trackExpense(params: CreateTrackExpenseParams) { recentWaypoints = [], betas, isSelfTourViewed, + hasCompletedGuidedSetupFlow, defaultWorkspaceName, previousOdometerDraft, delegateAccountID, @@ -2481,6 +2486,7 @@ function trackExpense(params: CreateTrackExpenseParams) { quickAction, betas, isSelfTourViewed, + hasCompletedGuidedSetupFlow, defaultWorkspaceName, optimisticChatReportID, delegateAccountID, diff --git a/src/libs/actions/IOU/types/CreateTrackExpenseParams.ts b/src/libs/actions/IOU/types/CreateTrackExpenseParams.ts index 2fc138a5f3b8..80f5c1a1887d 100644 --- a/src/libs/actions/IOU/types/CreateTrackExpenseParams.ts +++ b/src/libs/actions/IOU/types/CreateTrackExpenseParams.ts @@ -34,6 +34,8 @@ type CreateTrackExpenseParams = { recentWaypoints: OnyxEntry; betas: OnyxEntry; isSelfTourViewed: boolean; + // TODO: Make it required once we complete refactoring the trackExpense function to use hasCompletedGuidedSetupFlow. Refactor issue: https://github.com/Expensify/App/issues/66424 + hasCompletedGuidedSetupFlow?: boolean; defaultWorkspaceName?: string; previousOdometerDraft?: OnyxEntry; // TODO: delegateAccountID will be made required in PR 10 when all callers pass the value (https://github.com/Expensify/App/issues/66425) diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index 409ee3986332..2ce10264675e 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -232,6 +232,8 @@ type BuildPolicyDataOptions = { type?: typeof CONST.POLICY.TYPE.TEAM | typeof CONST.POLICY.TYPE.CORPORATE | typeof CONST.POLICY.TYPE.SUBMIT; // TODO: Make it required once we complete refactoring the buildPolicyData function to use isSelfTourViewed. Refactor issue: https://github.com/Expensify/App/issues/66424 isSelfTourViewed?: boolean; + // TODO: Make it required once we complete refactoring the buildPolicyData function to use hasCompletedGuidedSetupFlow. Refactor issue: https://github.com/Expensify/App/issues/66424 + hasCompletedGuidedSetupFlow?: boolean; hasActiveAdminPolicies: boolean | undefined; betas?: OnyxEntry; }; @@ -2570,6 +2572,7 @@ function buildPolicyData(options: BuildPolicyDataOptions): OnyxData { expect(resultWithoutTourViewed.chatReport).toBeDefined(); expect(resultWithoutTourViewed.transaction).toBeDefined(); }); + + it('should pass hasCompletedGuidedSetupFlow: true to trackExpense and create transaction successfully', async () => { + // Given a selfDM report + const selfDMReport: Report = { + ...createRandomReport(1, CONST.REPORT.CHAT_TYPE.SELF_DM), + reportID: 'selfDM-guided-setup-1', + }; + + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${selfDMReport.reportID}`, selfDMReport); + + // When trackExpense is called with hasCompletedGuidedSetupFlow: true + trackExpense({ + ...getDefaultTrackExpenseParams(selfDMReport, {amount: 11000, merchant: 'Guided Setup Complete Merchant'}), + hasCompletedGuidedSetupFlow: true, + }); + await waitForBatchedUpdates(); + + // Then the transaction should be created with correct values + let transactions: OnyxCollection; + await getOnyxData({ + key: ONYXKEYS.COLLECTION.TRANSACTION, + waitForCollectionCallback: true, + callback: (val) => { + transactions = val; + }, + }); + + const createdTransaction = Object.values(transactions ?? {}).at(0); + expect(createdTransaction).toBeTruthy(); + expect(Math.abs(createdTransaction?.amount ?? 0)).toBe(11000); + expect(createdTransaction?.merchant).toBe('Guided Setup Complete Merchant'); + }); + + it('should pass hasCompletedGuidedSetupFlow: false to trackExpense and create transaction successfully', async () => { + // Given a selfDM report + const selfDMReport: Report = { + ...createRandomReport(1, CONST.REPORT.CHAT_TYPE.SELF_DM), + reportID: 'selfDM-guided-setup-2', + }; + + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${selfDMReport.reportID}`, selfDMReport); + + // When trackExpense is called with hasCompletedGuidedSetupFlow: false + trackExpense({ + ...getDefaultTrackExpenseParams(selfDMReport, {amount: 8000, merchant: 'Guided Setup Incomplete Merchant'}), + hasCompletedGuidedSetupFlow: false, + }); + await waitForBatchedUpdates(); + + // Then the transaction should be created with correct values + let transactions: OnyxCollection; + await getOnyxData({ + key: ONYXKEYS.COLLECTION.TRANSACTION, + waitForCollectionCallback: true, + callback: (val) => { + transactions = val; + }, + }); + + const createdTransaction = Object.values(transactions ?? {}).at(0); + expect(createdTransaction).toBeTruthy(); + expect(Math.abs(createdTransaction?.amount ?? 0)).toBe(8000); + expect(createdTransaction?.merchant).toBe('Guided Setup Incomplete Merchant'); + }); + + it('should pass hasCompletedGuidedSetupFlow: undefined to trackExpense and create transaction successfully', async () => { + // Given a selfDM report + const selfDMReport: Report = { + ...createRandomReport(1, CONST.REPORT.CHAT_TYPE.SELF_DM), + reportID: 'selfDM-guided-setup-3', + }; + + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${selfDMReport.reportID}`, selfDMReport); + + // When trackExpense is called without hasCompletedGuidedSetupFlow (undefined) + trackExpense({ + ...getDefaultTrackExpenseParams(selfDMReport, {amount: 6000, merchant: 'Guided Setup Undefined Merchant'}), + hasCompletedGuidedSetupFlow: undefined, + }); + await waitForBatchedUpdates(); + + // Then the transaction should be created with correct values + let transactions: OnyxCollection; + await getOnyxData({ + key: ONYXKEYS.COLLECTION.TRANSACTION, + waitForCollectionCallback: true, + callback: (val) => { + transactions = val; + }, + }); + + const createdTransaction = Object.values(transactions ?? {}).at(0); + expect(createdTransaction).toBeTruthy(); + expect(Math.abs(createdTransaction?.amount ?? 0)).toBe(6000); + expect(createdTransaction?.merchant).toBe('Guided Setup Undefined Merchant'); + }); }); describe('requestMoney', () => { From b7c2a295fff0889666f1a6cff9a54d658662dec6 Mon Sep 17 00:00:00 2001 From: daledah Date: Tue, 9 Jun 2026 23:29:51 +0700 Subject: [PATCH 2/2] fix comments --- src/pages/iou/request/step/IOURequestStepAmount.tsx | 2 +- src/pages/iou/request/step/confirmation/useExpenseSubmission.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepAmount.tsx b/src/pages/iou/request/step/IOURequestStepAmount.tsx index 30b7052effcc..c51a2b373f6a 100644 --- a/src/pages/iou/request/step/IOURequestStepAmount.tsx +++ b/src/pages/iou/request/step/IOURequestStepAmount.tsx @@ -135,7 +135,7 @@ function IOURequestStepAmount({ const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED); const [guidedSetupAndTourStatus] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: guidedSetupAndTourStatusSelector}); const isSelfTourViewed = !!guidedSetupAndTourStatus?.isSelfTourViewed; - const hasCompletedGuidedSetupFlow = !!guidedSetupAndTourStatus?.hasCompletedGuidedSetupFlow; + const hasCompletedGuidedSetupFlow = guidedSetupAndTourStatus?.hasCompletedGuidedSetupFlow; const betas = useContext(BetasContext); const defaultExpensePolicy = useDefaultExpensePolicy(); const personalPolicy = usePersonalPolicy(); diff --git a/src/pages/iou/request/step/confirmation/useExpenseSubmission.ts b/src/pages/iou/request/step/confirmation/useExpenseSubmission.ts index bca3a51deb27..4acfb9b4bbff 100644 --- a/src/pages/iou/request/step/confirmation/useExpenseSubmission.ts +++ b/src/pages/iou/request/step/confirmation/useExpenseSubmission.ts @@ -256,7 +256,7 @@ function useExpenseSubmission(params: UseExpenseSubmissionParams) { const [quickAction] = useOnyx(ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE); const [guidedSetupAndTourStatus] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: guidedSetupAndTourStatusSelector}); const isSelfTourViewed = !!guidedSetupAndTourStatus?.isSelfTourViewed; - const hasCompletedGuidedSetupFlow = !!guidedSetupAndTourStatus?.hasCompletedGuidedSetupFlow; + const hasCompletedGuidedSetupFlow = guidedSetupAndTourStatus?.hasCompletedGuidedSetupFlow; const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED); const [betas] = useOnyx(ONYXKEYS.BETAS); const [gpsDraftDetails] = useOnyx(ONYXKEYS.GPS_DRAFT_DETAILS);