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); };