From aa440c398b541de3094ba9f77fb97dfa77346d00 Mon Sep 17 00:00:00 2001 From: truph01 Date: Tue, 21 Jul 2026 17:18:11 +0700 Subject: [PATCH 1/3] refactor: thread currentUserAccountID via openReport --- src/pages/Search/SearchMoneyRequestReportPage.tsx | 2 +- src/pages/Share/ShareDetailsPage.tsx | 1 + src/pages/TransactionDuplicate/Review.tsx | 4 ++-- .../hooks/useDistanceTransactionBackup.ts | 5 ++++- .../request/step/withWritableReportOrNotFound.tsx | 4 +++- .../routes/TransactionReceiptModalContent.tsx | 2 +- .../ReportAddAttachmentModalContent/index.tsx | 6 ++++-- .../report/ReportAttachmentModalContent.tsx | 6 ++++-- tests/actions/IOUTest/DeleteMoneyRequestTest.ts | 6 ++++++ tests/actions/IOUTest/DuplicateTest.ts | 2 ++ tests/actions/IOUTest/TrackExpenseTest.ts | 2 ++ tests/actions/MergeTransactionTest.ts | 2 ++ tests/actions/ReportTest.ts | 15 ++++++++++----- 13 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/pages/Search/SearchMoneyRequestReportPage.tsx b/src/pages/Search/SearchMoneyRequestReportPage.tsx index 1a3b116a4f77..cbee1c320944 100644 --- a/src/pages/Search/SearchMoneyRequestReportPage.tsx +++ b/src/pages/Search/SearchMoneyRequestReportPage.tsx @@ -212,7 +212,7 @@ function SearchMoneyRequestReportPage({route}: SearchMoneyRequestPageProps) { return; } - openReport({reportID: reportIDFromRoute, introSelected, betas, hasReportActions}); + openReport({reportID: reportIDFromRoute, introSelected, betas, hasReportActions, currentUserAccountID}); isInitialMountRef.current = false; // oneTransactionID dependency handles the case when deleting a transaction: diff --git a/src/pages/Share/ShareDetailsPage.tsx b/src/pages/Share/ShareDetailsPage.tsx index 64e23c563e9f..b6734d2eabca 100644 --- a/src/pages/Share/ShareDetailsPage.tsx +++ b/src/pages/Share/ShareDetailsPage.tsx @@ -163,6 +163,7 @@ function ShareDetailsPage({route}: ShareDetailsPageProps) { newReportObject: report, betas, hasReportActions: false, + currentUserAccountID: personalDetail.accountID, }); } if (report.reportID) { diff --git a/src/pages/TransactionDuplicate/Review.tsx b/src/pages/TransactionDuplicate/Review.tsx index 9a7c65cb889f..3f98dfb6e056 100644 --- a/src/pages/TransactionDuplicate/Review.tsx +++ b/src/pages/TransactionDuplicate/Review.tsx @@ -123,8 +123,8 @@ function TransactionDuplicateReview() { if (!route.params.threadReportID || report?.reportID) { return; } - openReport({reportID: route.params.threadReportID, introSelected, betas, hasReportActions}); - }, [report?.reportID, route.params.threadReportID, introSelected, betas, hasReportActions]); + openReport({reportID: route.params.threadReportID, introSelected, betas, hasReportActions, currentUserAccountID: currentPersonalDetails.accountID}); + }, [report?.reportID, route.params.threadReportID, introSelected, betas, hasReportActions, currentPersonalDetails.accountID]); useEffect(() => { if (!transactionID) { diff --git a/src/pages/iou/request/step/IOURequestStepDistance/hooks/useDistanceTransactionBackup.ts b/src/pages/iou/request/step/IOURequestStepDistance/hooks/useDistanceTransactionBackup.ts index c6fa47c860a1..581a46077039 100644 --- a/src/pages/iou/request/step/IOURequestStepDistance/hooks/useDistanceTransactionBackup.ts +++ b/src/pages/iou/request/step/IOURequestStepDistance/hooks/useDistanceTransactionBackup.ts @@ -1,3 +1,5 @@ +import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; + import {openReport} from '@libs/actions/Report'; import {createBackupTransaction, removeBackupTransaction, restoreOriginalTransactionFromBackup} from '@libs/actions/TransactionEdit'; import {hasRoute} from '@libs/TransactionUtils'; @@ -32,6 +34,7 @@ type UseDistanceTransactionBackupParams = { }; function useDistanceTransactionBackup({transaction, isCreatingNewRequest, isEditingSplit, isDraft, introSelected, betas, transactionWasSavedRef}: UseDistanceTransactionBackupParams): void { + const {accountID: currentUserAccountID} = useCurrentUserPersonalDetails(); // This effect runs when the component is mounted and unmounted. It's purpose is to be able to properly // discard changes if the user cancels out of making any changes. This is accomplished by backing up the // original transaction, letting the user modify the current transaction, and then if the user ever @@ -57,7 +60,7 @@ function useDistanceTransactionBackup({transaction, isCreatingNewRequest, isEdit if (!transaction?.reportID || hasRoute(transaction, true)) { return; } - openReport({reportID: transaction?.reportID, introSelected, betas, hasReportActions: true}); + openReport({reportID: transaction?.reportID, introSelected, betas, hasReportActions: true, currentUserAccountID}); }; // eslint-disable-next-line react-hooks/exhaustive-deps -- mount/unmount-only effect: backup on mount, restore-or-drop on unmount, never re-runs }, []); diff --git a/src/pages/iou/request/step/withWritableReportOrNotFound.tsx b/src/pages/iou/request/step/withWritableReportOrNotFound.tsx index 71ddd975c102..a08f18a0e6ab 100644 --- a/src/pages/iou/request/step/withWritableReportOrNotFound.tsx +++ b/src/pages/iou/request/step/withWritableReportOrNotFound.tsx @@ -1,5 +1,6 @@ import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; +import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useOnyx from '@hooks/useOnyx'; import useReportIsArchived from '@hooks/useReportIsArchived'; @@ -93,6 +94,7 @@ function WithWritableReportOrNotFoundImpl { - openReport({reportID, introSelected, reportActionID, betas, hasReportActions}); - }, [reportID, introSelected, reportActionID, betas, hasReportActions]); + openReport({reportID, introSelected, reportActionID, betas, hasReportActions, currentUserAccountID}); + }, [reportID, introSelected, reportActionID, betas, hasReportActions, currentUserAccountID]); // Close the modal if user loses write access (e.g., admin switches "Who can post" to Admins only) useEffect(() => { diff --git a/src/pages/media/AttachmentModalScreen/routes/report/ReportAttachmentModalContent.tsx b/src/pages/media/AttachmentModalScreen/routes/report/ReportAttachmentModalContent.tsx index cad45c9d1480..1690ba6c630c 100644 --- a/src/pages/media/AttachmentModalScreen/routes/report/ReportAttachmentModalContent.tsx +++ b/src/pages/media/AttachmentModalScreen/routes/report/ReportAttachmentModalContent.tsx @@ -1,5 +1,6 @@ import type {Attachment} from '@components/Attachments/types'; +import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; import useOriginalReportID from '@hooks/useOriginalReportID'; @@ -48,6 +49,7 @@ function ReportAttachmentModalContent({route, navigation}: AttachmentModalScreen const hasReportActions = !!reportActions; const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED); const [betas] = useOnyx(ONYXKEYS.BETAS); + const {accountID: currentUserAccountID} = useCurrentUserPersonalDetails(); const originalReportID = useOriginalReportID(reportID, reportActionID ? (reportActions?.[reportActionID ?? CONST.DEFAULT_NUMBER_ID] ?? {reportActionID}) : undefined); const reportActionReportID = originalReportID ?? reportID; @@ -75,8 +77,8 @@ function ReportAttachmentModalContent({route, navigation}: AttachmentModalScreen return; } - openReport({reportID: reportActionReportID, introSelected, reportActionID, betas, hasReportActions}); - }, [reportActionReportID, shouldFetchReport, introSelected, reportActionID, betas, hasReportActions]); + openReport({reportID: reportActionReportID, introSelected, reportActionID, betas, hasReportActions, currentUserAccountID}); + }, [reportActionReportID, shouldFetchReport, introSelected, reportActionID, betas, hasReportActions, currentUserAccountID]); const onCarouselAttachmentChange = (attachment: Attachment) => { const routeToNavigate = ROUTES.REPORT_ATTACHMENTS.getRoute({ diff --git a/tests/actions/IOUTest/DeleteMoneyRequestTest.ts b/tests/actions/IOUTest/DeleteMoneyRequestTest.ts index d192f4961198..3cab9cdf3337 100644 --- a/tests/actions/IOUTest/DeleteMoneyRequestTest.ts +++ b/tests/actions/IOUTest/DeleteMoneyRequestTest.ts @@ -549,6 +549,7 @@ describe('actions/IOU/DeleteMoneyRequest', () => { personalDetails: allPersonalDetails, newReportObject: thread, parentReportActionID: createIOUAction?.reportActionID, + currentUserAccountID: RORY_ACCOUNT_ID, }); await waitForBatchedUpdates(); @@ -658,6 +659,7 @@ describe('actions/IOU/DeleteMoneyRequest', () => { personalDetails: allPersonalDetails, newReportObject: thread, parentReportActionID: createIOUAction?.reportActionID, + currentUserAccountID: RORY_ACCOUNT_ID, }); await waitForBatchedUpdates(); @@ -794,6 +796,7 @@ describe('actions/IOU/DeleteMoneyRequest', () => { personalDetails: allPersonalDetails, newReportObject: thread, parentReportActionID: createIOUAction?.reportActionID, + currentUserAccountID: RORY_ACCOUNT_ID, }); await waitForBatchedUpdates(); @@ -942,6 +945,7 @@ describe('actions/IOU/DeleteMoneyRequest', () => { personalDetails: allPersonalDetails, newReportObject: thread, parentReportActionID: createIOUAction?.reportActionID, + currentUserAccountID: RORY_ACCOUNT_ID, }); await waitForBatchedUpdates(); @@ -1265,6 +1269,7 @@ describe('actions/IOU/DeleteMoneyRequest', () => { personalDetails: allPersonalDetails, newReportObject: thread, parentReportActionID: createIOUAction?.reportActionID, + currentUserAccountID: RORY_ACCOUNT_ID, }); await waitForBatchedUpdates(); @@ -1449,6 +1454,7 @@ describe('actions/IOU/DeleteMoneyRequest', () => { personalDetails: allPersonalDetails, newReportObject: thread, parentReportActionID: createIOUAction?.reportActionID, + currentUserAccountID: RORY_ACCOUNT_ID, }); await waitForBatchedUpdates(); diff --git a/tests/actions/IOUTest/DuplicateTest.ts b/tests/actions/IOUTest/DuplicateTest.ts index b5f5a0f7bcc2..f439cb660b3f 100644 --- a/tests/actions/IOUTest/DuplicateTest.ts +++ b/tests/actions/IOUTest/DuplicateTest.ts @@ -477,6 +477,7 @@ describe('actions/Duplicate', () => { betas: undefined, newReportObject: transactionThreadReport1, parentReportActionID: iouAction1?.reportActionID, + currentUserAccountID: RORY_ACCOUNT_ID, }); openReport({ hasReportActions: true, @@ -487,6 +488,7 @@ describe('actions/Duplicate', () => { betas: undefined, newReportObject: transactionThreadReport1, parentReportActionID: iouAction2?.reportActionID, + currentUserAccountID: RORY_ACCOUNT_ID, }); await waitForBatchedUpdates(); diff --git a/tests/actions/IOUTest/TrackExpenseTest.ts b/tests/actions/IOUTest/TrackExpenseTest.ts index 994948cf8ac4..b15f66177de3 100644 --- a/tests/actions/IOUTest/TrackExpenseTest.ts +++ b/tests/actions/IOUTest/TrackExpenseTest.ts @@ -2432,6 +2432,7 @@ describe('actions/IOU/TrackExpense', () => { personalDetails: allPersonalDetails, newReportObject: thread, parentReportActionID: createIOUAction?.reportActionID, + currentUserAccountID: RORY_ACCOUNT_ID, }); await waitForBatchedUpdates(); @@ -2545,6 +2546,7 @@ describe('actions/IOU/TrackExpense', () => { personalDetails: allPersonalDetails, newReportObject: thread, parentReportActionID: createIOUAction?.reportActionID, + currentUserAccountID: RORY_ACCOUNT_ID, }); await waitForBatchedUpdates(); diff --git a/tests/actions/MergeTransactionTest.ts b/tests/actions/MergeTransactionTest.ts index b929fc7eff3a..80985d062e03 100644 --- a/tests/actions/MergeTransactionTest.ts +++ b/tests/actions/MergeTransactionTest.ts @@ -1181,6 +1181,7 @@ describe('mergeTransactionRequest', () => { betas: undefined, newReportObject: thread, parentReportActionID: sourceIOUAction.reportActionID, + currentUserAccountID: TEST_ACCOUNT_ID, }); await waitForBatchedUpdates(); @@ -1371,6 +1372,7 @@ describe('mergeTransactionRequest', () => { betas: undefined, newReportObject: thread, parentReportActionID: sourceIOUAction.reportActionID, + currentUserAccountID: TEST_ACCOUNT_ID, }); await waitForBatchedUpdates(); diff --git a/tests/actions/ReportTest.ts b/tests/actions/ReportTest.ts index 69cc803ce3fd..b443a14ce497 100644 --- a/tests/actions/ReportTest.ts +++ b/tests/actions/ReportTest.ts @@ -625,7 +625,7 @@ describe('actions/Report', () => { // When the user visits the report currentTime = DateUtils.getDBTime(); - Report.openReport({hasReportActions: true, reportID: REPORT_ID, introSelected: TEST_INTRO_SELECTED, betas: undefined}); + Report.openReport({hasReportActions: true, reportID: REPORT_ID, introSelected: TEST_INTRO_SELECTED, betas: undefined, currentUserAccountID: USER_1_ACCOUNT_ID}); Report.readNewestAction(REPORT_ID, true); waitForBatchedUpdates(); return waitForBatchedUpdates(); @@ -1192,6 +1192,7 @@ describe('actions/Report', () => { newReportObject: { reportID: REPORT_ID, }, + currentUserAccountID: 1, }); } @@ -1211,7 +1212,7 @@ describe('actions/Report', () => { setHasRadio(false); await waitForBatchedUpdates(); - Report.openReport({hasReportActions: true, reportID: REPORT_ID, introSelected: undefined, betas: undefined}); + Report.openReport({hasReportActions: true, reportID: REPORT_ID, introSelected: undefined, betas: undefined, currentUserAccountID: 1}); await waitForBatchedUpdates(); const report = await getOnyxValue(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`); @@ -1235,6 +1236,7 @@ describe('actions/Report', () => { newReportObject: { reportID: REPORT_ID, }, + currentUserAccountID: 1, }); await waitForBatchedUpdates(); @@ -1309,6 +1311,7 @@ describe('actions/Report', () => { betas: undefined, transaction: transaction ?? undefined, parentReportID: SELF_DM_ID, + currentUserAccountID: TEST_USER_ACCOUNT_ID, }); await waitForBatchedUpdates(); @@ -1363,6 +1366,7 @@ describe('actions/Report', () => { newReportObject: { reportID: REPORT_ID, }, + currentUserAccountID: 1, }); } @@ -2341,6 +2345,7 @@ describe('actions/Report', () => { reportID: '2', }, parentReportActionID: reportActionID, + currentUserAccountID: TEST_USER_ACCOUNT_ID, }); await waitForBatchedUpdates(); @@ -4917,7 +4922,7 @@ describe('actions/Report', () => { await Onyx.set(ONYXKEYS.NVP_INTRO_SELECTED, TEST_INTRO_SELECTED); await waitForBatchedUpdates(); - Report.openReport({hasReportActions: true, reportID: REPORT_ID, introSelected: TEST_INTRO_SELECTED, betas: undefined}); + Report.openReport({hasReportActions: true, reportID: REPORT_ID, introSelected: TEST_INTRO_SELECTED, betas: undefined, currentUserAccountID: 1}); await waitForBatchedUpdates(); TestHelper.expectAPICommandToHaveBeenCalled(WRITE_COMMANDS.OPEN_REPORT, 1); @@ -4928,7 +4933,7 @@ describe('actions/Report', () => { const REPORT_ID = '2'; - Report.openReport({hasReportActions: true, reportID: REPORT_ID, introSelected: TEST_INTRO_SELECTED, betas: undefined}); + Report.openReport({hasReportActions: true, reportID: REPORT_ID, introSelected: TEST_INTRO_SELECTED, betas: undefined, currentUserAccountID: 1}); await waitForBatchedUpdates(); TestHelper.expectAPICommandToHaveBeenCalled(WRITE_COMMANDS.OPEN_REPORT, 1); @@ -4939,7 +4944,7 @@ describe('actions/Report', () => { const REPORT_ID = '3'; - Report.openReport({hasReportActions: true, reportID: REPORT_ID, introSelected: undefined, betas: undefined}); + Report.openReport({hasReportActions: true, reportID: REPORT_ID, introSelected: undefined, betas: undefined, currentUserAccountID: 1}); await waitForBatchedUpdates(); TestHelper.expectAPICommandToHaveBeenCalled(WRITE_COMMANDS.OPEN_REPORT, 1); From 4f77c3a2f8edb79841610a07cdca3dffb490f351 Mon Sep 17 00:00:00 2001 From: truph01 Date: Tue, 21 Jul 2026 18:10:43 +0700 Subject: [PATCH 2/3] refactor: rest openReport callers --- src/DeepLinkHandler.tsx | 17 +++-- src/libs/actions/Link.ts | 4 +- ...replaceOptimisticReportWithActualReport.ts | 21 ++++-- .../report/ContextMenu/ContextMenuActions.tsx | 4 +- ...aceOptimisticReportWithActualReportTest.ts | 65 ++++++++++--------- 5 files changed, 67 insertions(+), 44 deletions(-) diff --git a/src/DeepLinkHandler.tsx b/src/DeepLinkHandler.tsx index 3f23afdefabe..61f58431e1c2 100644 --- a/src/DeepLinkHandler.tsx +++ b/src/DeepLinkHandler.tsx @@ -36,7 +36,7 @@ function DeepLinkHandler({onInitialUrl}: DeepLinkHandlerProps) { const [allReports, allReportsMetadata] = useOnyx(ONYXKEYS.COLLECTION.REPORT); const [isLoadingApp = true] = useOnyx(ONYXKEYS.IS_LOADING_APP); - const [, sessionMetadata] = useOnyx(ONYXKEYS.SESSION); + const [session, sessionMetadata] = useOnyx(ONYXKEYS.SESSION); const [conciergeReportID, conciergeReportIDMetadata] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID); const [introSelected, introSelectedMetadata] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED); const [isSelfTourViewed, isSelfTourViewedMetadata] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector}); @@ -103,7 +103,16 @@ function DeepLinkHandler({onInitialUrl}: DeepLinkHandlerProps) { if (introSelected === undefined) { Log.info('[Deep link] introSelected is undefined when processing initial URL', false, {url}); } - openReportFromDeepLink(url, allReports, isCurrentlyAuthenticated, conciergeReportID, introSelected, isSelfTourViewed, betas); + openReportFromDeepLink( + url, + allReports, + isCurrentlyAuthenticated, + conciergeReportID, + introSelected, + isSelfTourViewed, + betas, + session?.accountID ?? CONST.DEFAULT_NUMBER_ID, + ); trackPendingPublicRoomFromDeepLink(url, isCurrentlyAuthenticated); } else { Report.doneCheckingPublicRoom(); @@ -131,7 +140,7 @@ function DeepLinkHandler({onInitialUrl}: DeepLinkHandlerProps) { Log.info('[Deep link] introSelected is undefined when processing URL change', false, {url: state.url}); } const isCurrentlyAuthenticated = hasAuthToken(); - openReportFromDeepLink(state.url, allReports, isCurrentlyAuthenticated, conciergeReportID, introSelected, isSelfTourViewed, betas); + openReportFromDeepLink(state.url, allReports, isCurrentlyAuthenticated, conciergeReportID, introSelected, isSelfTourViewed, betas, session?.accountID ?? CONST.DEFAULT_NUMBER_ID); trackPendingPublicRoomFromDeepLink(state.url, isCurrentlyAuthenticated); }); @@ -184,7 +193,7 @@ function DeepLinkHandler({onInitialUrl}: DeepLinkHandlerProps) { return; } hasRefetchedPublicRoom.current = true; - Report.openReport({reportID, introSelected, betas}); + Report.openReport({reportID, introSelected, betas, currentUserAccountID: session?.accountID}); }, [isLoadingApp, allReports, introSelected, betas]); return null; diff --git a/src/libs/actions/Link.ts b/src/libs/actions/Link.ts index a995f6d2ce24..a8e28429fb4d 100644 --- a/src/libs/actions/Link.ts +++ b/src/libs/actions/Link.ts @@ -459,6 +459,7 @@ function openReportFromDeepLink( introSelected: OnyxEntry, isSelfTourViewed: boolean | undefined, betas: OnyxEntry, + currentUserAccountID: number, ) { const reportID = getReportIDFromLink(url); @@ -470,8 +471,7 @@ function openReportFromDeepLink( parentSpan: getSpan(CONST.TELEMETRY.SPAN_BOOTSPLASH.PUBLIC_ROOM_CHECK), }); - // Call the OpenReport command to check in the server if it's a public room. If so, we'll open it as an anonymous user - openReport({reportID, introSelected, parentReportActionID: '0', isFromDeepLink: true, betas, hasReportActions: false}); + openReport({reportID, introSelected, parentReportActionID: '0', isFromDeepLink: true, betas, hasReportActions: false, currentUserAccountID}); // Show the sign-in page if the app is offline if (getIsOffline()) { diff --git a/src/libs/actions/replaceOptimisticReportWithActualReport.ts b/src/libs/actions/replaceOptimisticReportWithActualReport.ts index 06db72611bf4..2457ec52c746 100644 --- a/src/libs/actions/replaceOptimisticReportWithActualReport.ts +++ b/src/libs/actions/replaceOptimisticReportWithActualReport.ts @@ -2,6 +2,7 @@ import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; import TransitionTracker from '@libs/Navigation/TransitionTracker'; import {isMoneyRequest, isMoneyRequestReport, isOneTransactionReport} from '@libs/ReportUtils'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; @@ -47,6 +48,14 @@ Onyx.connectWithoutView({ let allReports: OnyxCollection; +let sessionAccountID: number | undefined; +Onyx.connectWithoutView({ + key: ONYXKEYS.SESSION, + callback: (value) => { + sessionAccountID = value?.accountID; + }, +}); + const allReportActions: OnyxCollection = {}; // Report actions are cached only to resolve parent actions for IOU cleanup; no UI subscribes, so connectWithoutView() is used. Onyx.connectWithoutView({ @@ -60,7 +69,7 @@ Onyx.connectWithoutView({ }, }); -function replaceOptimisticReportWithActualReport(report: Report, draftReportComment: string | undefined) { +function replaceOptimisticReportWithActualReport(report: Report, draftReportComment: string | undefined, currentUserAccountID: number) { const {reportID, preexistingReportID, parentReportID, parentReportActionID} = report; if (!reportID || !preexistingReportID) { @@ -215,7 +224,7 @@ function replaceOptimisticReportWithActualReport(report: Report, draftReportComm // betas is safe to pass as undefined because introSelected is undefined, so the code path // that uses betas is never reached. Passing it explicitly so the compiler flags this when // betas becomes required. Refactor issue: https://github.com/Expensify/App/issues/66424 - openReport({reportID: parentReportID, introSelected: undefined, betas: undefined, hasReportActions}); + openReport({reportID: parentReportID, introSelected: undefined, betas: undefined, hasReportActions, currentUserAccountID}); }); } else { callback(); @@ -224,7 +233,7 @@ function replaceOptimisticReportWithActualReport(report: Report, draftReportComm // betas is safe to pass as undefined because introSelected is undefined, so the code path // that uses betas is never reached. Passing it explicitly so the compiler flags this when // betas becomes required. Refactor issue: https://github.com/Expensify/App/issues/66424 - openReport({reportID: parentReportID, introSelected: undefined, betas: undefined, hasReportActions}); + openReport({reportID: parentReportID, introSelected: undefined, betas: undefined, hasReportActions, currentUserAccountID}); } return; } @@ -257,7 +266,11 @@ Onyx.connectWithoutView({ continue; } - replaceOptimisticReportWithActualReport(report, allReportDraftComments?.[`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${report.reportID}`]); + replaceOptimisticReportWithActualReport( + report, + allReportDraftComments?.[`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${report.reportID}`], + sessionAccountID ?? CONST.DEFAULT_NUMBER_ID, + ); } }, }); diff --git a/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx b/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx index a78ff43799c1..a9e35f0b20b9 100644 --- a/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx +++ b/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx @@ -607,11 +607,11 @@ const ContextMenuActions: ContextMenuAction[] = [ (canEditReportAction(reportAction, iouTransaction) || canEditReportAction(moneyRequestAction, iouTransaction)) && !isArchivedRoom && !isChronosReport, - onPress: (closePopover, {reportID, originalReportID, reportAction, moneyRequestAction, introSelected, betas, childReportActions}) => { + onPress: (closePopover, {reportID, originalReportID, reportAction, moneyRequestAction, introSelected, betas, childReportActions, currentUserAccountID}) => { if (isMoneyRequestAction(reportAction) || isMoneyRequestAction(moneyRequestAction)) { const editExpense = () => { const childReportID = reportAction?.childReportID; - openReport({reportID: childReportID, introSelected, betas, hasReportActions: !!childReportActions}); + openReport({reportID: childReportID, introSelected, betas, hasReportActions: !!childReportActions, currentUserAccountID}); Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(childReportID)); }; if (closePopover) { diff --git a/tests/actions/ReplaceOptimisticReportWithActualReportTest.ts b/tests/actions/ReplaceOptimisticReportWithActualReportTest.ts index 1590b5c2c864..7aa97d2d1a6e 100644 --- a/tests/actions/ReplaceOptimisticReportWithActualReportTest.ts +++ b/tests/actions/ReplaceOptimisticReportWithActualReportTest.ts @@ -56,6 +56,7 @@ describe('replaceOptimisticReportWithActualReport', () => { beforeEach(async () => { await Onyx.clear(); await waitForBatchedUpdates(); + await Onyx.set(ONYXKEYS.SESSION, {accountID: 1}); // Reset navigation mocks to default values mockIsReady.mockReturnValue(false); mockGetActiveRoute.mockReturnValue(''); @@ -70,7 +71,7 @@ describe('replaceOptimisticReportWithActualReport', () => { report.reportID = ''; report.preexistingReportID = '2'; - replaceOptimisticReportWithActualReport(report, undefined); + replaceOptimisticReportWithActualReport(report, undefined, 1); await waitForBatchedUpdates(); @@ -83,7 +84,7 @@ describe('replaceOptimisticReportWithActualReport', () => { report.reportID = '1'; report.preexistingReportID = undefined; - replaceOptimisticReportWithActualReport(report, undefined); + replaceOptimisticReportWithActualReport(report, undefined, 1); await waitForBatchedUpdates(); @@ -145,7 +146,7 @@ describe('replaceOptimisticReportWithActualReport', () => { await waitForBatchedUpdates(); // When replaceOptimisticReportWithActualReport is called - replaceOptimisticReportWithActualReport(report, undefined); + replaceOptimisticReportWithActualReport(report, undefined, 1); await waitForBatchedUpdates(); @@ -181,7 +182,7 @@ describe('replaceOptimisticReportWithActualReport', () => { await waitForBatchedUpdates(); // When replaceOptimisticReportWithActualReport is called - replaceOptimisticReportWithActualReport(optimisticReport, undefined); + replaceOptimisticReportWithActualReport(optimisticReport, undefined, 1); await waitForBatchedUpdates(); @@ -217,7 +218,7 @@ describe('replaceOptimisticReportWithActualReport', () => { await waitForBatchedUpdates(); // When replaceOptimisticReportWithActualReport is called - replaceOptimisticReportWithActualReport(optimisticReport, undefined); + replaceOptimisticReportWithActualReport(optimisticReport, undefined, 1); await waitForBatchedUpdates(); @@ -257,7 +258,7 @@ describe('replaceOptimisticReportWithActualReport', () => { await waitForBatchedUpdates(); // When replaceOptimisticReportWithActualReport is called - replaceOptimisticReportWithActualReport(optimisticReport, undefined); + replaceOptimisticReportWithActualReport(optimisticReport, undefined, 1); await waitForBatchedUpdates(); @@ -296,7 +297,7 @@ describe('replaceOptimisticReportWithActualReport', () => { await waitForBatchedUpdates(); // When replaceOptimisticReportWithActualReport is called - replaceOptimisticReportWithActualReport(optimisticReport, undefined); + replaceOptimisticReportWithActualReport(optimisticReport, undefined, 1); await waitForBatchedUpdates(); @@ -369,7 +370,7 @@ describe('replaceOptimisticReportWithActualReport', () => { // When replaceOptimisticReportWithActualReport is called const report = await getOnyxValue(`${ONYXKEYS.COLLECTION.REPORT}${optimisticReportID}`); if (report) { - replaceOptimisticReportWithActualReport(report, undefined); + replaceOptimisticReportWithActualReport(report, undefined, 1); } await waitForBatchedUpdates(); @@ -448,7 +449,7 @@ describe('replaceOptimisticReportWithActualReport', () => { // When replaceOptimisticReportWithActualReport is called const report = await getOnyxValue(`${ONYXKEYS.COLLECTION.REPORT}${optimisticReportID}`); if (report) { - replaceOptimisticReportWithActualReport(report, undefined); + replaceOptimisticReportWithActualReport(report, undefined, 1); } await waitForBatchedUpdates(); @@ -508,7 +509,7 @@ describe('replaceOptimisticReportWithActualReport', () => { // When replaceOptimisticReportWithActualReport is called const report = await getOnyxValue(`${ONYXKEYS.COLLECTION.REPORT}${optimisticReportID}`); if (report) { - replaceOptimisticReportWithActualReport(report, undefined); + replaceOptimisticReportWithActualReport(report, undefined, 1); } await waitForBatchedUpdates(); @@ -543,7 +544,7 @@ describe('replaceOptimisticReportWithActualReport', () => { await waitForBatchedUpdates(); // When replaceOptimisticReportWithActualReport is called with a draft comment - replaceOptimisticReportWithActualReport(optimisticReport, draftComment); + replaceOptimisticReportWithActualReport(optimisticReport, draftComment, 1); await waitForBatchedUpdates(); @@ -615,7 +616,7 @@ describe('replaceOptimisticReportWithActualReport', () => { await waitForBatchedUpdates(); // When replaceOptimisticReportWithActualReport is called with a draft comment - replaceOptimisticReportWithActualReport(optimisticReport, draftComment); + replaceOptimisticReportWithActualReport(optimisticReport, draftComment, 1); await waitForBatchedUpdates(); @@ -665,7 +666,7 @@ describe('replaceOptimisticReportWithActualReport', () => { await waitForBatchedUpdates(); // When replaceOptimisticReportWithActualReport is called with a draft comment - replaceOptimisticReportWithActualReport(optimisticReport, draftComment); + replaceOptimisticReportWithActualReport(optimisticReport, draftComment, 1); await waitForBatchedUpdates(); @@ -697,7 +698,7 @@ describe('replaceOptimisticReportWithActualReport', () => { await waitForBatchedUpdates(); // When replaceOptimisticReportWithActualReport is called with the draft comment - replaceOptimisticReportWithActualReport(optimisticReport, draftComment); + replaceOptimisticReportWithActualReport(optimisticReport, draftComment, 1); await waitForBatchedUpdates(); @@ -732,7 +733,7 @@ describe('replaceOptimisticReportWithActualReport', () => { }); // When replaceOptimisticReportWithActualReport is called - replaceOptimisticReportWithActualReport(optimisticReport, undefined); + replaceOptimisticReportWithActualReport(optimisticReport, undefined, 1); await waitForBatchedUpdates(); // Then the switchToPreExistingReport event should be emitted @@ -797,7 +798,7 @@ describe('replaceOptimisticReportWithActualReport', () => { }); // When replaceOptimisticReportWithActualReport is called and the callback is executed - replaceOptimisticReportWithActualReport(optimisticReport, undefined); + replaceOptimisticReportWithActualReport(optimisticReport, undefined, 1); await waitForBatchedUpdates(); capturedEventData?.callback(); @@ -849,7 +850,7 @@ describe('replaceOptimisticReportWithActualReport', () => { }); // When replaceOptimisticReportWithActualReport is called and the callback is executed - replaceOptimisticReportWithActualReport(optimisticReport, undefined); + replaceOptimisticReportWithActualReport(optimisticReport, undefined, 1); await waitForBatchedUpdates(); capturedEventData?.callback(); @@ -908,7 +909,7 @@ describe('replaceOptimisticReportWithActualReport', () => { }); // When replaceOptimisticReportWithActualReport is called and the callback is executed - replaceOptimisticReportWithActualReport(optimisticReport, undefined); + replaceOptimisticReportWithActualReport(optimisticReport, undefined, 1); await waitForBatchedUpdates(); capturedEventData?.callback(); @@ -969,7 +970,7 @@ describe('replaceOptimisticReportWithActualReport', () => { }); // When replaceOptimisticReportWithActualReport is called and the callback is executed - replaceOptimisticReportWithActualReport(optimisticReport, undefined); + replaceOptimisticReportWithActualReport(optimisticReport, undefined, 1); await waitForBatchedUpdates(); // Then the switch event is emitted (the focused optimistic report is recognized on the RHP route) @@ -1014,7 +1015,7 @@ describe('replaceOptimisticReportWithActualReport', () => { }); // When replaceOptimisticReportWithActualReport is called and the callback is executed - replaceOptimisticReportWithActualReport(optimisticReport, undefined); + replaceOptimisticReportWithActualReport(optimisticReport, undefined, 1); await waitForBatchedUpdates(); capturedEventData?.callback(); @@ -1067,7 +1068,7 @@ describe('replaceOptimisticReportWithActualReport', () => { }); // When replaceOptimisticReportWithActualReport is called - replaceOptimisticReportWithActualReport(optimisticReport, undefined); + replaceOptimisticReportWithActualReport(optimisticReport, undefined, 1); await waitForBatchedUpdates(); // Then the emitted event should have the parent IOU report as reportToCopyDraftTo @@ -1102,7 +1103,7 @@ describe('replaceOptimisticReportWithActualReport', () => { }); // When replaceOptimisticReportWithActualReport is called - replaceOptimisticReportWithActualReport(optimisticReport, undefined); + replaceOptimisticReportWithActualReport(optimisticReport, undefined, 1); await waitForBatchedUpdates(); // Then the switchToPreExistingReport event should NOT be emitted @@ -1151,11 +1152,11 @@ describe('replaceOptimisticReportWithActualReport', () => { await waitForBatchedUpdates(); // When replaceOptimisticReportWithActualReport is called - replaceOptimisticReportWithActualReport(optimisticReport, undefined); + replaceOptimisticReportWithActualReport(optimisticReport, undefined, 1); await waitForBatchedUpdates(); // Then openReport should be called with the parent IOU report ID - expect(mockOpenReport).toHaveBeenCalledWith({reportID: iouReportID, introSelected: undefined, betas: undefined, hasReportActions: true}); + expect(mockOpenReport).toHaveBeenCalledWith({reportID: iouReportID, introSelected: undefined, betas: undefined, hasReportActions: true, currentUserAccountID: 1}); // And the optimistic report should be cleared const deletedReport = await getOnyxValue(`${ONYXKEYS.COLLECTION.REPORT}${optimisticReportID}`); @@ -1199,7 +1200,7 @@ describe('replaceOptimisticReportWithActualReport', () => { await waitForBatchedUpdates(); // When replaceOptimisticReportWithActualReport is called with a draft comment - replaceOptimisticReportWithActualReport(optimisticReport, draftComment); + replaceOptimisticReportWithActualReport(optimisticReport, draftComment, 1); await waitForBatchedUpdates(); // Then the draft should be transferred to the parent IOU report @@ -1207,7 +1208,7 @@ describe('replaceOptimisticReportWithActualReport', () => { expect(parentDraft).toBe(draftComment); // And openReport should be called after the draft is saved - expect(mockOpenReport).toHaveBeenCalledWith({reportID: iouReportID, introSelected: undefined, betas: undefined, hasReportActions: true}); + expect(mockOpenReport).toHaveBeenCalledWith({reportID: iouReportID, introSelected: undefined, betas: undefined, hasReportActions: true, currentUserAccountID: 1}); // And the optimistic report should be cleared const deletedReport = await getOnyxValue(`${ONYXKEYS.COLLECTION.REPORT}${optimisticReportID}`); @@ -1250,11 +1251,11 @@ describe('replaceOptimisticReportWithActualReport', () => { await waitForBatchedUpdates(); // When replaceOptimisticReportWithActualReport is called - replaceOptimisticReportWithActualReport(optimisticReport, undefined); + replaceOptimisticReportWithActualReport(optimisticReport, undefined, 1); await waitForBatchedUpdates(); // Then openReport should be called with the parent IOU report ID - expect(mockOpenReport).toHaveBeenCalledWith({reportID: iouReportID, introSelected: undefined, betas: undefined, hasReportActions: true}); + expect(mockOpenReport).toHaveBeenCalledWith({reportID: iouReportID, introSelected: undefined, betas: undefined, hasReportActions: true, currentUserAccountID: 1}); }); it('should transfer draft to parent IOU report and call openReport when user is on search report view with draft comment', async () => { @@ -1294,7 +1295,7 @@ describe('replaceOptimisticReportWithActualReport', () => { await waitForBatchedUpdates(); // When replaceOptimisticReportWithActualReport is called with a draft comment - replaceOptimisticReportWithActualReport(optimisticReport, draftComment); + replaceOptimisticReportWithActualReport(optimisticReport, draftComment, 1); await waitForBatchedUpdates(); // Then the draft should be transferred to the parent IOU report @@ -1302,7 +1303,7 @@ describe('replaceOptimisticReportWithActualReport', () => { expect(parentDraft).toBe(draftComment); // And openReport should be called after the draft is saved - expect(mockOpenReport).toHaveBeenCalledWith({reportID: iouReportID, introSelected: undefined, betas: undefined, hasReportActions: true}); + expect(mockOpenReport).toHaveBeenCalledWith({reportID: iouReportID, introSelected: undefined, betas: undefined, hasReportActions: true, currentUserAccountID: 1}); // And the optimistic report should be cleared const deletedReport = await getOnyxValue(`${ONYXKEYS.COLLECTION.REPORT}${optimisticReportID}`); @@ -1346,7 +1347,7 @@ describe('replaceOptimisticReportWithActualReport', () => { await waitForBatchedUpdates(); // When replaceOptimisticReportWithActualReport is called - replaceOptimisticReportWithActualReport(optimisticReport, undefined); + replaceOptimisticReportWithActualReport(optimisticReport, undefined, 1); await waitForBatchedUpdates(); // Then the optimistic parent IOU action should be deleted @@ -1390,7 +1391,7 @@ describe('replaceOptimisticReportWithActualReport', () => { await waitForBatchedUpdates(); // When replaceOptimisticReportWithActualReport is called - replaceOptimisticReportWithActualReport(optimisticReport, undefined); + replaceOptimisticReportWithActualReport(optimisticReport, undefined, 1); await waitForBatchedUpdates(); // Then the non-optimistic parent IOU action should NOT be deleted From 1d69bd4b04c6a566f56a24407c95d7fb5138a4c4 Mon Sep 17 00:00:00 2001 From: truph01 Date: Tue, 21 Jul 2026 18:24:57 +0700 Subject: [PATCH 3/3] fix: lint --- src/DeepLinkHandler.tsx | 2 +- src/libs/actions/Link.ts | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/DeepLinkHandler.tsx b/src/DeepLinkHandler.tsx index 61f58431e1c2..a7d5fdebd63a 100644 --- a/src/DeepLinkHandler.tsx +++ b/src/DeepLinkHandler.tsx @@ -194,7 +194,7 @@ function DeepLinkHandler({onInitialUrl}: DeepLinkHandlerProps) { } hasRefetchedPublicRoom.current = true; Report.openReport({reportID, introSelected, betas, currentUserAccountID: session?.accountID}); - }, [isLoadingApp, allReports, introSelected, betas]); + }, [isLoadingApp, allReports, introSelected, betas, session?.accountID]); return null; } diff --git a/src/libs/actions/Link.ts b/src/libs/actions/Link.ts index a8e28429fb4d..b8de99b9b87c 100644 --- a/src/libs/actions/Link.ts +++ b/src/libs/actions/Link.ts @@ -42,13 +42,11 @@ import {canAnonymousUserAccessRoute, isAnonymousUser, signOutAndRedirectToSignIn import {setOnboardingErrorMessage} from './Welcome'; let currentUserEmail = ''; -let currentUserAccountID = -1; // Use connectWithoutView since this is to open an external link and doesn't affect any UI Onyx.connectWithoutView({ key: ONYXKEYS.SESSION, callback: (value) => { currentUserEmail = value?.email ?? ''; - currentUserAccountID = value?.accountID ?? CONST.DEFAULT_NUMBER_ID; }, });