diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 9c5e437a874e..ebfde73151e5 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3552,9 +3552,18 @@ function buildOptimisticTaskCommentReportAction( * @param chatReportID - Report ID of the chat where the IOU is. * @param currency - IOU currency. * @param isSendingMoney - If we pay someone the IOU should be created as settled + * @param created - The creation time for IOU action */ -function buildOptimisticIOUReport(payeeAccountID: number, payerAccountID: number, total: number, chatReportID: string, currency: string, isSendingMoney = false): OptimisticIOUReport { +function buildOptimisticIOUReport( + payeeAccountID: number, + payerAccountID: number, + total: number, + chatReportID: string, + currency: string, + isSendingMoney = false, + created: string = DateUtils.getDBTime(), +): OptimisticIOUReport { const formattedTotal = CurrencyUtils.convertToDisplayString(total, currency); const personalDetails = getPersonalDetailsForAccountID(payerAccountID); const payerEmail = 'login' in personalDetails ? personalDetails.login : ''; @@ -3580,7 +3589,7 @@ function buildOptimisticIOUReport(payeeAccountID: number, payerAccountID: number reportName: `${payerEmail} owes ${formattedTotal}`, notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, parentReportID: chatReportID, - lastVisibleActionCreated: DateUtils.getDBTime(), + lastVisibleActionCreated: created, }; } @@ -4049,7 +4058,7 @@ function buildOptimisticReportPreview(chatReport: OnyxEntry, iouReport: const hasReceipt = TransactionUtils.hasReceipt(transaction); const isReceiptBeingScanned = hasReceipt && TransactionUtils.isReceiptBeingScanned(transaction); const message = getReportPreviewMessage(iouReport); - const created = DateUtils.getDBTime(); + const created = iouReport.lastVisibleActionCreated ?? DateUtils.getDBTime(); return { reportActionID: NumberUtils.rand64(), reportID: chatReport?.reportID, @@ -4797,10 +4806,10 @@ function buildOptimisticMoneyRequestEntities( existingTransactionThreadReportID?: string, linkedTrackedExpenseReportAction?: ReportAction, ): [OptimisticCreatedReportAction, OptimisticCreatedReportAction, OptimisticIOUReportAction, OptimisticChatReport, OptimisticCreatedReportAction | EmptyObject] { - const createdActionForChat = buildOptimisticCreatedReportAction(payeeEmail); + const createdActionForChat = buildOptimisticCreatedReportAction(payeeEmail, iouReport.lastVisibleActionCreated); // The `CREATED` action must be optimistically generated before the IOU action so that it won't appear after the IOU action in the chat. - const iouActionCreationTime = DateUtils.getDBTime(); + const iouActionCreationTime = !iouReport.lastVisibleActionCreated || isEmpty(iouReport.lastVisibleActionCreated) ? DateUtils.getDBTime() : iouReport.lastVisibleActionCreated; const createdActionForIOUReport = buildOptimisticCreatedReportAction(payeeEmail, DateUtils.subtractMillisecondsFromDateTime(iouActionCreationTime, 1)); const iouAction = buildOptimisticIOUReportAction( diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index e0b406ad9c45..4e54124596e6 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -463,7 +463,6 @@ function buildOnyxDataForMoneyRequest( newQuickAction = CONST.QUICK_ACTIONS.REQUEST_DISTANCE; } const existingTransactionThreadReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${existingTransactionThreadReportID}`] ?? null; - if (chatReport) { optimisticData.push({ // Use SET for new reports because it doesn't exist yet, is faster and we need the data to be available when we navigate to the chat page @@ -471,6 +470,8 @@ function buildOnyxDataForMoneyRequest( key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, value: { ...chatReport, + // if it is a new money request then that becomes the most recent visible action + lastVisibleActionCreated: shouldCreateNewMoneyRequestReport ? iouReport.lastVisibleActionCreated : undefined, lastReadTime: DateUtils.getDBTime(), lastMessageTranslationKey: '', iouReportID: iouReport.reportID, @@ -1794,7 +1795,7 @@ function getMoneyRequestInformation( if (!iouReport || shouldCreateNewMoneyRequestReport) { iouReport = isPolicyExpenseChat ? ReportUtils.buildOptimisticExpenseReport(chatReport.reportID, chatReport.policyID ?? '', payeeAccountID, amount, currency) - : ReportUtils.buildOptimisticIOUReport(payeeAccountID, payerAccountID, amount, chatReport.reportID, currency); + : ReportUtils.buildOptimisticIOUReport(payeeAccountID, payerAccountID, amount, chatReport.reportID, currency, false, created); } else if (isPolicyExpenseChat) { iouReport = {...iouReport}; if (iouReport?.currency === currency && typeof iouReport.total === 'number') { @@ -1804,6 +1805,7 @@ function getMoneyRequestInformation( } else { iouReport = IOUUtils.updateIOUOwnerAndTotal(iouReport, payeeAccountID, amount, currency); } + // STEP 3: Build optimistic receipt and transaction const receiptObject: Receipt = {}; let filename; diff --git a/src/pages/home/report/ReportActionsList.tsx b/src/pages/home/report/ReportActionsList.tsx index 7d95d3555502..8ec82bed7a4e 100644 --- a/src/pages/home/report/ReportActionsList.tsx +++ b/src/pages/home/report/ReportActionsList.tsx @@ -200,7 +200,8 @@ function ReportActionsList({ ); const lastActionIndex = sortedVisibleReportActions[0]?.reportActionID; const reportActionSize = useRef(sortedVisibleReportActions.length); - const hasNewestReportAction = sortedReportActions?.[0].created === report.lastVisibleActionCreated; + const hasNewestReportAction = + sortedReportActions?.[0].created === report.lastVisibleActionCreated || sortedReportActions?.[0].created === transactionThreadReport?.lastVisibleActionCreated || sortedReportActions.some((reportAction) => reportAction.created === report.lastVisibleActionCreated); const hasNewestReportActionRef = useRef(hasNewestReportAction); hasNewestReportActionRef.current = hasNewestReportAction; const previousLastIndex = useRef(lastActionIndex); diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index 45bdc5fe743a..161cc30e8fce 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -246,6 +246,7 @@ describe('actions/IOU', () => { it('updates existing chat report if there is one', () => { const amount = 10000; const comment = 'Giv money plz'; + const created = DateUtils.getDBTime(); let chatReport: OnyxTypes.Report = { reportID: '1234', type: CONST.REPORT.TYPE.CHAT, @@ -254,7 +255,7 @@ describe('actions/IOU', () => { const createdAction: OnyxTypes.ReportAction = { reportActionID: NumberUtils.rand64(), actionName: CONST.REPORT.ACTIONS.TYPE.CREATED, - created: DateUtils.getDBTime(), + created, }; let iouReportID: string | undefined; let iouAction: OnyxEntry; @@ -270,7 +271,7 @@ describe('actions/IOU', () => { }), ) .then(() => { - IOU.requestMoney(chatReport, amount, CONST.CURRENCY.USD, '', '', RORY_EMAIL, RORY_ACCOUNT_ID, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment, {}); + IOU.requestMoney(chatReport, amount, CONST.CURRENCY.USD, created, '', RORY_EMAIL, RORY_ACCOUNT_ID, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment, {}); return waitForBatchedUpdates(); }) .then( @@ -318,6 +319,10 @@ describe('actions/IOU', () => { // The CREATED action should not be created after the IOU action expect(Date.parse(iouCreatedAction?.created ?? '')).toBeLessThan(Date.parse(iouAction?.created ?? '')); + // The iouAction created time should be same as lastVisibleActionCreated + // To prevent the "New message" from showing up in the report list + expect(iouAction?.created).toBe(chatReport.lastVisibleActionCreated); + // The IOUReportID should be correct expect(iouAction?.originalMessage?.IOUReportID).toBe(iouReportID);