diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionItem.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionItem.tsx index 0528b7d7deed..d255192f29f3 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionItem.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionItem.tsx @@ -17,12 +17,16 @@ import canUseTouchScreen from '@libs/DeviceCapabilities/canUseTouchScreen'; import {getTransactionPendingAction, isTransactionPendingDelete} from '@libs/TransactionUtils'; import variables from '@styles/variables'; import CONST from '@src/CONST'; +import type {Report} from '@src/types/onyx'; import type {TransactionWithOptionalHighlight} from './MoneyRequestReportTransactionList'; type MoneyRequestReportTransactionItemProps = { /** The transaction that is being displayed */ transaction: TransactionWithOptionalHighlight; + /** Report to which the transaction belongs */ + report: Report; + /** Whether the mobile selection mode is enabled */ isSelectionModeEnabled: boolean; @@ -57,6 +61,7 @@ type MoneyRequestReportTransactionItemProps = { function MoneyRequestReportTransactionItem({ transaction, columns, + report, isSelectionModeEnabled, toggleTransaction, isSelected, @@ -119,6 +124,7 @@ function MoneyRequestReportTransactionItem({ > ({ groupItem.transactions.map((transaction) => ( ({ )} = { type TransactionListItemType = ListItem & SearchTransaction & { + /** Report to which the transaction belongs */ + report: Report; + /** The personal details of the user requesting money */ from: SearchPersonalDetails; diff --git a/src/components/TransactionItemRow/TransactionItemRowRBR.tsx b/src/components/TransactionItemRow/TransactionItemRowRBR.tsx deleted file mode 100644 index a00072ca2a1b..000000000000 --- a/src/components/TransactionItemRow/TransactionItemRowRBR.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import React from 'react'; -import type {ViewStyle} from 'react-native'; -import {View} from 'react-native'; -import Icon from '@components/Icon'; -import {DotIndicator} from '@components/Icon/Expensicons'; -import RenderHTML from '@components/RenderHTML'; -import useLocalize from '@hooks/useLocalize'; -import useTheme from '@hooks/useTheme'; -import useThemeStyles from '@hooks/useThemeStyles'; -import Parser from '@libs/Parser'; -import ViolationsUtils from '@libs/Violations/ViolationsUtils'; -import variables from '@styles/variables'; -import type {TransactionViolations} from '@src/types/onyx'; - -type TransactionItemRowRBRProps = { - /** Transaction item */ - transactionViolations?: TransactionViolations; - - /** Styles for the RBR messages container */ - containerStyles?: ViewStyle[]; - - /** Error message for missing required fields in the transaction */ - missingFieldError?: string; -}; - -/** This component is lighter version of TransactionItemRowRBRWithOnyx that doesn't use onyx but uses transactionViolations data computed from search, - * thus it doesn't include violations taken from reportActions like its counterpart does. */ -function TransactionItemRowRBR({transactionViolations, containerStyles, missingFieldError}: TransactionItemRowRBRProps) { - const styles = useThemeStyles(); - const {translate} = useLocalize(); - const theme = useTheme(); - - if (!transactionViolations && !missingFieldError) { - return null; - } - - const RBRMessages = [ - ...(missingFieldError ? [`${missingFieldError}.`] : []), - // Some violations end with a period already so lets make sure the connected messages have only single period between them - // and end with a single dot. - ...(transactionViolations - ? transactionViolations.map((violation) => { - const message = ViolationsUtils.getViolationTranslation(violation, translate); - const textMessage = Parser.htmlToText(message); - return textMessage.endsWith('.') ? message : `${message}.`; - }) - : []), - ].join(' '); - return ( - RBRMessages.length > 0 && ( - - - - ${RBRMessages}`} /> - - - ) - ); -} - -TransactionItemRowRBR.displayName = 'TransactionItemRowRBR'; -export default TransactionItemRowRBR; diff --git a/src/components/TransactionItemRow/TransactionItemRowRBRWithOnyx.tsx b/src/components/TransactionItemRow/TransactionItemRowRBRWithOnyx.tsx index 129f00e6406a..383d9b440d6d 100644 --- a/src/components/TransactionItemRow/TransactionItemRowRBRWithOnyx.tsx +++ b/src/components/TransactionItemRow/TransactionItemRowRBRWithOnyx.tsx @@ -6,7 +6,6 @@ import {DotIndicator} from '@components/Icon/Expensicons'; import RenderHTML from '@components/RenderHTML'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; -import usePaginatedReportActions from '@hooks/usePaginatedReportActions'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useTransactionViolations from '@hooks/useTransactionViolations'; @@ -14,12 +13,16 @@ import {getIOUActionForTransactionID} from '@libs/ReportActionsUtils'; import ViolationsUtils from '@libs/Violations/ViolationsUtils'; import variables from '@styles/variables'; import ONYXKEYS from '@src/ONYXKEYS'; +import type {Report} from '@src/types/onyx'; import type Transaction from '@src/types/onyx/Transaction'; type TransactionItemRowRBRProps = { /** Transaction item */ transaction: Transaction; + /** Report item */ + report?: Report; + /** Styles for the RBR messages container */ containerStyles?: ViewStyle[]; @@ -27,17 +30,21 @@ type TransactionItemRowRBRProps = { missingFieldError?: string; }; -function TransactionItemRowRBRWithOnyx({transaction, containerStyles, missingFieldError}: TransactionItemRowRBRProps) { +function TransactionItemRowRBRWithOnyx({transaction, report, containerStyles, missingFieldError}: TransactionItemRowRBRProps) { const styles = useThemeStyles(); const transactionViolations = useTransactionViolations(transaction?.transactionID, false); const {translate} = useLocalize(); const theme = useTheme(); - const {sortedAllReportActions: transactionActions, report} = usePaginatedReportActions(transaction.reportID); + const [reportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transaction.reportID}`, { + canBeMissing: true, + }); const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${report?.policyID}`, {canBeMissing: true}); - const transactionThreadId = transactionActions ? getIOUActionForTransactionID(transactionActions, transaction.transactionID)?.childReportID : undefined; - const {sortedAllReportActions: transactionThreadActions} = usePaginatedReportActions(transactionThreadId); + const transactionThreadId = reportActions ? getIOUActionForTransactionID(Object.values(reportActions ?? {}), transaction.transactionID)?.childReportID : undefined; + const [transactionThreadActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadId}`, { + canBeMissing: true, + }); - const RBRMessages = ViolationsUtils.getRBRMessages(transaction, transactionViolations, translate, missingFieldError, transactionThreadActions, policyTags); + const RBRMessages = ViolationsUtils.getRBRMessages(transaction, transactionViolations, translate, missingFieldError, Object.values(transactionThreadActions ?? {}), policyTags); return ( RBRMessages.length > 0 && ( diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx index b7e8ac8dad01..0f7bbb208fef 100644 --- a/src/components/TransactionItemRow/index.tsx +++ b/src/components/TransactionItemRow/index.tsx @@ -26,7 +26,7 @@ import { } from '@libs/TransactionUtils'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; -import type {TransactionViolation} from '@src/types/onyx'; +import type {Report, TransactionViolation} from '@src/types/onyx'; import type {SearchPersonalDetails, SearchTransactionAction} from '@src/types/onyx/SearchResults'; import CategoryCell from './DataCells/CategoryCell'; import ChatBubbleCell from './DataCells/ChatBubbleCell'; @@ -79,6 +79,7 @@ type TransactionWithOptionalSearchFields = TransactionWithOptionalHighlight & { type TransactionItemRowProps = { transactionItem: TransactionWithOptionalSearchFields; + report?: Report; shouldUseNarrowLayout: boolean; isSelected: boolean; shouldShowTooltip: boolean; @@ -111,6 +112,7 @@ function getMerchantName(transactionItem: TransactionWithOptionalSearchFields, t function TransactionItemRow({ transactionItem, + report, shouldUseNarrowLayout, isSelected, shouldShowTooltip, @@ -443,6 +445,7 @@ function TransactionItemRow({ )} @@ -476,6 +479,7 @@ function TransactionItemRow({ diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index 16e093119295..e1d8aaf6e098 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -760,6 +760,7 @@ function getTransactionsSections(data: OnyxTypes.SearchResults['data'], metadata const transactionSection: TransactionListItemType = { action: getAction(data, allViolations, key, currentSearch), + report, from, to, formattedFrom, @@ -1201,6 +1202,7 @@ function getReportSections( const transaction = { ...transactionItem, action: getAction(data, allViolations, key, currentSearch, actions), + report, from, to, formattedFrom, diff --git a/tests/unit/Search/SearchUIUtilsTest.ts b/tests/unit/Search/SearchUIUtilsTest.ts index 8aa9d6d55f97..96d17e618b84 100644 --- a/tests/unit/Search/SearchUIUtilsTest.ts +++ b/tests/unit/Search/SearchUIUtilsTest.ts @@ -34,6 +34,106 @@ const transactionID2 = '2'; const transactionID3 = '3'; const transactionID4 = '4'; +const report1 = { + accountID: adminAccountID, + action: 'view', + chatReportID: '1706144653204915', + created: '2024-12-21 13:05:20', + currency: 'USD', + isOneTransactionReport: true, + isPolicyExpenseChat: false, + isWaitingOnBankAccount: false, + managerID: adminAccountID, + nonReimbursableTotal: 0, + ownerAccountID: adminAccountID, + policyID, + reportID, + reportName: 'Expense Report #123', + stateNum: 0, + statusNum: 0, + total: -5000, + type: 'expense', + unheldTotal: -5000, +} as const; + +const report2 = { + accountID: adminAccountID, + action: 'view', + chatReportID: '1706144653204915', + created: '2024-12-21 13:05:20', + currency: 'USD', + isOneTransactionReport: true, + isPolicyExpenseChat: false, + isWaitingOnBankAccount: false, + managerID: adminAccountID, + nonReimbursableTotal: 0, + ownerAccountID: adminAccountID, + policyID, + reportID: reportID2, + reportName: 'Expense Report #123', + stateNum: 1, + statusNum: 1, + total: -5000, + type: 'expense', + unheldTotal: -5000, +} as const; + +const report3 = { + accountID: adminAccountID, + chatReportID: '6155022250251839', + chatType: undefined, + created: '2025-03-05 16:34:27', + currency: 'VND', + isOneTransactionReport: false, + isOwnPolicyExpenseChat: false, + isPolicyExpenseChat: false, + isWaitingOnBankAccount: false, + managerID: approverAccountID, + nonReimbursableTotal: 0, + oldPolicyName: '', + ownerAccountID: adminAccountID, + policyID, + private_isArchived: '', + reportID: reportID3, + reportName: 'Report Name', + stateNum: 1, + statusNum: 1, + total: 4400, + type: 'iou', + unheldTotal: 4400, +} as const; + +const report4 = { + accountID: adminAccountID, + reportID: reportID4, + chatReportID: '', + chatType: 'policyExpenseChat', + created: '2025-03-05 16:34:27', + type: 'chat', +} as const; + +const report5 = { + accountID: adminAccountID, + action: 'view', + chatReportID: '1706144653204915', + created: '2024-12-21 13:05:20', + currency: 'USD', + isOneTransactionReport: true, + isPolicyExpenseChat: false, + isWaitingOnBankAccount: false, + managerID: adminAccountID, + nonReimbursableTotal: 0, + ownerAccountID: adminAccountID, + policyID, + reportID: reportID5, + reportName: 'Expense Report #123', + stateNum: 0, + statusNum: 0, + total: 0, + type: 'expense', + unheldTotal: 0, +} as const; + const allViolations = { [`transactionViolations_${transactionID2}`]: [ { @@ -159,101 +259,11 @@ const searchResults: OnyxTypes.SearchResults = { reportName: 'Admin1', }, }, - [`report_${reportID}`]: { - accountID: adminAccountID, - action: 'view', - chatReportID: '1706144653204915', - created: '2024-12-21 13:05:20', - currency: 'USD', - isOneTransactionReport: true, - isPolicyExpenseChat: false, - isWaitingOnBankAccount: false, - managerID: adminAccountID, - nonReimbursableTotal: 0, - ownerAccountID: adminAccountID, - policyID, - reportID, - reportName: 'Expense Report #123', - stateNum: 0, - statusNum: 0, - total: -5000, - type: 'expense', - unheldTotal: -5000, - }, - [`report_${reportID2}`]: { - accountID: adminAccountID, - action: 'view', - chatReportID: '1706144653204915', - created: '2024-12-21 13:05:20', - currency: 'USD', - isOneTransactionReport: true, - isPolicyExpenseChat: false, - isWaitingOnBankAccount: false, - managerID: adminAccountID, - nonReimbursableTotal: 0, - ownerAccountID: adminAccountID, - policyID, - reportID: reportID2, - reportName: 'Expense Report #123', - stateNum: 1, - statusNum: 1, - total: -5000, - type: 'expense', - unheldTotal: -5000, - }, - [`report_${reportID3}`]: { - accountID: adminAccountID, - chatReportID: '6155022250251839', - chatType: undefined, - created: '2025-03-05 16:34:27', - currency: 'VND', - isOneTransactionReport: false, - isOwnPolicyExpenseChat: false, - isPolicyExpenseChat: false, - isWaitingOnBankAccount: false, - managerID: approverAccountID, - nonReimbursableTotal: 0, - oldPolicyName: '', - ownerAccountID: adminAccountID, - policyID, - private_isArchived: '', - reportID: reportID3, - reportName: 'Report Name', - stateNum: 1, - statusNum: 1, - total: 4400, - type: 'iou', - unheldTotal: 4400, - }, - [`report_${reportID4}`]: { - accountID: adminAccountID, - reportID: reportID4, - chatReportID: '', - chatType: 'policyExpenseChat', - created: '2025-03-05 16:34:27', - type: 'chat', - }, - [`report_${reportID5}`]: { - accountID: adminAccountID, - action: 'view', - chatReportID: '1706144653204915', - created: '2024-12-21 13:05:20', - currency: 'USD', - isOneTransactionReport: true, - isPolicyExpenseChat: false, - isWaitingOnBankAccount: false, - managerID: adminAccountID, - nonReimbursableTotal: 0, - ownerAccountID: adminAccountID, - policyID, - reportID: reportID5, - reportName: 'Expense Report #123', - stateNum: 0, - statusNum: 0, - total: 0, - type: 'expense', - unheldTotal: 0, - }, + [`report_${reportID}`]: report1, + [`report_${reportID2}`]: report2, + [`report_${reportID3}`]: report3, + [`report_${reportID4}`]: report4, + [`report_${reportID5}`]: report5, [`transactions_${transactionID}`]: { accountID: adminAccountID, action: 'view', @@ -484,6 +494,7 @@ const transactionsListItems = [ accountID: 18439984, action: 'submit', amount: -5000, + report: report1, canDelete: true, canHold: true, canUnhold: false, @@ -554,6 +565,7 @@ const transactionsListItems = [ accountID: 18439984, action: 'review', amount: -5000, + report: report2, canDelete: true, canHold: true, canUnhold: false, @@ -629,6 +641,7 @@ const transactionsListItems = [ accountID: 18439984, amount: 1200, action: 'view', + report: report3, canDelete: true, canHold: true, canUnhold: false, @@ -699,6 +712,7 @@ const transactionsListItems = [ accountID: 18439984, amount: 3200, action: 'view', + report: report3, canDelete: true, canHold: true, canUnhold: false, @@ -804,6 +818,7 @@ const transactionReportGroupListItems = [ { accountID: 18439984, action: 'submit', + report: report1, amount: -5000, canDelete: true, canHold: true, @@ -911,6 +926,7 @@ const transactionReportGroupListItems = [ { accountID: 18439984, action: 'review', + report: report2, amount: -5000, canDelete: true, canHold: true, diff --git a/tests/unit/Search/handleActionButtonPressTest.ts b/tests/unit/Search/handleActionButtonPressTest.ts index 84e248b431fa..0c1902165a85 100644 --- a/tests/unit/Search/handleActionButtonPressTest.ts +++ b/tests/unit/Search/handleActionButtonPressTest.ts @@ -64,6 +64,9 @@ const mockReportItemWithHold = { }, transactions: [ { + report: { + reportID: '1350959062018695', + }, accountID: 1206, action: 'view', amount: -1200, @@ -139,6 +142,9 @@ const mockReportItemWithHold = { shouldAnimateInHighlight: false, }, { + report: { + reportID: '1350959062018695', + }, accountID: 1206, action: 'view', amount: -12300,