From b00b27716f37899a99bcdf7b5f91c18f40ab492f Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 11 Jun 2026 10:47:12 -0600 Subject: [PATCH 1/3] fix bug --- .../ListItem/ActionCell/PayActionCell.tsx | 6 ++++-- .../SearchList/ListItem/ActionCell/index.tsx | 5 +++++ .../ListItem/ExpenseReportListItem.tsx | 11 ++++++----- .../ExpenseReportListItemRowWide.tsx | 2 ++ .../ExpenseReportListItemRow/index.tsx | 1 + .../ListItem/ExpenseReportListItemRow/types.ts | 4 +++- .../ListItem/ReportListItemHeader.tsx | 18 +++++++++++++++--- 7 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/components/Search/SearchList/ListItem/ActionCell/PayActionCell.tsx b/src/components/Search/SearchList/ListItem/ActionCell/PayActionCell.tsx index b30b63392457..094a994f7fdc 100644 --- a/src/components/Search/SearchList/ListItem/ActionCell/PayActionCell.tsx +++ b/src/components/Search/SearchList/ListItem/ActionCell/PayActionCell.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import type {OnyxEntry} from 'react-native-onyx'; import {useDelegateNoAccessActions, useDelegateNoAccessState} from '@components/DelegateNoAccessModalProvider'; import {SearchScopeProvider} from '@components/Search/SearchScopeProvider'; import SettlementButton from '@components/SettlementButton'; @@ -17,6 +18,7 @@ import {isInvoiceReport} from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type {Report} from '@src/types/onyx'; type PayActionCellProps = { isLoading: boolean; @@ -26,9 +28,10 @@ type PayActionCellProps = { amount?: number; extraSmall: boolean; shouldDisablePointerEvents?: boolean; + chatReport: OnyxEntry; }; -function PayActionCell({isLoading, policyID, reportID, hash, amount, extraSmall, shouldDisablePointerEvents}: PayActionCellProps) { +function PayActionCell({isLoading, policyID, reportID, hash, amount, extraSmall, shouldDisablePointerEvents, chatReport}: PayActionCellProps) { const styles = useThemeStyles(); const {convertToDisplayString} = useCurrencyListActions(); const {isOffline} = useNetwork(); @@ -37,7 +40,6 @@ function PayActionCell({isLoading, policyID, reportID, hash, amount, extraSmall, const [iouReport, transactions] = useReportWithTransactionsAndViolations(reportID); const policy = usePolicy(policyID); const [bankAccountList] = useOnyx(ONYXKEYS.BANK_ACCOUNT_LIST); - const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${iouReport?.chatReportID}`); const invoiceReceiverPolicyID = chatReport?.invoiceReceiver && 'policyID' in chatReport.invoiceReceiver ? chatReport.invoiceReceiver.policyID : undefined; const invoiceReceiverPolicy = usePolicy(invoiceReceiverPolicyID); const { diff --git a/src/components/Search/SearchList/ListItem/ActionCell/index.tsx b/src/components/Search/SearchList/ListItem/ActionCell/index.tsx index 97c1fe4ceda5..99e822d72677 100644 --- a/src/components/Search/SearchList/ListItem/ActionCell/index.tsx +++ b/src/components/Search/SearchList/ListItem/ActionCell/index.tsx @@ -1,10 +1,12 @@ import React from 'react'; +import type {OnyxEntry} from 'react-native-onyx'; import Button from '@components/Button'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; import type {ModifiedMouseEvent} from '@libs/Navigation/helpers/openInternalRouteInNewTab'; import CONST from '@src/CONST'; +import type {Report} from '@src/types/onyx'; import type {SearchTransactionAction} from '@src/types/onyx/SearchResults'; import actionTranslationsMap from './actionTranslationsMap'; import PayActionCell from './PayActionCell'; @@ -21,6 +23,7 @@ type ActionCellProps = { amount?: number; extraSmall?: boolean; shouldDisablePointerEvents?: boolean; + chatReport?: OnyxEntry; }; function ActionCell({ @@ -35,6 +38,7 @@ function ActionCell({ amount, extraSmall = false, shouldDisablePointerEvents, + chatReport, }: ActionCellProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); @@ -75,6 +79,7 @@ function ActionCell({ amount={amount} extraSmall={extraSmall} shouldDisablePointerEvents={shouldDisablePointerEvents} + chatReport={chatReport} /> ); } diff --git a/src/components/Search/SearchList/ListItem/ExpenseReportListItem.tsx b/src/components/Search/SearchList/ListItem/ExpenseReportListItem.tsx index 9eeb51f6645d..65253d13f89c 100644 --- a/src/components/Search/SearchList/ListItem/ExpenseReportListItem.tsx +++ b/src/components/Search/SearchList/ListItem/ExpenseReportListItem.tsx @@ -101,6 +101,8 @@ function ExpenseReportListItem({ return searchData?.[`${ONYXKEYS.COLLECTION.REPORT}${reportItem.parentReportID}`]; }, [searchData, reportItem.parentReportID]); + const chatReport = parentChatReport ?? snapshotChatReport; + const snapshotPolicy = useMemo(() => { return (searchData?.[`${ONYXKEYS.COLLECTION.POLICY}${reportItem.policyID}`] ?? {}) as Policy; }, [searchData, reportItem.policyID]); @@ -171,7 +173,7 @@ function ExpenseReportListItem({ const liveReportTransactions = useMemo(() => Object.values(reportTransactions), [reportTransactions]); const {currentUserAccountID, currentUserLogin, introSelected, betas, isSelfTourViewed, activePolicy, nextStep, chatReportPolicy, amountOwed} = useReportPaymentContext({ reportID: reportItem.reportID, - chatReportPolicyID: parentChatReport?.policyID ?? snapshotChatReport?.policyID, + chatReportPolicyID: chatReport?.policyID, }); const handleOnButtonPress = useCallback(() => { @@ -192,7 +194,6 @@ function ExpenseReportListItem({ // Search rows render from a snapshot; the report may not exist in the main // collection yet. Fall back to the snapshot so the modal can submit. const moneyRequestReport = parentReport ?? snapshotReport; - const chatReport = parentChatReport ?? snapshotChatReport; const transactionsForHoldMenu = liveReportTransactions.length > 0 ? liveReportTransactions : holdItem.transactions; const {nonHeldAmount, fullAmount, hasValidNonHeldAmount} = getNonHeldAndFullAmount(moneyRequestReport, holdItem.canPay ?? false, transactionsForHoldMenu); const hasNonHeldExpenses = transactionsForHoldMenu.some((t) => !isOnHold(t)); @@ -218,7 +219,7 @@ function ExpenseReportListItem({ betas, isSelfTourViewed, activePolicy, - chatReport: parentChatReport ?? snapshotChatReport, + chatReport, chatReportPolicy, iouReportCurrentNextStepDeprecated: nextStep, searchData, @@ -230,11 +231,10 @@ function ExpenseReportListItem({ onSelectRow, searchData, snapshotReport, - snapshotChatReport, + chatReport, snapshotPolicy, parentPolicy, parentReport, - parentChatReport, lastPaymentMethod, userBillingGracePeriodEnds, personalPolicyID, @@ -402,6 +402,7 @@ function ExpenseReportListItem({ canSelectMultiple={canSelectMultiple} onCheckboxPress={handleSelectionButtonPress} onButtonPress={handleOnButtonPress} + chatReport={chatReport} isSelectAllChecked={isSelected} isIndeterminate={false} isDisabledCheckbox={isDisabledCheckbox} diff --git a/src/components/Search/SearchList/ListItem/ExpenseReportListItemRow/ExpenseReportListItemRowWide.tsx b/src/components/Search/SearchList/ListItem/ExpenseReportListItemRow/ExpenseReportListItemRowWide.tsx index ab301d389d58..3c2aecdc285a 100644 --- a/src/components/Search/SearchList/ListItem/ExpenseReportListItemRow/ExpenseReportListItemRowWide.tsx +++ b/src/components/Search/SearchList/ListItem/ExpenseReportListItemRow/ExpenseReportListItemRowWide.tsx @@ -27,6 +27,7 @@ function ExpenseReportListItemRowWide({ onCheckboxPress = () => {}, onButtonPress = () => {}, isActionLoading, + chatReport, containerStyle, showTooltip, canSelectMultiple, @@ -199,6 +200,7 @@ function ExpenseReportListItemRowWide({ reportID={item.reportID} hash={item.hash} amount={item.total} + chatReport={chatReport} shouldDisablePointerEvents={isPendingDelete} /> diff --git a/src/components/Search/SearchList/ListItem/ExpenseReportListItemRow/index.tsx b/src/components/Search/SearchList/ListItem/ExpenseReportListItemRow/index.tsx index 30e4854a6291..487a65fbb8ba 100644 --- a/src/components/Search/SearchList/ListItem/ExpenseReportListItemRow/index.tsx +++ b/src/components/Search/SearchList/ListItem/ExpenseReportListItemRow/index.tsx @@ -17,6 +17,7 @@ function ExpenseReportListItemRow(props: ExpenseReportListItemRowProps) { isActionLoading={props.isActionLoading} onButtonPress={props.onButtonPress} onCheckboxPress={props.onCheckboxPress} + chatReport={props.chatReport} containerStyle={props.containerStyle} isSelectAllChecked={props.isSelectAllChecked} isIndeterminate={props.isIndeterminate} diff --git a/src/components/Search/SearchList/ListItem/ExpenseReportListItemRow/types.ts b/src/components/Search/SearchList/ListItem/ExpenseReportListItemRow/types.ts index 6a405152939a..7d60df18a7a0 100644 --- a/src/components/Search/SearchList/ListItem/ExpenseReportListItemRow/types.ts +++ b/src/components/Search/SearchList/ListItem/ExpenseReportListItemRow/types.ts @@ -1,7 +1,8 @@ import type {StyleProp, ViewStyle} from 'react-native'; import type {ExpenseReportListItemType} from '@components/Search/SearchList/ListItem/types'; import type {SearchColumnType} from '@components/Search/types'; -import type {ReportAction} from '@src/types/onyx'; +import type {Report, ReportAction} from '@src/types/onyx'; +import type {OnyxEntry} from 'react-native-onyx'; type ExpenseReportListItemRowNarrowProps = { item: ExpenseReportListItemType; @@ -17,6 +18,7 @@ type ExpenseReportListItemRowWideProps = ExpenseReportListItemRowNarrowProps & { showTooltip: boolean; isActionLoading?: boolean; onButtonPress?: () => void; + chatReport?: OnyxEntry; containerStyle?: StyleProp; isHovered?: boolean; isFocused?: boolean; diff --git a/src/components/Search/SearchList/ListItem/ReportListItemHeader.tsx b/src/components/Search/SearchList/ListItem/ReportListItemHeader.tsx index 8e97f79ed7b2..5efc2955d351 100644 --- a/src/components/Search/SearchList/ListItem/ReportListItemHeader.tsx +++ b/src/components/Search/SearchList/ListItem/ReportListItemHeader.tsx @@ -1,5 +1,6 @@ import React, {useMemo} from 'react'; import type {ColorValue} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; import {View} from 'react-native'; import Checkbox from '@components/Checkbox'; import {useDelegateNoAccessActions, useDelegateNoAccessState} from '@components/DelegateNoAccessModalProvider'; @@ -96,6 +97,9 @@ type FirstRowReportHeaderProps = { /** Whether the down arrow is expanded */ isExpanded?: boolean; + + /** Parent chat report resolved from live Onyx with search snapshot fallback */ + chatReport?: OnyxEntry; }; function HeaderFirstRow({ @@ -109,6 +113,7 @@ function HeaderFirstRow({ isIndeterminate, onDownArrowClick, isExpanded, + chatReport, }: FirstRowReportHeaderProps) { const icons = useMemoizedLazyExpensifyIcons(['DownArrow', 'UpArrow']); const styles = useThemeStyles(); @@ -190,6 +195,7 @@ function HeaderFirstRow({ hash={reportItem.hash} amount={reportItem.total} extraSmall={!isLargeScreenWidth} + chatReport={chatReport} /> )} @@ -228,11 +234,16 @@ function ReportListItemHeader({ const snapshotPolicy = useMemo(() => { return (snapshot?.data?.[`${ONYXKEYS.COLLECTION.POLICY}${reportItem.policyID}`] ?? {}) as Policy; }, [snapshot, reportItem.policyID]); + const snapshotChatReport = useMemo(() => { + const chatReportID = snapshotReport?.chatReportID ?? reportItem.parentReportID; + return chatReportID ? snapshot?.data?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`] : undefined; + }, [snapshot, snapshotReport?.chatReportID, reportItem.parentReportID]); const [parentPolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${getNonEmptyStringOnyxID(snapshotReport?.policyID ?? reportItem.policyID)}`); - const [parentChatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(snapshotReport?.chatReportID)}`); + const [parentChatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(snapshotReport?.chatReportID ?? reportItem.parentReportID)}`); + const chatReport = parentChatReport ?? snapshotChatReport; const {currentUserAccountID, currentUserLogin, introSelected, betas, isSelfTourViewed, activePolicy, nextStep, chatReportPolicy, amountOwed} = useReportPaymentContext({ reportID: reportItem.reportID, - chatReportPolicyID: parentChatReport?.policyID, + chatReportPolicyID: chatReport?.policyID, }); const {isDelegateAccessRestricted} = useDelegateNoAccessState(); const {showDelegateNoAccessModal} = useDelegateNoAccessActions(); @@ -265,7 +276,7 @@ function ReportListItemHeader({ betas, isSelfTourViewed, activePolicy, - chatReport: parentChatReport, + chatReport, chatReportPolicy, iouReportCurrentNextStepDeprecated: nextStep, searchData: snapshot?.data, @@ -306,6 +317,7 @@ function ReportListItemHeader({ isIndeterminate={isIndeterminate} onDownArrowClick={onDownArrowClick} isExpanded={isExpanded} + chatReport={chatReport} /> ); From ad699c5f2f42f2789be7df148195ab699cfe7c01 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 11 Jun 2026 10:54:55 -0600 Subject: [PATCH 2/3] fix prettier --- .../SearchList/ListItem/ExpenseReportListItemRow/types.ts | 2 +- .../Search/SearchList/ListItem/ReportListItemHeader.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Search/SearchList/ListItem/ExpenseReportListItemRow/types.ts b/src/components/Search/SearchList/ListItem/ExpenseReportListItemRow/types.ts index 7d60df18a7a0..a40897ce8171 100644 --- a/src/components/Search/SearchList/ListItem/ExpenseReportListItemRow/types.ts +++ b/src/components/Search/SearchList/ListItem/ExpenseReportListItemRow/types.ts @@ -1,8 +1,8 @@ import type {StyleProp, ViewStyle} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; import type {ExpenseReportListItemType} from '@components/Search/SearchList/ListItem/types'; import type {SearchColumnType} from '@components/Search/types'; import type {Report, ReportAction} from '@src/types/onyx'; -import type {OnyxEntry} from 'react-native-onyx'; type ExpenseReportListItemRowNarrowProps = { item: ExpenseReportListItemType; diff --git a/src/components/Search/SearchList/ListItem/ReportListItemHeader.tsx b/src/components/Search/SearchList/ListItem/ReportListItemHeader.tsx index 5efc2955d351..5596e7c933bc 100644 --- a/src/components/Search/SearchList/ListItem/ReportListItemHeader.tsx +++ b/src/components/Search/SearchList/ListItem/ReportListItemHeader.tsx @@ -1,7 +1,7 @@ import React, {useMemo} from 'react'; import type {ColorValue} from 'react-native'; -import type {OnyxEntry} from 'react-native-onyx'; import {View} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; import Checkbox from '@components/Checkbox'; import {useDelegateNoAccessActions, useDelegateNoAccessState} from '@components/DelegateNoAccessModalProvider'; import Icon from '@components/Icon'; From cd33034901f36ec5f8491dc8f7c408156fc70879 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 11 Jun 2026 11:58:24 -0600 Subject: [PATCH 3/3] add fallback report --- .../Search/SearchList/ListItem/ExpenseReportListItem.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/Search/SearchList/ListItem/ExpenseReportListItem.tsx b/src/components/Search/SearchList/ListItem/ExpenseReportListItem.tsx index 65253d13f89c..c409d37b3624 100644 --- a/src/components/Search/SearchList/ListItem/ExpenseReportListItem.tsx +++ b/src/components/Search/SearchList/ListItem/ExpenseReportListItem.tsx @@ -88,7 +88,6 @@ function ExpenseReportListItem({ // Fetch live policy categories from Onyx to sync violations at render time const [parentPolicy] = originalUseOnyx(`${ONYXKEYS.COLLECTION.POLICY}${getNonEmptyStringOnyxID(reportItem.policyID)}`); const [parentReport] = originalUseOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(reportItem.reportID)}`); - const [parentChatReport] = originalUseOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(reportItem.parentReportID)}`); const [policyCategories] = originalUseOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${getNonEmptyStringOnyxID(reportItem.policyID)}`); const searchData = currentSearchResults?.data; @@ -97,9 +96,12 @@ function ExpenseReportListItem({ return (searchData?.[`${ONYXKEYS.COLLECTION.REPORT}${reportItem.reportID}`] ?? {}) as Report; }, [searchData, reportItem.reportID]); + const [parentChatReport] = originalUseOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(snapshotReport?.chatReportID ?? reportItem.parentReportID)}`); + const snapshotChatReport = useMemo(() => { - return searchData?.[`${ONYXKEYS.COLLECTION.REPORT}${reportItem.parentReportID}`]; - }, [searchData, reportItem.parentReportID]); + const chatReportID = snapshotReport?.chatReportID ?? reportItem.parentReportID; + return chatReportID ? searchData?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`] : undefined; + }, [searchData, snapshotReport?.chatReportID, reportItem.parentReportID]); const chatReport = parentChatReport ?? snapshotChatReport;