diff --git a/src/hooks/useReportActionsPagination.ts b/src/hooks/useReportActionsPagination.ts index 66f65895d20a..61b87c8f7318 100644 --- a/src/hooks/useReportActionsPagination.ts +++ b/src/hooks/useReportActionsPagination.ts @@ -1,4 +1,4 @@ -import {getReportPreviewAction} from '@libs/actions/IOU/MoneyRequestBuilder'; +import {getReportPreviewReportAction} from '@libs/actions/IOU/MoneyRequestBuilder'; import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; import {getCombinedReportActions, getFilteredReportActionsForReportView, isCreatedAction} from '@libs/ReportActionsUtils'; import {isConciergeChatReport, isInvoiceReport, isMoneyRequestReport, isReportTransactionThread as isReportTransactionThreadUtil, shouldReportAlignToTop} from '@libs/ReportUtils'; @@ -71,7 +71,10 @@ function useReportActionsPagination(reportID: string | undefined, reportActionID const shouldAddCreatedAction = !isCreatedAction(lastAction) && (isMoneyRequestReport(report) || isInvoiceReport(report) || isReportTransactionThread || isConciergeChat); const [chatReportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${getNonEmptyStringOnyxID(report?.chatReportID)}`); - const reportPreviewAction = useMemo(() => getReportPreviewAction(report?.chatReportID, report?.reportID, chatReportActions), [report?.chatReportID, report?.reportID, chatReportActions]); + const reportPreviewAction = useMemo( + () => getReportPreviewReportAction(report?.chatReportID, report?.reportID, chatReportActions), + [report?.chatReportID, report?.reportID, chatReportActions], + ); // When we are offline before opening an IOU/Expense report, // the total of the report and sometimes the expense aren't displayed because these actions aren't returned until `OpenReport` API is complete. diff --git a/src/libs/actions/IOU/DeleteMoneyRequest.ts b/src/libs/actions/IOU/DeleteMoneyRequest.ts index 32448477db55..2a1318664073 100644 --- a/src/libs/actions/IOU/DeleteMoneyRequest.ts +++ b/src/libs/actions/IOU/DeleteMoneyRequest.ts @@ -43,7 +43,7 @@ import cloneDeep from 'lodash/cloneDeep'; import Onyx from 'react-native-onyx'; import {getAllReportActionsFromIOU, getAllReportNameValuePairs, getAllReports, getAllTransactions, getAllTransactionViolations} from '.'; -import {getReportPreviewAction, maybeUpdateReportNameForFormulaTitle} from './MoneyRequestBuilder'; +import {getReportPreviewReportAction, maybeUpdateReportNameForFormulaTitle} from './MoneyRequestBuilder'; type PrepareToCleanUpMoneyRequestResult = { shouldDeleteTransactionThread: boolean; @@ -115,7 +115,7 @@ function prepareToCleanUpMoneyRequest({ // STEP 1: Get all collections we're updating const iouReportID = iouReport?.reportID; - const reportPreviewAction = getReportPreviewAction(iouReport?.chatReportID, iouReport?.reportID); + const reportPreviewAction = getReportPreviewReportAction(iouReport?.chatReportID, iouReport?.reportID); const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; const isTransactionOnHold = isOnHold(transaction); const transactionViolations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`]; @@ -693,7 +693,7 @@ function getCleanUpTransactionThreadReportOnyxData({ const iouReportID = isMoneyRequestAction(reportAction) ? reportAction?.reportID : undefined; const iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReportID}`]; const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReport?.chatReportID}`]; - const originalReportPreviewAction = getReportPreviewAction(chatReport?.reportID, iouReport?.reportID) ?? undefined; + const originalReportPreviewAction = getReportPreviewReportAction(chatReport?.reportID, iouReport?.reportID) ?? undefined; let reportPreviewAction = updatedReportPreviewAction ?? originalReportPreviewAction; if ( originalReportPreviewAction?.reportActionID && diff --git a/src/libs/actions/IOU/MoneyRequestBuilder.ts b/src/libs/actions/IOU/MoneyRequestBuilder.ts index d767fce52a6c..2e03d83581be 100644 --- a/src/libs/actions/IOU/MoneyRequestBuilder.ts +++ b/src/libs/actions/IOU/MoneyRequestBuilder.ts @@ -324,7 +324,7 @@ function buildMinimalTransactionForFormula( }; } -function getReportPreviewAction( +function getReportPreviewReportAction( chatReportID: string | undefined, iouReportID: string | undefined, chatReportActions?: OnyxEntry, @@ -1629,7 +1629,7 @@ function getMoneyRequestInformation(moneyRequestInformation: MoneyRequestInforma delegateAccountIDParam: delegateAccountID, }); - let reportPreviewAction = shouldCreateNewMoneyRequestReport ? null : getReportPreviewAction(chatReport.reportID, iouReport.reportID); + let reportPreviewAction = shouldCreateNewMoneyRequestReport ? null : getReportPreviewReportAction(chatReport.reportID, iouReport.reportID); if (reportPreviewAction) { reportPreviewAction = updateReportPreview(iouReport, reportPreviewAction, getCurrencyDecimals, false, comment, optimisticTransaction); @@ -1896,7 +1896,7 @@ export { calculateDiffAmount, getMoneyRequestInformation, getReceiptError, - getReportPreviewAction, + getReportPreviewReportAction, getTransactionWithPreservedLocalReceiptSource, getUpdatedMoneyRequestReportData, maybeUpdateReportNameForFormulaTitle, diff --git a/src/libs/actions/IOU/PayMoneyRequest.ts b/src/libs/actions/IOU/PayMoneyRequest.ts index 9337ea2c52f8..c77d047e71bd 100644 --- a/src/libs/actions/IOU/PayMoneyRequest.ts +++ b/src/libs/actions/IOU/PayMoneyRequest.ts @@ -51,7 +51,7 @@ import Onyx from 'react-native-onyx'; import {getAllPersonalDetails, getAllTransactionViolations} from '.'; import {getReportFromHoldRequestsOnyxData} from './Hold'; -import {getReportPreviewAction} from './MoneyRequestBuilder'; +import {getReportPreviewReportAction} from './MoneyRequestBuilder'; type PayInvoiceArgs = { paymentMethodType: PaymentMethodType; @@ -293,7 +293,7 @@ function getPayMoneyRequestParams({ // In some instances, the report preview action might not be available to the payer (only whispered to the requestor) // hence we need to make the updates to the action safely. let optimisticReportPreviewAction = null; - const reportPreviewAction = getReportPreviewAction(chatReport.reportID, iouReport?.reportID, chatReportActions); + const reportPreviewAction = getReportPreviewReportAction(chatReport.reportID, iouReport?.reportID, chatReportActions); if (reportPreviewAction) { optimisticReportPreviewAction = updateReportPreview(iouReport, reportPreviewAction, getCurrencyDecimals, true); } @@ -880,7 +880,7 @@ function markReportPaymentReceived( const receivedPaymentMessage = getElsewherePaymentReportActionMessage(translateLocal, optimisticIOUReportAction.originalMessage); optimisticIOUReportAction.message = [{html: receivedPaymentMessage, text: receivedPaymentMessage, isEdited: false, type: CONST.REPORT.MESSAGE.TYPE.COMMENT}]; - const reportPreviewAction = getReportPreviewAction(chatReport.reportID, iouReport.reportID, chatReportActions); + const reportPreviewAction = getReportPreviewReportAction(chatReport.reportID, iouReport.reportID, chatReportActions); const optimisticReportPreviewAction = reportPreviewAction ? updateReportPreview(iouReport, reportPreviewAction, getCurrencyDecimals, true) : null; const optimisticNextStep = buildOptimisticNextStep({report: iouReport, predictedNextStatus: CONST.REPORT.STATUS_NUM.REIMBURSED, isTrackIntentUser}); diff --git a/src/libs/actions/IOU/PerDiem.ts b/src/libs/actions/IOU/PerDiem.ts index 9fe643475f72..649af0c9a556 100644 --- a/src/libs/actions/IOU/PerDiem.ts +++ b/src/libs/actions/IOU/PerDiem.ts @@ -67,7 +67,7 @@ import {getAllPersonalDetails, getAllReports} from '.'; import { buildMinimalTransactionForFormula, buildOnyxDataForMoneyRequest, - getReportPreviewAction, + getReportPreviewReportAction, mergePolicyRecentlyUsedCategories, mergePolicyRecentlyUsedCurrencies, } from './MoneyRequestBuilder'; @@ -541,7 +541,7 @@ function getPerDiemExpenseInformation(perDiemExpenseInformation: PerDiemExpenseI shouldGenerateTransactionThreadReport: false, }); - let reportPreviewAction = shouldCreateNewMoneyRequestReport ? null : getReportPreviewAction(chatReport.reportID, iouReport.reportID); + let reportPreviewAction = shouldCreateNewMoneyRequestReport ? null : getReportPreviewReportAction(chatReport.reportID, iouReport.reportID); if (reportPreviewAction) { reportPreviewAction = updateReportPreview(iouReport, reportPreviewAction, getCurrencyDecimals, false, comment, optimisticTransaction); diff --git a/src/libs/actions/IOU/Split.ts b/src/libs/actions/IOU/Split.ts index 830d5893ff9b..534b618d2b5d 100644 --- a/src/libs/actions/IOU/Split.ts +++ b/src/libs/actions/IOU/Split.ts @@ -87,7 +87,7 @@ import { buildOnyxDataForMoneyRequest, getMoneyRequestInformation, getReceiptError, - getReportPreviewAction, + getReportPreviewReportAction, mergePolicyRecentlyUsedCategories, mergePolicyRecentlyUsedCurrencies, } from './MoneyRequestBuilder'; @@ -1142,7 +1142,7 @@ function completeSplitBill({ delegateAccountIDParam: delegateAccountID, }); - let oneOnOneReportPreviewAction = getReportPreviewAction(oneOnOneChatReport?.reportID, oneOnOneIOUReport?.reportID); + let oneOnOneReportPreviewAction = getReportPreviewReportAction(oneOnOneChatReport?.reportID, oneOnOneIOUReport?.reportID); if (oneOnOneReportPreviewAction) { oneOnOneReportPreviewAction = updateReportPreview(oneOnOneIOUReport, oneOnOneReportPreviewAction, getCurrencyDecimals); } else { @@ -1883,7 +1883,7 @@ function createSplitsAndOnyxData({ redundantParticipants[accountID] = null; } - let oneOnOneReportPreviewAction = getReportPreviewAction(oneOnOneChatReport.reportID, oneOnOneIOUReport.reportID); + let oneOnOneReportPreviewAction = getReportPreviewReportAction(oneOnOneChatReport.reportID, oneOnOneIOUReport.reportID); if (oneOnOneReportPreviewAction) { oneOnOneReportPreviewAction = updateReportPreview(oneOnOneIOUReport, oneOnOneReportPreviewAction, getCurrencyDecimals); } else { diff --git a/src/libs/actions/IOU/SplitTransactionUpdate.ts b/src/libs/actions/IOU/SplitTransactionUpdate.ts index 86ad8d93cf10..4bc33988cd56 100644 --- a/src/libs/actions/IOU/SplitTransactionUpdate.ts +++ b/src/libs/actions/IOU/SplitTransactionUpdate.ts @@ -83,7 +83,7 @@ import type {UpdateMoneyRequestDataKeys} from './UpdateMoneyRequest'; import {getCleanUpTransactionThreadReportOnyxData} from './DeleteMoneyRequest'; import {getAllReports} from './index'; import {getMoneyRequestParticipantsFromReport} from './MoneyRequest'; -import {getMoneyRequestInformation, getReportPreviewAction} from './MoneyRequestBuilder'; +import {getMoneyRequestInformation, getReportPreviewReportAction} from './MoneyRequestBuilder'; import {getDeleteTrackExpenseInformation} from './TrackExpense'; import {getUpdateMoneyRequestParams} from './UpdateMoneyRequest'; @@ -388,7 +388,7 @@ function updateSplitTransactions({ } let updatedReportPreviewAction: Partial | undefined; - const originalReportPreviewAction = getReportPreviewAction( + const originalReportPreviewAction = getReportPreviewReportAction( expenseReport?.chatReportID, expenseReport?.reportID, allReportActionsList?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport?.chatReportID}`], diff --git a/src/libs/actions/IOU/TrackExpense.ts b/src/libs/actions/IOU/TrackExpense.ts index 1fb47330142c..ce0369c7251d 100644 --- a/src/libs/actions/IOU/TrackExpense.ts +++ b/src/libs/actions/IOU/TrackExpense.ts @@ -124,7 +124,13 @@ import type { import {deleteMoneyRequest, getCleanUpTransactionThreadReportOnyxData, getNavigationUrlOnMoneyRequestDelete} from './DeleteMoneyRequest'; import {getAllReports, getAllTransactionDrafts, getAllTransactions, getAllTransactionViolations} from './index'; -import {buildMinimalTransactionForFormula, getMoneyRequestInformation, getReceiptError, getReportPreviewAction, getTransactionWithPreservedLocalReceiptSource} from './MoneyRequestBuilder'; +import { + buildMinimalTransactionForFormula, + getMoneyRequestInformation, + getReceiptError, + getReportPreviewReportAction, + getTransactionWithPreservedLocalReceiptSource, +} from './MoneyRequestBuilder'; import {highlightTransactionOnSearchRouteIfNeeded} from './NavigationHelpers'; import {addPendingNewTransactionIDs, isOneToTwoTransactionTransition} from './PendingNewTransactions'; import {getSearchOnyxUpdate} from './SearchUpdate'; @@ -1154,7 +1160,7 @@ function getTrackExpenseInformation(params: GetTrackExpenseInformationParams): T let reportPreviewAction: OnyxInputValue> = null; if (shouldUseMoneyReport && iouReport) { - reportPreviewAction = shouldCreateNewMoneyRequestReport ? null : getReportPreviewAction(chatReport.reportID, iouReport.reportID); + reportPreviewAction = shouldCreateNewMoneyRequestReport ? null : getReportPreviewReportAction(chatReport.reportID, iouReport.reportID); if (reportPreviewAction) { reportPreviewAction = updateReportPreview(iouReport, reportPreviewAction, getCurrencyDecimals, false, comment, optimisticTransaction); diff --git a/src/libs/actions/OnyxDerived/configs/reportAttributes.ts b/src/libs/actions/OnyxDerived/configs/reportAttributes.ts index 36c96db81e33..fe0270a77437 100644 --- a/src/libs/actions/OnyxDerived/configs/reportAttributes.ts +++ b/src/libs/actions/OnyxDerived/configs/reportAttributes.ts @@ -1,6 +1,6 @@ import type {LocalizedTranslate} from '@components/LocaleContextProvider'; -import {getReportPreviewAction} from '@libs/actions/IOU/MoneyRequestBuilder'; +import {getReportPreviewReportAction} from '@libs/actions/IOU/MoneyRequestBuilder'; import {translate as translateForLocale} from '@libs/Localize'; import {getIsOffline} from '@libs/NetworkState'; import {getLoginByAccountID} from '@libs/PersonalDetailsUtils'; @@ -29,7 +29,7 @@ import {hasKeyTriggeredCompute} from '@userActions/OnyxDerived/utils'; import CONST from '@src/CONST'; import IntlStore from '@src/languages/IntlStore'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {PersonalDetails, PersonalDetailsList, Policy, Report, ReportAttributesDerivedValue, Transaction, TransactionViolation} from '@src/types/onyx'; +import type {PersonalDetails, PersonalDetailsList, Policy, Report, ReportActions, ReportAttributesDerivedValue, Transaction, TransactionViolation} from '@src/types/onyx'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; @@ -163,14 +163,20 @@ const reportReferencesAccountIDs = (report: Report, accountIDs: Set): bo // Returns the report-preview action ID of the oldest child in `reportIDs` matching `predicate` // (oldest by preview-action creation time), or undefined when none match. -const getOldestPreviewActionID = (chatReportID: string, reportIDs: string[] | undefined, reports: OnyxCollection, predicate?: (childReport: OnyxEntry) => boolean) => { +const getOldestPreviewActionID = ( + chatReportID: string, + reportIDs: string[] | undefined, + reports: OnyxCollection, + chatReportActions: OnyxEntry, + predicate?: (childReport: OnyxEntry) => boolean, +) => { let oldestCreated: string | undefined; let targetReportActionID: string | undefined; for (const childReportID of reportIDs ?? []) { if (predicate && !predicate(reports?.[`${ONYXKEYS.COLLECTION.REPORT}${childReportID}`])) { continue; } - const reportPreviewAction = getReportPreviewAction(chatReportID, childReportID); + const reportPreviewAction = getReportPreviewReportAction(chatReportID, childReportID, chatReportActions); if (!reportPreviewAction) { continue; } @@ -700,10 +706,11 @@ export default createOnyxDerivedValueConfig({ const chatAttributes = reportAttributes[chatReportID]; let actionTargetReportActionID = chatAttributes.actionTargetReportActionID; + const chatReportActions = reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`]; actionTargetReportActionID = - getOldestPreviewActionID(chatReportID, erroredChildReportIDs, reports, isActionable) ?? - getOldestPreviewActionID(chatReportID, childReportIDsByChat.get(chatReportID), reports, (childReport) => + getOldestPreviewActionID(chatReportID, erroredChildReportIDs, reports, chatReportActions, isActionable) ?? + getOldestPreviewActionID(chatReportID, childReportIDsByChat.get(chatReportID), reports, chatReportActions, (childReport) => needsViolationFix( childReport, getLoginByAccountID(childReport?.ownerAccountID, personalDetails), @@ -713,7 +720,7 @@ export default createOnyxDerivedValueConfig({ currentUserEmail, ), ) ?? - getOldestPreviewActionID(chatReportID, erroredChildReportIDs, reports) ?? + getOldestPreviewActionID(chatReportID, erroredChildReportIDs, reports, chatReportActions) ?? actionTargetReportActionID; // Clone the entry before mutating — it may be a reference carried over from @@ -741,4 +748,4 @@ export default createOnyxDerivedValueConfig({ }, }); -export {hasPolicyRelevantFieldChanged}; +export {hasPolicyRelevantFieldChanged, getOldestPreviewActionID}; diff --git a/tests/actions/IOUTest/DeleteMoneyRequestTest.ts b/tests/actions/IOUTest/DeleteMoneyRequestTest.ts index 3fec5f3c1c7d..e4b7cc616b88 100644 --- a/tests/actions/IOUTest/DeleteMoneyRequestTest.ts +++ b/tests/actions/IOUTest/DeleteMoneyRequestTest.ts @@ -1,5 +1,5 @@ import {deleteMoneyRequest, getCleanUpTransactionThreadReportOnyxData} from '@libs/actions/IOU/DeleteMoneyRequest'; -import {getReportPreviewAction} from '@libs/actions/IOU/MoneyRequestBuilder'; +import {getReportPreviewReportAction} from '@libs/actions/IOU/MoneyRequestBuilder'; import {requestMoney} from '@libs/actions/IOU/TrackExpense'; import {updateMoneyRequestAmountAndCurrency} from '@libs/actions/IOU/UpdateMoneyRequest'; import initOnyxDerivedValues from '@libs/actions/OnyxDerived'; @@ -1159,7 +1159,7 @@ describe('actions/IOU/DeleteMoneyRequest', () => { expect(iouReport).toHaveProperty('chatReportID'); expect(iouReport?.total).toBe(30000); - const iouPreview = chatReport?.reportID && iouReport?.reportID ? getReportPreviewAction(chatReport.reportID, iouReport.reportID) : undefined; + const iouPreview = chatReport?.reportID && iouReport?.reportID ? getReportPreviewReportAction(chatReport.reportID, iouReport.reportID) : undefined; expect(iouPreview).toBeTruthy(); expect(getReportActionText(iouPreview)).toBe('rory@expensifail.com owes $300.00'); @@ -1469,7 +1469,7 @@ describe('actions/IOU/DeleteMoneyRequest', () => { jest.advanceTimersByTime(10); // When a comment is added - let iouPreview = getReportPreviewAction(chatReport?.reportID, iouReport?.reportID); + let iouPreview = getReportPreviewReportAction(chatReport?.reportID, iouReport?.reportID); const ancestors = []; ancestors.push(...(iouReport && createIOUAction ? [{report: iouReport, reportAction: createIOUAction, shouldDisplayNewMarker: false}] : [])); ancestors.push(...(chatReport && iouPreview ? [{report: chatReport, reportAction: iouPreview, shouldDisplayNewMarker: false}] : [])); @@ -1513,7 +1513,7 @@ describe('actions/IOU/DeleteMoneyRequest', () => { expect(createIOUAction?.childVisibleActionCount).toEqual(1); expect(createIOUAction?.childCommenterCount).toEqual(1); - iouPreview = getReportPreviewAction(chatReport?.reportID, iouReport?.reportID); + iouPreview = getReportPreviewReportAction(chatReport?.reportID, iouReport?.reportID); expect(iouPreview).toBeTruthy(); expect(iouPreview?.childVisibleActionCount).toEqual(1); expect(iouPreview?.childCommenterCount).toEqual(1); @@ -1541,7 +1541,7 @@ describe('actions/IOU/DeleteMoneyRequest', () => { // Then we expect the reportPreview to update with new childVisibleActionCount - iouPreview = getReportPreviewAction(chatReport?.reportID, iouReport?.reportID); + iouPreview = getReportPreviewReportAction(chatReport?.reportID, iouReport?.reportID); expect(iouPreview).toBeTruthy(); expect(iouPreview?.childVisibleActionCount).toEqual(0); expect(iouPreview?.childCommenterCount).toEqual(0); @@ -1551,7 +1551,7 @@ describe('actions/IOU/DeleteMoneyRequest', () => { await waitForBatchedUpdates(); // Then we expect the reportPreview to update with new childVisibleActionCount - iouPreview = getReportPreviewAction(chatReport?.reportID, iouReport?.reportID); + iouPreview = getReportPreviewReportAction(chatReport?.reportID, iouReport?.reportID); expect(iouPreview).toBeTruthy(); expect(iouPreview?.childVisibleActionCount).toEqual(0); expect(iouPreview?.childCommenterCount).toEqual(0); diff --git a/tests/actions/IOUTest/DuplicateTest.ts b/tests/actions/IOUTest/DuplicateTest.ts index e637b34451cc..ba5dfefbc766 100644 --- a/tests/actions/IOUTest/DuplicateTest.ts +++ b/tests/actions/IOUTest/DuplicateTest.ts @@ -3,7 +3,7 @@ import type {RenderAPI} from '@testing-library/react-native'; import {bulkDuplicateExpenses, bulkDuplicateReports, duplicateExpenseTransaction, duplicateReport, mergeDuplicates, resolveDuplicates} from '@libs/actions/IOU/Duplicate'; import type {BulkDuplicateReportsParams, DuplicateReportParams} from '@libs/actions/IOU/Duplicate'; -import {getReportPreviewAction} from '@libs/actions/IOU/MoneyRequestBuilder'; +import {getReportPreviewReportAction} from '@libs/actions/IOU/MoneyRequestBuilder'; import initOnyxDerivedValues from '@libs/actions/OnyxDerived'; import {addComment, openReport} from '@libs/actions/Report'; import type {MergeDuplicatesParams} from '@libs/API/parameters'; @@ -679,7 +679,7 @@ describe('actions/Duplicate', () => { await waitForBatchedUpdates(); // Then we expect the reportPreview to update with new childVisibleActionCount - previewAction = getReportPreviewAction(chatReport?.reportID, expenseReport?.reportID) ?? undefined; + previewAction = getReportPreviewReportAction(chatReport?.reportID, expenseReport?.reportID) ?? undefined; expect(previewAction).toBeTruthy(); expect(previewAction?.childVisibleActionCount).toEqual(0); expect(previewAction?.childCommenterCount).toEqual(0); diff --git a/tests/actions/IOUTest/SplitTest.ts b/tests/actions/IOUTest/SplitTest.ts index 79270539ce79..1f1dd3764a2c 100644 --- a/tests/actions/IOUTest/SplitTest.ts +++ b/tests/actions/IOUTest/SplitTest.ts @@ -3,7 +3,7 @@ import type {RenderAPI} from '@testing-library/react-native'; import {putOnHold} from '@libs/actions/IOU/Hold'; -import {getReportPreviewAction} from '@libs/actions/IOU/MoneyRequestBuilder'; +import {getReportPreviewReportAction} from '@libs/actions/IOU/MoneyRequestBuilder'; import {requestMoney} from '@libs/actions/IOU/TrackExpense'; import initOnyxDerivedValues from '@libs/actions/OnyxDerived'; import {createWorkspace, generatePolicyID, setWorkspaceApprovalMode} from '@libs/actions/Policy/Policy'; @@ -5800,7 +5800,7 @@ describe('updateSplitTransactions', () => { await waitForBatchedUpdates(); const iouAction = getIOUActionForReportID(expenseReport?.reportID, originalTransactionID); - const iouPreview = getReportPreviewAction(expenseReport?.chatReportID, expenseReport?.reportID); + const iouPreview = getReportPreviewReportAction(expenseReport?.chatReportID, expenseReport?.reportID); expect(iouAction?.childVisibleActionCount).toEqual(1); expect(iouPreview?.childVisibleActionCount).toEqual(1); @@ -5822,7 +5822,7 @@ describe('updateSplitTransactions', () => { expect(Object.values(split2ReportActions ?? {}).some((action) => action?.actionName === CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT)).toBe(true); // The report preview should reflect both held child threads. - const updatedReportPreviewAction = getReportPreviewAction(expenseReport?.chatReportID, expenseReport?.reportID); + const updatedReportPreviewAction = getReportPreviewReportAction(expenseReport?.chatReportID, expenseReport?.reportID); expect(updatedReportPreviewAction).toBeTruthy(); expect(updatedReportPreviewAction?.childVisibleActionCount).toEqual(2); }); @@ -5852,7 +5852,7 @@ describe('updateSplitTransactions', () => { await waitForBatchedUpdates(); const iouAction = getIOUActionForReportID(expenseReport?.reportID, originalTransactionID); - const iouPreview = getReportPreviewAction(expenseReport?.chatReportID, expenseReport?.reportID); + const iouPreview = getReportPreviewReportAction(expenseReport?.chatReportID, expenseReport?.reportID); expect(iouAction?.childVisibleActionCount).toEqual(1); expect(iouPreview?.childVisibleActionCount).toEqual(1); @@ -5886,7 +5886,7 @@ describe('updateSplitTransactions', () => { writeSpy.mockRestore(); // The report preview should reflect both held child threads. - const updatedReportPreviewAction = getReportPreviewAction(expenseReport?.chatReportID, expenseReport?.reportID); + const updatedReportPreviewAction = getReportPreviewReportAction(expenseReport?.chatReportID, expenseReport?.reportID); expect(updatedReportPreviewAction).toBeTruthy(); expect(updatedReportPreviewAction?.childVisibleActionCount).toEqual(2); }); @@ -5915,7 +5915,7 @@ describe('updateSplitTransactions', () => { await waitForBatchedUpdates(); const originalIOUAction = getIOUActionForReportID(expenseReport?.reportID, originalTransactionID); - const originalReportPreviewAction = getReportPreviewAction(expenseReport?.chatReportID, expenseReport?.reportID); + const originalReportPreviewAction = getReportPreviewReportAction(expenseReport?.chatReportID, expenseReport?.reportID); expect(originalIOUAction?.childVisibleActionCount).toEqual(1); expect(originalReportPreviewAction?.childVisibleActionCount).toEqual(1); @@ -5926,7 +5926,7 @@ describe('updateSplitTransactions', () => { const {splitTransactionID1, splitTransactionID2} = await splitToTwo(expenseReport, originalTransactionID, originalIOUAction); const splitIOUAction1 = getIOUActionForReportID(expenseReport?.reportID, splitTransactionID1); const splitIOUAction2 = getIOUActionForReportID(expenseReport?.reportID, splitTransactionID2); - const updatedReportPreviewAction = getReportPreviewAction(expenseReport?.chatReportID, expenseReport?.reportID); + const updatedReportPreviewAction = getReportPreviewReportAction(expenseReport?.chatReportID, expenseReport?.reportID); // Ensure childVisibleActionCount updates correctly expect(splitIOUAction1?.childVisibleActionCount).toEqual(1); @@ -5967,7 +5967,7 @@ describe('updateSplitTransactions', () => { await waitForBatchedUpdates(); const iouAction = getIOUActionForReportID(expenseReport?.reportID, splitTransactionID1); - const iouPreview = getReportPreviewAction(expenseReport?.chatReportID, expenseReport?.reportID); + const iouPreview = getReportPreviewReportAction(expenseReport?.chatReportID, expenseReport?.reportID); expect(iouAction?.childVisibleActionCount).toEqual(2); expect(iouPreview?.childVisibleActionCount).toEqual(2); @@ -6048,7 +6048,7 @@ describe('updateSplitTransactions', () => { ); // The report preview must reflect these changes. - const updatedReportPreviewAction = getReportPreviewAction(chatReport?.reportID, expenseReport?.reportID); + const updatedReportPreviewAction = getReportPreviewReportAction(chatReport?.reportID, expenseReport?.reportID); expect(updatedReportPreviewAction?.childVisibleActionCount).toEqual(2); }); @@ -6168,7 +6168,7 @@ describe('updateSplitTransactions', () => { await waitForBatchedUpdates(); const iouAction = getIOUActionForReportID(expenseReport?.reportID, originalTransactionID); - const iouPreview = getReportPreviewAction(expenseReport?.chatReportID, expenseReport?.reportID); + const iouPreview = getReportPreviewReportAction(expenseReport?.chatReportID, expenseReport?.reportID); expect(iouAction?.childVisibleActionCount).toEqual(1); expect(iouPreview?.childVisibleActionCount).toEqual(1); @@ -6216,7 +6216,7 @@ describe('updateSplitTransactions', () => { }); await waitForBatchedUpdates(); - const updatedReportPreviewAction = getReportPreviewAction(chatReport?.reportID, expenseReport?.reportID); + const updatedReportPreviewAction = getReportPreviewReportAction(chatReport?.reportID, expenseReport?.reportID); expect(updatedReportPreviewAction?.childVisibleActionCount).toEqual(2); }); @@ -6288,7 +6288,7 @@ describe('updateSplitTransactions', () => { }); await waitForBatchedUpdates(); - const updatedReportPreviewAction = getReportPreviewAction(chatReport?.reportID, expenseReport?.reportID); + const updatedReportPreviewAction = getReportPreviewReportAction(chatReport?.reportID, expenseReport?.reportID); expect(updatedReportPreviewAction?.childVisibleActionCount).toEqual(2); }); @@ -6321,9 +6321,9 @@ describe('updateSplitTransactions', () => { const reports = getTransactionAndExpenseReports(expenseReport.reportID); // Capture the preview action's count after the split-to-three setup, before our isolated call. - const countBeforeUpdate = getReportPreviewAction(chatReport?.reportID, expenseReport?.reportID)?.childVisibleActionCount; + const countBeforeUpdate = getReportPreviewReportAction(chatReport?.reportID, expenseReport?.reportID)?.childVisibleActionCount; - // Provide a non-nullish but empty actions slice for the chat report. getReportPreviewAction + // Provide a non-nullish but empty actions slice for the chat report. getReportPreviewReportAction // uses the param directly (no legacy fallback), finds no preview action, and skips the update. const emptyChatReportActions = {[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.chatReportID}`]: {}}; @@ -6368,7 +6368,7 @@ describe('updateSplitTransactions', () => { // Because no preview action was found via the param, the update is skipped and the count stays unchanged. // (The test 'should resolve the report preview action from the allReportActionsList param' proves the // same scenario bumps the count to 2 when the param supplies the preview action.) - const reportPreviewAction = getReportPreviewAction(chatReport?.reportID, expenseReport?.reportID); + const reportPreviewAction = getReportPreviewReportAction(chatReport?.reportID, expenseReport?.reportID); expect(reportPreviewAction?.childVisibleActionCount).toEqual(countBeforeUpdate); expect(reportPreviewAction?.childVisibleActionCount).not.toEqual(2); }); diff --git a/tests/actions/MergeTransactionTest.ts b/tests/actions/MergeTransactionTest.ts index a7eb4fe2cfc6..7ea44053399f 100644 --- a/tests/actions/MergeTransactionTest.ts +++ b/tests/actions/MergeTransactionTest.ts @@ -1,4 +1,4 @@ -import {getReportPreviewAction} from '@libs/actions/IOU/MoneyRequestBuilder'; +import {getReportPreviewReportAction} from '@libs/actions/IOU/MoneyRequestBuilder'; import {areTransactionsEligibleForMerge, getTransactionsForMerging, mergeTransactionRequest, setMergeTransactionKey, setupMergeTransactionData} from '@libs/actions/MergeTransaction'; import {addComment, openReport} from '@libs/actions/Report'; import {WRITE_COMMANDS} from '@libs/API/types'; @@ -1279,7 +1279,7 @@ describe('mergeTransactionRequest', () => { await waitForBatchedUpdates(); // Then we expect the reportPreview to update with new childVisibleActionCount - previewAction = getReportPreviewAction(chatReport.reportID, sourceReport.reportID) as OnyxEntry; + previewAction = getReportPreviewReportAction(chatReport.reportID, sourceReport.reportID) as OnyxEntry; expect(previewAction).toBeTruthy(); expect(previewAction?.childVisibleActionCount).toEqual(0); expect(previewAction?.childCommenterCount).toEqual(0); @@ -1301,7 +1301,7 @@ describe('mergeTransactionRequest', () => { await waitForBatchedUpdates(); // Then we expect the reportPreview to update with new childVisibleActionCount - previewAction = getReportPreviewAction(chatReport.reportID, sourceReport.reportID) as OnyxEntry; + previewAction = getReportPreviewReportAction(chatReport.reportID, sourceReport.reportID) as OnyxEntry; expect(previewAction).toBeTruthy(); expect(previewAction?.childVisibleActionCount).toEqual(0); expect(previewAction?.childCommenterCount).toEqual(0); diff --git a/tests/unit/reportAttributesTest.ts b/tests/unit/reportAttributesTest.ts index a75fd1f490ae..c823bae6b2ed 100644 --- a/tests/unit/reportAttributesTest.ts +++ b/tests/unit/reportAttributesTest.ts @@ -1,15 +1,16 @@ import type reportAttributesModuleDefault from '@userActions/OnyxDerived/configs/reportAttributes'; -import {hasPolicyRelevantFieldChanged} from '@userActions/OnyxDerived/configs/reportAttributes'; +import {getOldestPreviewActionID, hasPolicyRelevantFieldChanged} from '@userActions/OnyxDerived/configs/reportAttributes'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {OnyxKey} from '@src/ONYXKEYS'; -import type {Policy, Report, ReportAttributesDerivedValue, Transaction} from '@src/types/onyx'; +import type {Policy, Report, ReportAction, ReportActions, ReportAttributesDerivedValue, Transaction} from '@src/types/onyx'; import type {OnyxCollection} from 'react-native-onyx'; import {createRandomReport} from '../utils/collections/reports'; import createRandomTransaction from '../utils/collections/transaction'; +import createMock from '../utils/createMock'; type ReportAttributesConfig = typeof reportAttributesModuleDefault; @@ -132,6 +133,105 @@ describe('hasPolicyRelevantFieldChanged', () => { }); }); +describe('getOldestPreviewActionID', () => { + const chatReportID = 'chat1'; + + const createReportPreviewAction = (reportActionID: string, linkedReportID: string, created: string): ReportAction => ({ + reportActionID, + actionName: CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW, + created, + originalMessage: {linkedReportID}, + message: [{type: 'COMMENT', text: ''}], + }); + + it('returns undefined when reportIDs is undefined', () => { + expect(getOldestPreviewActionID(chatReportID, undefined, {}, {})).toBeUndefined(); + }); + + it('returns undefined when reportIDs is empty', () => { + expect(getOldestPreviewActionID(chatReportID, [], {}, {})).toBeUndefined(); + }); + + it('returns the reportActionID of the only child report with a matching preview action', () => { + const childReport = createRandomReport(1); + const previewAction = createReportPreviewAction('action1', childReport.reportID, '2024-01-01 12:00:00'); + const reports: OnyxCollection = {[`${ONYXKEYS.COLLECTION.REPORT}${childReport.reportID}`]: childReport}; + const chatReportActions: ReportActions = {[previewAction.reportActionID]: previewAction}; + + expect(getOldestPreviewActionID(chatReportID, [childReport.reportID], reports, chatReportActions)).toBe('action1'); + }); + + it('returns the reportActionID of the oldest preview action among multiple matching child reports', () => { + const childReport1 = createRandomReport(1); + const childReport2 = createRandomReport(2); + const olderPreviewAction = createReportPreviewAction('olderAction', childReport1.reportID, '2024-01-01 12:00:00'); + const newerPreviewAction = createReportPreviewAction('newerAction', childReport2.reportID, '2024-06-01 12:00:00'); + const reports: OnyxCollection = { + [`${ONYXKEYS.COLLECTION.REPORT}${childReport1.reportID}`]: childReport1, + [`${ONYXKEYS.COLLECTION.REPORT}${childReport2.reportID}`]: childReport2, + }; + const chatReportActions: ReportActions = { + [olderPreviewAction.reportActionID]: olderPreviewAction, + [newerPreviewAction.reportActionID]: newerPreviewAction, + }; + + expect(getOldestPreviewActionID(chatReportID, [childReport2.reportID, childReport1.reportID], reports, chatReportActions)).toBe('olderAction'); + }); + + it('skips child reports that have no matching preview action', () => { + const childReportWithoutPreview = createRandomReport(1); + const childReportWithPreview = createRandomReport(2); + const previewAction = createReportPreviewAction('action1', childReportWithPreview.reportID, '2024-01-01 12:00:00'); + const reports: OnyxCollection = { + [`${ONYXKEYS.COLLECTION.REPORT}${childReportWithoutPreview.reportID}`]: childReportWithoutPreview, + [`${ONYXKEYS.COLLECTION.REPORT}${childReportWithPreview.reportID}`]: childReportWithPreview, + }; + const chatReportActions: ReportActions = {[previewAction.reportActionID]: previewAction}; + + expect(getOldestPreviewActionID(chatReportID, [childReportWithoutPreview.reportID, childReportWithPreview.reportID], reports, chatReportActions)).toBe('action1'); + }); + + it('returns undefined when no child report has a matching preview action', () => { + const childReport = createRandomReport(1); + const reports: OnyxCollection = {[`${ONYXKEYS.COLLECTION.REPORT}${childReport.reportID}`]: childReport}; + + expect(getOldestPreviewActionID(chatReportID, [childReport.reportID], reports, {})).toBeUndefined(); + }); + + it('excludes child reports that fail the predicate', () => { + const excludedReport = createRandomReport(1); + const includedReport = createRandomReport(2); + const excludedPreviewAction = createReportPreviewAction('excludedAction', excludedReport.reportID, '2024-01-01 12:00:00'); + const includedPreviewAction = createReportPreviewAction('includedAction', includedReport.reportID, '2024-06-01 12:00:00'); + const reports: OnyxCollection = { + [`${ONYXKEYS.COLLECTION.REPORT}${excludedReport.reportID}`]: excludedReport, + [`${ONYXKEYS.COLLECTION.REPORT}${includedReport.reportID}`]: includedReport, + }; + const chatReportActions: ReportActions = { + [excludedPreviewAction.reportActionID]: excludedPreviewAction, + [includedPreviewAction.reportActionID]: includedPreviewAction, + }; + const predicate = (report: Report | undefined) => report?.reportID === includedReport.reportID; + + expect(getOldestPreviewActionID(chatReportID, [excludedReport.reportID, includedReport.reportID], reports, chatReportActions, predicate)).toBe('includedAction'); + }); + + it('ignores non-REPORT_PREVIEW actions even when linkedReportID matches', () => { + const childReport = createRandomReport(1); + const nonPreviewAction = createMock({ + reportActionID: 'commentAction1', + actionName: CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT, + created: '2024-01-01 12:00:00', + originalMessage: {linkedReportID: childReport.reportID}, + message: [{type: 'COMMENT', text: ''}], + }); + const reports: OnyxCollection = {[`${ONYXKEYS.COLLECTION.REPORT}${childReport.reportID}`]: childReport}; + const chatReportActions: ReportActions = {[nonPreviewAction.reportActionID]: nonPreviewAction}; + + expect(getOldestPreviewActionID(chatReportID, [childReport.reportID], reports, chatReportActions)).toBeUndefined(); + }); +}); + describe('reportAttributes compute — policy change code flow', () => { let config: ReportAttributesConfig;