From be2e732417729a328341425edc71cc4f60163e7d Mon Sep 17 00:00:00 2001
From: "I.K." <54219858+M00rish@users.noreply.github.com>
Date: Wed, 7 Jan 2026 12:02:29 +0000
Subject: [PATCH 01/11] show upgrade first
---
.../ReimbursementAccountPage.tsx | 4 +-
src/pages/Search/SearchPage.tsx | 55 ++++++++++++++++++-
2 files changed, 57 insertions(+), 2 deletions(-)
diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx b/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx
index 6d52954267870..6b0ac9fbcc88c 100644
--- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx
+++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx
@@ -22,6 +22,7 @@ import usePrevious from '@hooks/usePrevious';
import useRootNavigationState from '@hooks/useRootNavigationState';
import useThemeStyles from '@hooks/useThemeStyles';
import {isCurrencySupportedForECards} from '@libs/CardUtils';
+import Log from '@libs/Log';
import Navigation from '@libs/Navigation/Navigation';
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {ReimbursementAccountNavigatorParamList} from '@libs/Navigation/types';
@@ -288,6 +289,7 @@ function ReimbursementAccountPage({route, policy, isLoadingPolicy, navigation}:
// Update the data that is returned from back-end to draft value
const draftStep = reimbursementAccount?.draftStep;
+ Log.hmmm('draftStep', draftStep);
if (draftStep) {
updateReimbursementAccountDraft(getBankAccountFields(getFieldsForStep(draftStep)));
}
@@ -451,7 +453,7 @@ function ReimbursementAccountPage({route, policy, isLoadingPolicy, navigation}:
// or when data is being loaded. Don't show the loading indicator if we're offline and restarted the bank account setup process
// On Android, when we open the app from the background, Onfido activity gets destroyed, so we need to reopen it.
// eslint-disable-next-line react-compiler/react-compiler
- if ((!hasACHDataBeenLoaded || isLoading) && shouldShowOfflineLoader && (shouldReopenOnfido || !requestorStepRef?.current)) {
+ if (!hasACHDataBeenLoaded && isLoading && shouldShowOfflineLoader && (shouldReopenOnfido || !requestorStepRef?.current)) {
return ;
}
diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx
index 69b0475351210..f7abe5c64f3a9 100644
--- a/src/pages/Search/SearchPage.tsx
+++ b/src/pages/Search/SearchPage.tsx
@@ -30,6 +30,7 @@ import useMobileSelectionMode from '@hooks/useMobileSelectionMode';
import useNetwork from '@hooks/useNetwork';
import useOnyx from '@hooks/useOnyx';
import usePermissions from '@hooks/usePermissions';
+import usePolicyForMovingExpenses from '@hooks/usePolicyForMovingExpenses';
import usePrevious from '@hooks/usePrevious';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useTheme from '@hooks/useTheme';
@@ -77,6 +78,7 @@ import {
isExpenseReport as isExpenseReportUtil,
isInvoiceReport,
isIOUReport as isIOUReportUtil,
+ isTrackExpenseReport,
} from '@libs/ReportUtils';
import {buildSearchQueryJSON} from '@libs/SearchQueryUtils';
import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils';
@@ -269,6 +271,43 @@ function SearchPage({route}: SearchPageProps) {
[queryJSON, selectedTransactionsKeys, areAllMatchingItemsSelected, selectedTransactionReportIDs],
);
+ const selectedTransactionReport = useMemo(() => {
+ if (!selectedTransactionsKeys.length) {
+ return null;
+ }
+
+ const firstTransactionID = selectedTransactionsKeys.at(0);
+
+ if (!firstTransactionID) {
+ return null;
+ }
+
+ const transaction = selectedTransactions[firstTransactionID];
+
+ if (!transaction || typeof transaction !== 'object' || !('reportID' in transaction)) {
+ return null;
+ }
+
+ return getReportOrDraftReport(transaction.reportID);
+ }, [selectedTransactionsKeys, selectedTransactions]);
+
+ const iouType = useMemo(() => {
+ if (!selectedTransactionReport) {
+ return CONST.IOU.TYPE.SUBMIT;
+ }
+
+ if (isTrackExpenseReport(selectedTransactionReport)) {
+ return CONST.IOU.TYPE.TRACK;
+ }
+ if (isInvoiceReport(selectedTransactionReport)) {
+ return CONST.IOU.TYPE.INVOICE;
+ }
+ return CONST.IOU.TYPE.SUBMIT;
+ }, [selectedTransactionReport]);
+
+ const {policyForMovingExpenses, shouldSelectPolicy} = usePolicyForMovingExpenses();
+ const shouldNavigateToUpgradePath = !policyForMovingExpenses && !shouldSelectPolicy;
+
const policyIDsWithVBBA = useMemo(() => {
return Object.values(policies ?? {})
.filter((policy): policy is Policy => !!policy?.achAccount?.bankAccountID)
@@ -764,7 +803,21 @@ function SearchPage({route}: SearchPageProps) {
icon: expensifyIcons.DocumentMerge,
value: CONST.SEARCH.BULK_ACTION_TYPES.CHANGE_REPORT,
shouldCloseModalOnSelect: true,
- onSelected: () => Navigation.navigate(ROUTES.MOVE_TRANSACTIONS_SEARCH_RHP),
+ onSelected: () => {
+ if (shouldNavigateToUpgradePath && selectedTransactionsKeys.length > 0) {
+ Navigation.navigate(
+ ROUTES.MONEY_REQUEST_UPGRADE.getRoute({
+ action: CONST.IOU.ACTION.EDIT,
+ iouType,
+ transactionID: selectedTransactionsKeys.at(0),
+ reportID: selectedTransactions[selectedTransactionsKeys[0]].reportID,
+ upgradePath: CONST.UPGRADE_PATHS.REPORTS,
+ }),
+ );
+ return;
+ }
+ Navigation.navigate(ROUTES.MOVE_TRANSACTIONS_SEARCH_RHP);
+ },
});
}
From 47c974e9b659953718b03f0cab5f3225a01d93a5 Mon Sep 17 00:00:00 2001
From: "I.K." <54219858+M00rish@users.noreply.github.com>
Date: Wed, 14 Jan 2026 13:47:40 +0000
Subject: [PATCH 02/11] fix bulk move and navigation
---
.../ReimbursementAccountPage.tsx | 2 -
src/pages/Search/SearchPage.tsx | 55 +--------------
.../Search/SearchTransactionsChangeReport.tsx | 16 +++++
.../request/step/IOURequestStepUpgrade.tsx | 70 +++++++++++++++++--
4 files changed, 82 insertions(+), 61 deletions(-)
diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx b/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx
index ed39c4e37e07a..39bebe2feaf72 100644
--- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx
+++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx
@@ -22,7 +22,6 @@ import usePrevious from '@hooks/usePrevious';
import useRootNavigationState from '@hooks/useRootNavigationState';
import useThemeStyles from '@hooks/useThemeStyles';
import {isCurrencySupportedForECards} from '@libs/CardUtils';
-import Log from '@libs/Log';
import Navigation from '@libs/Navigation/Navigation';
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {ReimbursementAccountNavigatorParamList} from '@libs/Navigation/types';
@@ -290,7 +289,6 @@ function ReimbursementAccountPage({route, policy, isLoadingPolicy, navigation}:
// Update the data that is returned from back-end to draft value
const draftStep = reimbursementAccount?.draftStep;
- Log.hmmm('draftStep', draftStep);
if (draftStep) {
updateReimbursementAccountDraft(getBankAccountFields(getFieldsForStep(draftStep)));
}
diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx
index b272d0d79bc08..475882508eb97 100644
--- a/src/pages/Search/SearchPage.tsx
+++ b/src/pages/Search/SearchPage.tsx
@@ -31,7 +31,6 @@ import useMobileSelectionMode from '@hooks/useMobileSelectionMode';
import useNetwork from '@hooks/useNetwork';
import useOnyx from '@hooks/useOnyx';
import usePermissions from '@hooks/usePermissions';
-import usePolicyForMovingExpenses from '@hooks/usePolicyForMovingExpenses';
import usePrevious from '@hooks/usePrevious';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useTheme from '@hooks/useTheme';
@@ -79,7 +78,6 @@ import {
isExpenseReport as isExpenseReportUtil,
isInvoiceReport,
isIOUReport as isIOUReportUtil,
- isTrackExpenseReport,
} from '@libs/ReportUtils';
import {buildSearchQueryJSON} from '@libs/SearchQueryUtils';
import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils';
@@ -284,43 +282,6 @@ function SearchPage({route}: SearchPageProps) {
[queryJSON, selectedTransactionsKeys, areAllMatchingItemsSelected, selectedTransactionReportIDs, showConfirmModal, translate, clearSelectedTransactions],
);
- const selectedTransactionReport = useMemo(() => {
- if (!selectedTransactionsKeys.length) {
- return null;
- }
-
- const firstTransactionID = selectedTransactionsKeys.at(0);
-
- if (!firstTransactionID) {
- return null;
- }
-
- const transaction = selectedTransactions[firstTransactionID];
-
- if (!transaction || typeof transaction !== 'object' || !('reportID' in transaction)) {
- return null;
- }
-
- return getReportOrDraftReport(transaction.reportID);
- }, [selectedTransactionsKeys, selectedTransactions]);
-
- const iouType = useMemo(() => {
- if (!selectedTransactionReport) {
- return CONST.IOU.TYPE.SUBMIT;
- }
-
- if (isTrackExpenseReport(selectedTransactionReport)) {
- return CONST.IOU.TYPE.TRACK;
- }
- if (isInvoiceReport(selectedTransactionReport)) {
- return CONST.IOU.TYPE.INVOICE;
- }
- return CONST.IOU.TYPE.SUBMIT;
- }, [selectedTransactionReport]);
-
- const {policyForMovingExpenses, shouldSelectPolicy} = usePolicyForMovingExpenses();
- const shouldNavigateToUpgradePath = !policyForMovingExpenses && !shouldSelectPolicy;
-
const policyIDsWithVBBA = useMemo(() => {
return Object.values(policies ?? {})
.filter((policy): policy is Policy => !!policy?.achAccount?.bankAccountID)
@@ -922,21 +883,7 @@ function SearchPage({route}: SearchPageProps) {
icon: expensifyIcons.DocumentMerge,
value: CONST.SEARCH.BULK_ACTION_TYPES.CHANGE_REPORT,
shouldCloseModalOnSelect: true,
- onSelected: () => {
- if (shouldNavigateToUpgradePath && selectedTransactionsKeys.length > 0) {
- Navigation.navigate(
- ROUTES.MONEY_REQUEST_UPGRADE.getRoute({
- action: CONST.IOU.ACTION.EDIT,
- iouType,
- transactionID: selectedTransactionsKeys.at(0),
- reportID: selectedTransactions[selectedTransactionsKeys[0]].reportID,
- upgradePath: CONST.UPGRADE_PATHS.REPORTS,
- }),
- );
- return;
- }
- Navigation.navigate(ROUTES.MOVE_TRANSACTIONS_SEARCH_RHP);
- },
+ onSelected: () => Navigation.navigate(ROUTES.MOVE_TRANSACTIONS_SEARCH_RHP),
});
}
diff --git a/src/pages/Search/SearchTransactionsChangeReport.tsx b/src/pages/Search/SearchTransactionsChangeReport.tsx
index a5bf591fb6ad6..f7575d9f210ad 100644
--- a/src/pages/Search/SearchTransactionsChangeReport.tsx
+++ b/src/pages/Search/SearchTransactionsChangeReport.tsx
@@ -99,6 +99,22 @@ function SearchTransactionsChangeReport() {
});
const createReport = () => {
+ if (!policyForMovingExpensesID && !shouldSelectPolicy && selectedTransactionsKeys.length > 0) {
+ const firstTransactionID = selectedTransactionsKeys.at(0);
+ if (firstTransactionID) {
+ Navigation.navigate(
+ ROUTES.MONEY_REQUEST_UPGRADE.getRoute({
+ action: CONST.IOU.ACTION.EDIT,
+ iouType: CONST.IOU.TYPE.SUBMIT,
+ transactionID: firstTransactionID,
+ reportID: selectedTransactions[firstTransactionID]?.reportID,
+ upgradePath: CONST.UPGRADE_PATHS.REPORTS,
+ }),
+ );
+ }
+ return;
+ }
+
if (shouldSelectPolicy) {
Navigation.navigate(ROUTES.NEW_REPORT_WORKSPACE_SELECTION.getRoute(true));
return;
diff --git a/src/pages/iou/request/step/IOURequestStepUpgrade.tsx b/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
index bfe3d38d59607..b7722f92d0c4b 100644
--- a/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
+++ b/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
@@ -4,21 +4,25 @@ import HeaderWithBackButton from '@components/HeaderWithBackButton';
import {usePersonalDetails} from '@components/OnyxListItemProvider';
import ScreenWrapper from '@components/ScreenWrapper';
import ScrollView from '@components/ScrollView';
+import {useSearchContext} from '@components/Search/SearchContext';
import WorkspaceConfirmationForm from '@components/WorkspaceConfirmationForm';
import type {WorkspaceConfirmationSubmitFunctionParams} from '@components/WorkspaceConfirmationForm';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useOnyx from '@hooks/useOnyx';
+import usePermissions from '@hooks/usePermissions';
import usePreferredPolicy from '@hooks/usePreferredPolicy';
import useThemeStyles from '@hooks/useThemeStyles';
-import {setTransactionReport} from '@libs/actions/Transaction';
+import {createNewReport} from '@libs/actions/Report';
+import {changeTransactionsReport, setTransactionReport} from '@libs/actions/Transaction';
import type CreateWorkspaceParams from '@libs/API/parameters/CreateWorkspaceParams';
import getPlatform from '@libs/getPlatform';
import Navigation from '@libs/Navigation/Navigation';
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {MoneyRequestNavigatorParamList} from '@libs/Navigation/types';
import {getParticipantsOption} from '@libs/OptionsListUtils';
+import {hasViolations as hasViolationsReportUtils} from '@libs/ReportUtils';
import UpgradeConfirmation from '@pages/workspace/upgrade/UpgradeConfirmation';
import UpgradeIntro from '@pages/workspace/upgrade/UpgradeIntro';
import {setCustomUnitRateID, setMoneyRequestParticipants} from '@userActions/IOU';
@@ -60,6 +64,19 @@ function IOURequestStepUpgrade({
const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED, {canBeMissing: true});
const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID, {canBeMissing: true});
+ // Hooks for bulk move functionality
+ const {selectedTransactions, clearSelectedTransactions} = useSearchContext();
+ const selectedTransactionsKeys = useMemo(() => Object.keys(selectedTransactions), [selectedTransactions]);
+ const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, {canBeMissing: true});
+ const [allPolicyCategories] = useOnyx(ONYXKEYS.COLLECTION.POLICY_CATEGORIES, {canBeMissing: true});
+ const [allReportNextSteps] = useOnyx(ONYXKEYS.COLLECTION.NEXT_STEP, {canBeMissing: true});
+ const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true});
+ const [session] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: false});
+
+ const {isBetaEnabled} = usePermissions();
+ const isASAPSubmitBetaEnabled = isBetaEnabled(CONST.BETAS.ASAP_SUBMIT);
+ const hasViolations = hasViolationsReportUtils(undefined, transactionViolations, session?.accountID ?? CONST.DEFAULT_NUMBER_ID, session?.email ?? '');
+
const feature = useMemo(
() =>
Object.values(CONST.UPGRADE_FEATURE_INTRO_MAPPING)
@@ -82,6 +99,34 @@ function IOURequestStepUpgrade({
const afterUpgradeAcknowledged = useCallback(() => {
const expenseReportID = policyDataRef.current?.expenseChatReportID ?? reportID;
const policyID = policyDataRef.current?.policyID;
+
+ // Handle bulk move for REPORTS case separately - it needs to close the entire RHP flow
+ if (upgradePath === CONST.UPGRADE_PATHS.REPORTS && policyID && selectedTransactionsKeys.length > 0) {
+ // Get the newly created policy
+ const newPolicy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`];
+
+ // Create a new report for the policy
+ const optimisticReport = createNewReport(currentUserPersonalDetails, hasViolations, isASAPSubmitBetaEnabled, newPolicy, false, false);
+
+ const reportNextStep = allReportNextSteps?.[`${ONYXKEYS.COLLECTION.NEXT_STEP}${optimisticReport.reportID}`];
+
+ // Move ALL selected transactions to the new report
+ changeTransactionsReport(
+ selectedTransactionsKeys,
+ isASAPSubmitBetaEnabled,
+ session?.accountID ?? CONST.DEFAULT_NUMBER_ID,
+ session?.email ?? '',
+ optimisticReport,
+ newPolicy,
+ reportNextStep,
+ allPolicyCategories?.[`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`],
+ );
+ clearSelectedTransactions();
+
+ Navigation.dismissModal();
+ return;
+ }
+
if (shouldSubmitExpense) {
setMoneyRequestParticipants(transactionID, [
{
@@ -111,7 +156,6 @@ function IOURequestStepUpgrade({
}
case CONST.UPGRADE_PATHS.REPORTS:
navigateWithMicrotask(ROUTES.MONEY_REQUEST_STEP_REPORT.getRoute(action, CONST.IOU.TYPE.SUBMIT, transactionID, reportID));
-
break;
case CONST.UPGRADE_PATHS.CATEGORIES:
navigateWithMicrotask(backTo ?? ROUTES.MONEY_REQUEST_STEP_CATEGORY.getRoute(action, CONST.IOU.TYPE.SUBMIT, transactionID, reportID));
@@ -119,7 +163,25 @@ function IOURequestStepUpgrade({
break;
default:
}
- }, [action, backTo, navigateWithMicrotask, reportID, shouldSubmitExpense, transactionID, upgradePath]);
+ }, [
+ action,
+ backTo,
+ navigateWithMicrotask,
+ reportID,
+ shouldSubmitExpense,
+ transactionID,
+ upgradePath,
+ selectedTransactionsKeys,
+ clearSelectedTransactions,
+ hasViolations,
+ isASAPSubmitBetaEnabled,
+ allPolicies,
+ allReportNextSteps,
+ allPolicyCategories,
+ session?.accountID,
+ session?.email,
+ currentUserPersonalDetails,
+ ]);
const adminParticipant = useMemo(() => {
const participant = transaction?.participants?.[0];
@@ -177,8 +239,6 @@ function IOURequestStepUpgrade({
isRestrictedPolicyCreation,
]);
- const [session] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: false});
-
const handleConfirmUpgradeWarning = useCallback(() => {
setIsUpgradeWarningModalOpen(false);
}, []);
From d8ec8353193d60b2575baa986baf40d6bab5f9a7 Mon Sep 17 00:00:00 2001
From: "I.K." <54219858+M00rish@users.noreply.github.com>
Date: Mon, 26 Jan 2026 06:00:53 +0000
Subject: [PATCH 03/11] Update IOURequestStepUpgrade and UpgradeConfirmation
components
---
src/pages/iou/request/step/IOURequestStepUpgrade.tsx | 4 +---
src/pages/workspace/upgrade/UpgradeConfirmation.tsx | 4 ++--
2 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/src/pages/iou/request/step/IOURequestStepUpgrade.tsx b/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
index 67f3528dc9f53..9d5ab20434c6e 100644
--- a/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
+++ b/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
@@ -97,12 +97,9 @@ function IOURequestStepUpgrade({
const expenseReportID = policyDataRef.current?.expenseChatReportID ?? reportID;
const policyID = policyDataRef.current?.policyID;
- // Handle bulk move for REPORTS case separately - it needs to close the entire RHP flow
if (upgradePath === CONST.UPGRADE_PATHS.REPORTS && policyID && selectedTransactionsKeys.length > 0) {
- // Get the newly created policy
const newPolicy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`];
- // Create a new report for the policy
const optimisticReport = createNewReport(currentUserPersonalDetails, hasViolations, isASAPSubmitBetaEnabled, newPolicy, false, false);
const reportNextStep = allReportNextSteps?.[`${ONYXKEYS.COLLECTION.NEXT_STEP}${optimisticReport.reportID}`];
@@ -180,6 +177,7 @@ function IOURequestStepUpgrade({
session?.accountID,
session?.email,
currentUserPersonalDetails,
+ allTransactions,
]);
const participant = transaction?.participants?.[0];
diff --git a/src/pages/workspace/upgrade/UpgradeConfirmation.tsx b/src/pages/workspace/upgrade/UpgradeConfirmation.tsx
index 35563e7013534..821ad6ed2a49f 100644
--- a/src/pages/workspace/upgrade/UpgradeConfirmation.tsx
+++ b/src/pages/workspace/upgrade/UpgradeConfirmation.tsx
@@ -36,7 +36,7 @@ function UpgradeConfirmation({policyName, afterUpgradeAcknowledged, isReporting,
}, [updateSubscriptionLink]);
const description = useMemo(() => {
- if (isCategorizing ?? isReporting) {
+ if (isCategorizing || isReporting) {
return {translate('workspace.upgrade.completed.categorizeMessage')};
}
@@ -56,7 +56,7 @@ function UpgradeConfirmation({policyName, afterUpgradeAcknowledged, isReporting,
}, [isDistanceRateUpgrade, isCategorizing, isReporting, isTravelUpgrade, policyName, styles.renderHTML, styles.textAlignCenter, styles.w100, translate, subscriptionLink]);
const heading = useMemo(() => {
- if (isCategorizing ?? isReporting) {
+ if (isCategorizing || isReporting) {
return translate('workspace.upgrade.completed.createdWorkspace');
}
return translate('workspace.upgrade.completed.headline');
From 0ecce10e3cee5aee1e94e6bc8bee708544a71535 Mon Sep 17 00:00:00 2001
From: "I.K." <54219858+M00rish@users.noreply.github.com>
Date: Wed, 28 Jan 2026 04:55:53 +0000
Subject: [PATCH 04/11] lint
---
src/pages/Search/SearchTransactionsChangeReport.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/pages/Search/SearchTransactionsChangeReport.tsx b/src/pages/Search/SearchTransactionsChangeReport.tsx
index d20bead104b54..7cfb24308f7dc 100644
--- a/src/pages/Search/SearchTransactionsChangeReport.tsx
+++ b/src/pages/Search/SearchTransactionsChangeReport.tsx
@@ -124,7 +124,7 @@ function SearchTransactionsChangeReport() {
action: CONST.IOU.ACTION.EDIT,
iouType: CONST.IOU.TYPE.SUBMIT,
transactionID: firstTransactionID,
- reportID: selectedTransactions[firstTransactionID]?.reportID,
+ reportID: selectedTransactions[firstTransactionID]?.reportID ?? CONST.REPORT.UNREPORTED_REPORT_ID,
upgradePath: CONST.UPGRADE_PATHS.REPORTS,
}),
);
From e861d89047796335b23c17ef86c89a243256d4ff Mon Sep 17 00:00:00 2001
From: "I.K." <54219858+M00rish@users.noreply.github.com>
Date: Fri, 6 Feb 2026 03:44:03 +0000
Subject: [PATCH 05/11] Fix selectedTransactions not properly passed to
changeTransactionsReport in IOURequestStepUpgrade
---
.../request/step/IOURequestStepUpgrade.tsx | 76 +++++++++++--------
1 file changed, 46 insertions(+), 30 deletions(-)
diff --git a/src/pages/iou/request/step/IOURequestStepUpgrade.tsx b/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
index 9d5ab20434c6e..16618705452ae 100644
--- a/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
+++ b/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
@@ -1,12 +1,13 @@
-import React, {useCallback, useMemo, useRef, useState} from 'react';
+import React, { useCallback, useMemo, useRef, useState } from 'react';
+import type { OnyxCollection } from 'react-native-onyx';
import ConfirmModal from '@components/ConfirmModal';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
-import {usePersonalDetails} from '@components/OnyxListItemProvider';
+import { usePersonalDetails } from '@components/OnyxListItemProvider';
import ScreenWrapper from '@components/ScreenWrapper';
import ScrollView from '@components/ScrollView';
-import {useSearchContext} from '@components/Search/SearchContext';
+import { useSearchContext } from '@components/Search/SearchContext';
import WorkspaceConfirmationForm from '@components/WorkspaceConfirmationForm';
-import type {WorkspaceConfirmationSubmitFunctionParams} from '@components/WorkspaceConfirmationForm';
+import type { WorkspaceConfirmationSubmitFunctionParams } from '@components/WorkspaceConfirmationForm';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
@@ -14,41 +15,42 @@ import useOnyx from '@hooks/useOnyx';
import usePermissions from '@hooks/usePermissions';
import usePreferredPolicy from '@hooks/usePreferredPolicy';
import useThemeStyles from '@hooks/useThemeStyles';
-import {createNewReport} from '@libs/actions/Report';
-import {changeTransactionsReport, setTransactionReport} from '@libs/actions/Transaction';
+import { createNewReport } from '@libs/actions/Report';
+import { changeTransactionsReport, setTransactionReport } from '@libs/actions/Transaction';
import type CreateWorkspaceParams from '@libs/API/parameters/CreateWorkspaceParams';
import getPlatform from '@libs/getPlatform';
import Navigation from '@libs/Navigation/Navigation';
-import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
-import type {MoneyRequestNavigatorParamList} from '@libs/Navigation/types';
-import {getParticipantsOption} from '@libs/OptionsListUtils';
-import {hasViolations as hasViolationsReportUtils} from '@libs/ReportUtils';
+import type { PlatformStackScreenProps } from '@libs/Navigation/PlatformStackNavigation/types';
+import type { MoneyRequestNavigatorParamList } from '@libs/Navigation/types';
+import { getParticipantsOption } from '@libs/OptionsListUtils';
+import { hasViolations as hasViolationsReportUtils } from '@libs/ReportUtils';
import UpgradeConfirmation from '@pages/workspace/upgrade/UpgradeConfirmation';
import UpgradeIntro from '@pages/workspace/upgrade/UpgradeIntro';
-import {setCustomUnitRateID, setMoneyRequestParticipants} from '@userActions/IOU';
+import { setCustomUnitRateID, setMoneyRequestParticipants } from '@userActions/IOU';
import CONST from '@src/CONST';
import * as Policy from '@src/libs/actions/Policy/Policy';
import ONYXKEYS from '@src/ONYXKEYS';
-import type {Route} from '@src/ROUTES';
+import type { Route } from '@src/ROUTES';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
+import type { Transaction } from '@src/types/onyx';
type IOURequestStepUpgradeProps = PlatformStackScreenProps;
function IOURequestStepUpgrade({
route: {
- params: {transactionID, action, reportID, shouldSubmitExpense, upgradePath, backTo},
+ params: { transactionID, action, reportID, shouldSubmitExpense, upgradePath, backTo },
},
}: IOURequestStepUpgradeProps) {
const styles = useThemeStyles();
- const {translate} = useLocalize();
- const {isOffline} = useNetwork();
+ const { translate } = useLocalize();
+ const { isOffline } = useNetwork();
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
const personalDetails = usePersonalDetails();
- const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {canBeMissing: true});
- const [onboardingPurposeSelected] = useOnyx(ONYXKEYS.ONBOARDING_PURPOSE_SELECTED, {canBeMissing: true});
+ const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, { canBeMissing: true });
+ const [onboardingPurposeSelected] = useOnyx(ONYXKEYS.ONBOARDING_PURPOSE_SELECTED, { canBeMissing: true });
const [isUpgraded, setIsUpgraded] = useState(false);
const [showConfirmationForm, setShowConfirmationForm] = useState(false);
@@ -60,21 +62,35 @@ function IOURequestStepUpgrade({
const isReporting = upgradePath === CONST.UPGRADE_PATHS.REPORTS;
const platform = getPlatform();
const isWeb = platform === CONST.PLATFORM.WEB;
- const {isRestrictedPolicyCreation} = usePreferredPolicy();
- const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED, {canBeMissing: true});
- const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID, {canBeMissing: true});
+ const { isRestrictedPolicyCreation } = usePreferredPolicy();
+ const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED, { canBeMissing: true });
+ const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID, { canBeMissing: true });
// Hooks for bulk move functionality
- const {selectedTransactions, clearSelectedTransactions} = useSearchContext();
+ const { selectedTransactions, clearSelectedTransactions } = useSearchContext();
const selectedTransactionsKeys = useMemo(() => Object.keys(selectedTransactions), [selectedTransactions]);
- const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, {canBeMissing: true});
- const [allPolicyCategories] = useOnyx(ONYXKEYS.COLLECTION.POLICY_CATEGORIES, {canBeMissing: true});
- const [allReportNextSteps] = useOnyx(ONYXKEYS.COLLECTION.NEXT_STEP, {canBeMissing: true});
- const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true});
- const [allTransactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION, {canBeMissing: true});
- const [session] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: false});
+ const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, { canBeMissing: true });
+ const [allPolicyCategories] = useOnyx(ONYXKEYS.COLLECTION.POLICY_CATEGORIES, { canBeMissing: true });
+ const [allReportNextSteps] = useOnyx(ONYXKEYS.COLLECTION.NEXT_STEP, { canBeMissing: true });
+ const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, { canBeMissing: true });
+ const [session] = useOnyx(ONYXKEYS.SESSION, { canBeMissing: false });
- const {isBetaEnabled} = usePermissions();
+ // Build transactions map from selectedTransactions (search results) instead of Onyx TRANSACTION collection
+ // This ensures that transactions selected from search are properly included in the map passed to changeTransactionsReport
+ const allTransactions = useMemo(
+ () =>
+ Object.values(selectedTransactions).reduce(
+ (transactionsCollection, transactionItem) => {
+ // eslint-disable-next-line no-param-reassign
+ transactionsCollection[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionItem.transaction.transactionID}`] = transactionItem.transaction;
+ return transactionsCollection;
+ },
+ {} as NonNullable>,
+ ),
+ [selectedTransactions],
+ );
+
+ const { isBetaEnabled } = usePermissions();
const isASAPSubmitBetaEnabled = isBetaEnabled(CONST.BETAS.ASAP_SUBMIT);
const hasViolations = hasViolationsReportUtils(undefined, transactionViolations, session?.accountID ?? CONST.DEFAULT_NUMBER_ID, session?.email ?? '');
@@ -142,10 +158,10 @@ function IOURequestStepUpgrade({
if (!policyID || !reportID) {
return;
}
- setTransactionReport(transactionID, {reportID: expenseReportID}, true);
+ setTransactionReport(transactionID, { reportID: expenseReportID }, true);
// Let the confirmation step decide the distance rate because policy data is not fully available at this step
setCustomUnitRateID(transactionID, '-1');
- Navigation.setParams({reportID: expenseReportID});
+ Navigation.setParams({ reportID: expenseReportID });
navigateWithMicrotask(ROUTES.WORKSPACE_CREATE_DISTANCE_RATE_UPGRADE.getRoute(policyID, transactionID, expenseReportID));
break;
From 2f2628cb91d39e1c5570c69998d5e85d0765503d Mon Sep 17 00:00:00 2001
From: "I.K." <54219858+M00rish@users.noreply.github.com>
Date: Fri, 6 Feb 2026 03:56:49 +0000
Subject: [PATCH 06/11] lint
---
.../request/step/IOURequestStepUpgrade.tsx | 70 ++++++++++---------
1 file changed, 36 insertions(+), 34 deletions(-)
diff --git a/src/pages/iou/request/step/IOURequestStepUpgrade.tsx b/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
index 16618705452ae..897ab1d905c03 100644
--- a/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
+++ b/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
@@ -1,13 +1,13 @@
-import React, { useCallback, useMemo, useRef, useState } from 'react';
-import type { OnyxCollection } from 'react-native-onyx';
+import React, {useCallback, useMemo, useRef, useState} from 'react';
+import type {OnyxCollection} from 'react-native-onyx';
import ConfirmModal from '@components/ConfirmModal';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
-import { usePersonalDetails } from '@components/OnyxListItemProvider';
+import {usePersonalDetails} from '@components/OnyxListItemProvider';
import ScreenWrapper from '@components/ScreenWrapper';
import ScrollView from '@components/ScrollView';
-import { useSearchContext } from '@components/Search/SearchContext';
+import {useSearchContext} from '@components/Search/SearchContext';
import WorkspaceConfirmationForm from '@components/WorkspaceConfirmationForm';
-import type { WorkspaceConfirmationSubmitFunctionParams } from '@components/WorkspaceConfirmationForm';
+import type {WorkspaceConfirmationSubmitFunctionParams} from '@components/WorkspaceConfirmationForm';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
@@ -15,42 +15,42 @@ import useOnyx from '@hooks/useOnyx';
import usePermissions from '@hooks/usePermissions';
import usePreferredPolicy from '@hooks/usePreferredPolicy';
import useThemeStyles from '@hooks/useThemeStyles';
-import { createNewReport } from '@libs/actions/Report';
-import { changeTransactionsReport, setTransactionReport } from '@libs/actions/Transaction';
+import {createNewReport} from '@libs/actions/Report';
+import {changeTransactionsReport, setTransactionReport} from '@libs/actions/Transaction';
import type CreateWorkspaceParams from '@libs/API/parameters/CreateWorkspaceParams';
import getPlatform from '@libs/getPlatform';
import Navigation from '@libs/Navigation/Navigation';
-import type { PlatformStackScreenProps } from '@libs/Navigation/PlatformStackNavigation/types';
-import type { MoneyRequestNavigatorParamList } from '@libs/Navigation/types';
-import { getParticipantsOption } from '@libs/OptionsListUtils';
-import { hasViolations as hasViolationsReportUtils } from '@libs/ReportUtils';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
+import type {MoneyRequestNavigatorParamList} from '@libs/Navigation/types';
+import {getParticipantsOption} from '@libs/OptionsListUtils';
+import {hasViolations as hasViolationsReportUtils} from '@libs/ReportUtils';
import UpgradeConfirmation from '@pages/workspace/upgrade/UpgradeConfirmation';
import UpgradeIntro from '@pages/workspace/upgrade/UpgradeIntro';
-import { setCustomUnitRateID, setMoneyRequestParticipants } from '@userActions/IOU';
+import {setCustomUnitRateID, setMoneyRequestParticipants} from '@userActions/IOU';
import CONST from '@src/CONST';
import * as Policy from '@src/libs/actions/Policy/Policy';
import ONYXKEYS from '@src/ONYXKEYS';
-import type { Route } from '@src/ROUTES';
+import type {Route} from '@src/ROUTES';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
-import type { Transaction } from '@src/types/onyx';
+import type {Transaction} from '@src/types/onyx';
type IOURequestStepUpgradeProps = PlatformStackScreenProps;
function IOURequestStepUpgrade({
route: {
- params: { transactionID, action, reportID, shouldSubmitExpense, upgradePath, backTo },
+ params: {transactionID, action, reportID, shouldSubmitExpense, upgradePath, backTo},
},
}: IOURequestStepUpgradeProps) {
const styles = useThemeStyles();
- const { translate } = useLocalize();
- const { isOffline } = useNetwork();
+ const {translate} = useLocalize();
+ const {isOffline} = useNetwork();
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
const personalDetails = usePersonalDetails();
- const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, { canBeMissing: true });
- const [onboardingPurposeSelected] = useOnyx(ONYXKEYS.ONBOARDING_PURPOSE_SELECTED, { canBeMissing: true });
+ const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {canBeMissing: true});
+ const [onboardingPurposeSelected] = useOnyx(ONYXKEYS.ONBOARDING_PURPOSE_SELECTED, {canBeMissing: true});
const [isUpgraded, setIsUpgraded] = useState(false);
const [showConfirmationForm, setShowConfirmationForm] = useState(false);
@@ -62,18 +62,18 @@ function IOURequestStepUpgrade({
const isReporting = upgradePath === CONST.UPGRADE_PATHS.REPORTS;
const platform = getPlatform();
const isWeb = platform === CONST.PLATFORM.WEB;
- const { isRestrictedPolicyCreation } = usePreferredPolicy();
- const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED, { canBeMissing: true });
- const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID, { canBeMissing: true });
+ const {isRestrictedPolicyCreation} = usePreferredPolicy();
+ const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED, {canBeMissing: true});
+ const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID, {canBeMissing: true});
// Hooks for bulk move functionality
- const { selectedTransactions, clearSelectedTransactions } = useSearchContext();
+ const {selectedTransactions, clearSelectedTransactions} = useSearchContext();
const selectedTransactionsKeys = useMemo(() => Object.keys(selectedTransactions), [selectedTransactions]);
- const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, { canBeMissing: true });
- const [allPolicyCategories] = useOnyx(ONYXKEYS.COLLECTION.POLICY_CATEGORIES, { canBeMissing: true });
- const [allReportNextSteps] = useOnyx(ONYXKEYS.COLLECTION.NEXT_STEP, { canBeMissing: true });
- const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, { canBeMissing: true });
- const [session] = useOnyx(ONYXKEYS.SESSION, { canBeMissing: false });
+ const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, {canBeMissing: true});
+ const [allPolicyCategories] = useOnyx(ONYXKEYS.COLLECTION.POLICY_CATEGORIES, {canBeMissing: true});
+ const [allReportNextSteps] = useOnyx(ONYXKEYS.COLLECTION.NEXT_STEP, {canBeMissing: true});
+ const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true});
+ const [session] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: false});
// Build transactions map from selectedTransactions (search results) instead of Onyx TRANSACTION collection
// This ensures that transactions selected from search are properly included in the map passed to changeTransactionsReport
@@ -81,8 +81,10 @@ function IOURequestStepUpgrade({
() =>
Object.values(selectedTransactions).reduce(
(transactionsCollection, transactionItem) => {
- // eslint-disable-next-line no-param-reassign
- transactionsCollection[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionItem.transaction.transactionID}`] = transactionItem.transaction;
+ if (transactionItem.transaction) {
+ // eslint-disable-next-line no-param-reassign
+ transactionsCollection[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionItem.transaction.transactionID}`] = transactionItem.transaction;
+ }
return transactionsCollection;
},
{} as NonNullable>,
@@ -90,7 +92,7 @@ function IOURequestStepUpgrade({
[selectedTransactions],
);
- const { isBetaEnabled } = usePermissions();
+ const {isBetaEnabled} = usePermissions();
const isASAPSubmitBetaEnabled = isBetaEnabled(CONST.BETAS.ASAP_SUBMIT);
const hasViolations = hasViolationsReportUtils(undefined, transactionViolations, session?.accountID ?? CONST.DEFAULT_NUMBER_ID, session?.email ?? '');
@@ -116,7 +118,7 @@ function IOURequestStepUpgrade({
if (upgradePath === CONST.UPGRADE_PATHS.REPORTS && policyID && selectedTransactionsKeys.length > 0) {
const newPolicy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`];
- const optimisticReport = createNewReport(currentUserPersonalDetails, hasViolations, isASAPSubmitBetaEnabled, newPolicy, false, false);
+ const optimisticReport = createNewReport(currentUserPersonalDetails, hasViolations, isASAPSubmitBetaEnabled, newPolicy, false);
const reportNextStep = allReportNextSteps?.[`${ONYXKEYS.COLLECTION.NEXT_STEP}${optimisticReport.reportID}`];
@@ -158,10 +160,10 @@ function IOURequestStepUpgrade({
if (!policyID || !reportID) {
return;
}
- setTransactionReport(transactionID, { reportID: expenseReportID }, true);
+ setTransactionReport(transactionID, {reportID: expenseReportID}, true);
// Let the confirmation step decide the distance rate because policy data is not fully available at this step
setCustomUnitRateID(transactionID, '-1');
- Navigation.setParams({ reportID: expenseReportID });
+ Navigation.setParams({reportID: expenseReportID});
navigateWithMicrotask(ROUTES.WORKSPACE_CREATE_DISTANCE_RATE_UPGRADE.getRoute(policyID, transactionID, expenseReportID));
break;
From 9cbf2d21ac18ec70997ddb1b79bc792d29331f66 Mon Sep 17 00:00:00 2001
From: "I.K." <54219858+M00rish@users.noreply.github.com>
Date: Fri, 6 Feb 2026 04:13:40 +0000
Subject: [PATCH 07/11] Fix TypeScript errors: add null check and remove extra
false arg
---
src/pages/iou/request/step/IOURequestStepUpgrade.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/pages/iou/request/step/IOURequestStepUpgrade.tsx b/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
index 897ab1d905c03..de9673d261bf1 100644
--- a/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
+++ b/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
@@ -118,7 +118,7 @@ function IOURequestStepUpgrade({
if (upgradePath === CONST.UPGRADE_PATHS.REPORTS && policyID && selectedTransactionsKeys.length > 0) {
const newPolicy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`];
- const optimisticReport = createNewReport(currentUserPersonalDetails, hasViolations, isASAPSubmitBetaEnabled, newPolicy, false);
+ const optimisticReport = createNewReport(currentUserPersonalDetails, hasViolations, isASAPSubmitBetaEnabled, newPolicy);
const reportNextStep = allReportNextSteps?.[`${ONYXKEYS.COLLECTION.NEXT_STEP}${optimisticReport.reportID}`];
From e56d95f4d75b72d43e6b3799d2192c34ac866848 Mon Sep 17 00:00:00 2001
From: "I.K." <54219858+M00rish@users.noreply.github.com>
Date: Sun, 8 Feb 2026 23:34:17 +0000
Subject: [PATCH 08/11] fix: add missing betas parameter to createNewReport
call
---
src/pages/iou/request/step/IOURequestStepUpgrade.tsx | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/pages/iou/request/step/IOURequestStepUpgrade.tsx b/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
index de9673d261bf1..fbe49dbb67188 100644
--- a/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
+++ b/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
@@ -74,6 +74,7 @@ function IOURequestStepUpgrade({
const [allReportNextSteps] = useOnyx(ONYXKEYS.COLLECTION.NEXT_STEP, {canBeMissing: true});
const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true});
const [session] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: false});
+ const [betas] = useOnyx(ONYXKEYS.BETAS, {canBeMissing: true});
// Build transactions map from selectedTransactions (search results) instead of Onyx TRANSACTION collection
// This ensures that transactions selected from search are properly included in the map passed to changeTransactionsReport
@@ -118,7 +119,7 @@ function IOURequestStepUpgrade({
if (upgradePath === CONST.UPGRADE_PATHS.REPORTS && policyID && selectedTransactionsKeys.length > 0) {
const newPolicy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`];
- const optimisticReport = createNewReport(currentUserPersonalDetails, hasViolations, isASAPSubmitBetaEnabled, newPolicy);
+ const optimisticReport = createNewReport(currentUserPersonalDetails, hasViolations, isASAPSubmitBetaEnabled, newPolicy, betas);
const reportNextStep = allReportNextSteps?.[`${ONYXKEYS.COLLECTION.NEXT_STEP}${optimisticReport.reportID}`];
@@ -196,6 +197,7 @@ function IOURequestStepUpgrade({
session?.email,
currentUserPersonalDetails,
allTransactions,
+ betas,
]);
const participant = transaction?.participants?.[0];
From 93c98097df82b3daa7f8a471416f41a7ef01612e Mon Sep 17 00:00:00 2001
From: "I.K." <54219858+M00rish@users.noreply.github.com>
Date: Wed, 11 Feb 2026 02:33:22 +0000
Subject: [PATCH 09/11] fixes
---
.../request/step/IOURequestStepUpgrade.tsx | 32 +++++++++++--------
1 file changed, 18 insertions(+), 14 deletions(-)
diff --git a/src/pages/iou/request/step/IOURequestStepUpgrade.tsx b/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
index b559486ae5cf0..d29c88bce953f 100644
--- a/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
+++ b/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
@@ -23,7 +23,7 @@ import Navigation from '@libs/Navigation/Navigation';
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {MoneyRequestNavigatorParamList} from '@libs/Navigation/types';
import {getParticipantsOption} from '@libs/OptionsListUtils';
-import {hasViolations as hasViolationsReportUtils} from '@libs/ReportUtils';
+import {getPersonalDetailsForAccountID, hasViolations as hasViolationsReportUtils} from '@libs/ReportUtils';
import UpgradeConfirmation from '@pages/workspace/upgrade/UpgradeConfirmation';
import UpgradeIntro from '@pages/workspace/upgrade/UpgradeIntro';
import {setCustomUnitRateID, setMoneyRequestParticipants} from '@userActions/IOU';
@@ -33,7 +33,7 @@ import ONYXKEYS from '@src/ONYXKEYS';
import type {Route} from '@src/ROUTES';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
-import type {Transaction} from '@src/types/onyx';
+import type {PersonalDetails, Transaction} from '@src/types/onyx';
type IOURequestStepUpgradeProps = PlatformStackScreenProps;
@@ -50,6 +50,7 @@ function IOURequestStepUpgrade({
const personalDetails = usePersonalDetails();
const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {canBeMissing: true});
+ const [selectedReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, {canBeMissing: true});
const [onboardingPurposeSelected] = useOnyx(ONYXKEYS.ONBOARDING_PURPOSE_SELECTED, {canBeMissing: true});
const [isUpgraded, setIsUpgraded] = useState(false);
@@ -97,29 +98,32 @@ function IOURequestStepUpgrade({
const isASAPSubmitBetaEnabled = isBetaEnabled(CONST.BETAS.ASAP_SUBMIT);
const hasViolations = hasViolationsReportUtils(undefined, transactionViolations, session?.accountID ?? CONST.DEFAULT_NUMBER_ID, session?.email ?? '');
+ const ownerPersonalDetails = useMemo(
+ () => getPersonalDetailsForAccountID(selectedReport?.ownerAccountID, personalDetails) as PersonalDetails,
+ [personalDetails, selectedReport?.ownerAccountID],
+ );
+
const feature = Object.values(CONST.UPGRADE_FEATURE_INTRO_MAPPING)
.filter((value) => value.id !== CONST.UPGRADE_FEATURE_INTRO_MAPPING.policyPreventMemberChangingTitle.id)
.find((f) => f.alias === upgradePath);
- const navigateWithMicrotask = useCallback(
- (route: Route) => {
- if (isWeb) {
- Navigation.setNavigationActionToMicrotaskQueue(() => Navigation.navigate(route));
- } else {
- Navigation.navigate(route);
- }
- },
- [isWeb],
- );
+ const navigateWithMicrotask = (route: Route) => {
+ if (isWeb) {
+ Navigation.setNavigationActionToMicrotaskQueue(() => Navigation.navigate(route));
+ } else {
+ Navigation.navigate(route);
+ }
+ };
const afterUpgradeAcknowledged = useCallback(() => {
const expenseReportID = policyDataRef.current?.expenseChatReportID ?? reportID;
const policyID = policyDataRef.current?.policyID;
+ // Bulk move expenses
if (upgradePath === CONST.UPGRADE_PATHS.REPORTS && policyID && selectedTransactionsKeys.length > 0) {
const newPolicy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`];
- const optimisticReport = createNewReport(currentUserPersonalDetails, hasViolations, isASAPSubmitBetaEnabled, newPolicy, betas);
+ const optimisticReport = createNewReport(ownerPersonalDetails, hasViolations, isASAPSubmitBetaEnabled, newPolicy, betas);
const reportNextStep = allReportNextSteps?.[`${ONYXKEYS.COLLECTION.NEXT_STEP}${optimisticReport.reportID}`];
@@ -195,7 +199,7 @@ function IOURequestStepUpgrade({
allPolicyCategories,
session?.accountID,
session?.email,
- currentUserPersonalDetails,
+ ownerPersonalDetails,
allTransactions,
betas,
]);
From e1fe4bc5224199694becc409f810dcc506b296d3 Mon Sep 17 00:00:00 2001
From: "I.K." <54219858+M00rish@users.noreply.github.com>
Date: Wed, 18 Feb 2026 00:34:54 +0000
Subject: [PATCH 10/11] fix expense selection
---
src/pages/iou/request/step/IOURequestStepUpgrade.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/pages/iou/request/step/IOURequestStepUpgrade.tsx b/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
index d29c88bce953f..1ff8346a73dd2 100644
--- a/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
+++ b/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
@@ -120,7 +120,7 @@ function IOURequestStepUpgrade({
const policyID = policyDataRef.current?.policyID;
// Bulk move expenses
- if (upgradePath === CONST.UPGRADE_PATHS.REPORTS && policyID && selectedTransactionsKeys.length > 0) {
+ if (upgradePath === CONST.UPGRADE_PATHS.REPORTS && policyID && selectedTransactionsKeys.includes(transactionID)) {
const newPolicy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`];
const optimisticReport = createNewReport(ownerPersonalDetails, hasViolations, isASAPSubmitBetaEnabled, newPolicy, betas);
From fc8b21b56a40ccd842043f1f6ddb87132752f0f2 Mon Sep 17 00:00:00 2001
From: "I.K." <54219858+M00rish@users.noreply.github.com>
Date: Wed, 11 Mar 2026 07:49:07 +0000
Subject: [PATCH 11/11] resolve conflict
---
.../request/step/IOURequestStepUpgrade.tsx | 72 ++++++++++---------
1 file changed, 38 insertions(+), 34 deletions(-)
diff --git a/src/pages/iou/request/step/IOURequestStepUpgrade.tsx b/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
index d661513a7a819..66c312e354cb9 100644
--- a/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
+++ b/src/pages/iou/request/step/IOURequestStepUpgrade.tsx
@@ -1,14 +1,14 @@
-import { hasSeenTourSelector } from '@selectors/Onboarding';
-import React, { useCallback, useMemo, useRef, useState } from 'react';
-import type { OnyxCollection } from 'react-native-onyx';
+import {hasSeenTourSelector} from '@selectors/Onboarding';
+import React, {useCallback, useMemo, useRef, useState} from 'react';
+import type {OnyxCollection} from 'react-native-onyx';
import ConfirmModal from '@components/ConfirmModal';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
-import { usePersonalDetails } from '@components/OnyxListItemProvider';
+import {usePersonalDetails} from '@components/OnyxListItemProvider';
import ScreenWrapper from '@components/ScreenWrapper';
import ScrollView from '@components/ScrollView';
-import { useSearchContext } from '@components/Search/SearchContext';
+import {useSearchActionsContext, useSearchStateContext} from '@components/Search/SearchContext';
import WorkspaceConfirmationForm from '@components/WorkspaceConfirmationForm';
-import type { WorkspaceConfirmationSubmitFunctionParams } from '@components/WorkspaceConfirmationForm';
+import type {WorkspaceConfirmationSubmitFunctionParams} from '@components/WorkspaceConfirmationForm';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
@@ -16,43 +16,43 @@ import useOnyx from '@hooks/useOnyx';
import usePermissions from '@hooks/usePermissions';
import usePreferredPolicy from '@hooks/usePreferredPolicy';
import useThemeStyles from '@hooks/useThemeStyles';
-import { createNewReport } from '@libs/actions/Report';
-import { changeTransactionsReport, setTransactionReport } from '@libs/actions/Transaction';
+import {createNewReport} from '@libs/actions/Report';
+import {changeTransactionsReport, setTransactionReport} from '@libs/actions/Transaction';
import type CreateWorkspaceParams from '@libs/API/parameters/CreateWorkspaceParams';
import getPlatform from '@libs/getPlatform';
import Navigation from '@libs/Navigation/Navigation';
-import type { PlatformStackScreenProps } from '@libs/Navigation/PlatformStackNavigation/types';
-import type { MoneyRequestNavigatorParamList } from '@libs/Navigation/types';
-import { getParticipantsOption } from '@libs/OptionsListUtils';
-import { getPersonalDetailsForAccountID, hasViolations as hasViolationsReportUtils } from '@libs/ReportUtils';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
+import type {MoneyRequestNavigatorParamList} from '@libs/Navigation/types';
+import {getParticipantsOption} from '@libs/OptionsListUtils';
+import {getPersonalDetailsForAccountID, hasViolations as hasViolationsReportUtils} from '@libs/ReportUtils';
import UpgradeConfirmation from '@pages/workspace/upgrade/UpgradeConfirmation';
import UpgradeIntro from '@pages/workspace/upgrade/UpgradeIntro';
-import { setCustomUnitRateID, setMoneyRequestParticipants } from '@userActions/IOU';
+import {setCustomUnitRateID, setMoneyRequestParticipants} from '@userActions/IOU';
import CONST from '@src/CONST';
import * as Policy from '@src/libs/actions/Policy/Policy';
import ONYXKEYS from '@src/ONYXKEYS';
-import type { Route } from '@src/ROUTES';
+import type {Route} from '@src/ROUTES';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
-import type { PersonalDetails, Transaction } from '@src/types/onyx';
+import type {PersonalDetails, Transaction} from '@src/types/onyx';
type IOURequestStepUpgradeProps = PlatformStackScreenProps;
function IOURequestStepUpgrade({
route: {
- params: { transactionID, action, reportID, shouldSubmitExpense, upgradePath, backTo },
+ params: {transactionID, action, reportID, shouldSubmitExpense, upgradePath, backTo},
},
}: IOURequestStepUpgradeProps) {
const styles = useThemeStyles();
- const { translate } = useLocalize();
- const { isOffline } = useNetwork();
+ const {translate, toLocaleDigit} = useLocalize();
+ const {isOffline} = useNetwork();
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
const personalDetails = usePersonalDetails();
- const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, { canBeMissing: true });
- const [selectedReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, { canBeMissing: true });
- const [onboardingPurposeSelected] = useOnyx(ONYXKEYS.ONBOARDING_PURPOSE_SELECTED, { canBeMissing: true });
+ const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`);
+ const [selectedReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`);
+ const [onboardingPurposeSelected] = useOnyx(ONYXKEYS.ONBOARDING_PURPOSE_SELECTED);
const [isUpgraded, setIsUpgraded] = useState(false);
const [showConfirmationForm, setShowConfirmationForm] = useState(false);
@@ -64,20 +64,21 @@ function IOURequestStepUpgrade({
const isReporting = upgradePath === CONST.UPGRADE_PATHS.REPORTS;
const platform = getPlatform();
const isWeb = platform === CONST.PLATFORM.WEB;
- const { isRestrictedPolicyCreation } = usePreferredPolicy();
+ const {isRestrictedPolicyCreation} = usePreferredPolicy();
const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED);
const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID);
- const [isSelfTourViewed] = useOnyx(ONYXKEYS.NVP_ONBOARDING, { selector: hasSeenTourSelector });
+ const [isSelfTourViewed] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector});
// Hooks for bulk move functionality
- const { selectedTransactions, clearSelectedTransactions } = useSearchContext();
+ const {selectedTransactions} = useSearchStateContext();
+ const {clearSelectedTransactions} = useSearchActionsContext();
const selectedTransactionsKeys = useMemo(() => Object.keys(selectedTransactions), [selectedTransactions]);
- const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, { canBeMissing: true });
- const [allPolicyCategories] = useOnyx(ONYXKEYS.COLLECTION.POLICY_CATEGORIES, { canBeMissing: true });
- const [allReportNextSteps] = useOnyx(ONYXKEYS.COLLECTION.NEXT_STEP, { canBeMissing: true });
- const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, { canBeMissing: true });
- const [session] = useOnyx(ONYXKEYS.SESSION, { canBeMissing: false });
- const [betas] = useOnyx(ONYXKEYS.BETAS, { canBeMissing: true });
+ const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS);
+ const [allPolicyCategories] = useOnyx(ONYXKEYS.COLLECTION.POLICY_CATEGORIES);
+ const [allReportNextSteps] = useOnyx(ONYXKEYS.COLLECTION.NEXT_STEP);
+ const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY);
+ const [session] = useOnyx(ONYXKEYS.SESSION);
+ const [betas] = useOnyx(ONYXKEYS.BETAS);
// Build transactions map from selectedTransactions (search results) instead of Onyx TRANSACTION collection
// This ensures that transactions selected from search are properly included in the map passed to changeTransactionsReport
@@ -96,7 +97,7 @@ function IOURequestStepUpgrade({
[selectedTransactions],
);
- const { isBetaEnabled } = usePermissions();
+ const {isBetaEnabled} = usePermissions();
const isASAPSubmitBetaEnabled = isBetaEnabled(CONST.BETAS.ASAP_SUBMIT);
const hasViolations = hasViolationsReportUtils(undefined, transactionViolations, session?.accountID ?? CONST.DEFAULT_NUMBER_ID, session?.email ?? '');
@@ -140,6 +141,8 @@ function IOURequestStepUpgrade({
reportNextStep,
policyCategories: allPolicyCategories?.[`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`],
allTransactions,
+ translate,
+ toLocaleDigit,
});
clearSelectedTransactions();
@@ -174,10 +177,10 @@ function IOURequestStepUpgrade({
Navigation.goBack(backToRoute);
- setTransactionReport(transactionID, { reportID: expenseReportID }, true);
+ setTransactionReport(transactionID, {reportID: expenseReportID}, true);
// Let the confirmation step decide the distance rate because policy data is not fully available at this step
setCustomUnitRateID(transactionID, '-1', undefined, undefined);
- Navigation.setParams({ reportID: expenseReportID });
+ Navigation.setParams({reportID: expenseReportID});
navigateWithMicrotask(ROUTES.WORKSPACE_CREATE_DISTANCE_RATE_UPGRADE.getRoute(policyID, transactionID, expenseReportID));
break;
@@ -220,6 +223,8 @@ function IOURequestStepUpgrade({
ownerPersonalDetails,
allTransactions,
betas,
+ translate,
+ toLocaleDigit,
]);
const participant = transaction?.participants?.[0];
@@ -261,7 +266,6 @@ function IOURequestStepUpgrade({
policyDataRef.current = policyData;
};
-
const handleConfirmUpgradeWarning = () => {
setIsUpgradeWarningModalOpen(false);
};