From bd1c53d6e22abc4938c80143e97006720a6fc515 Mon Sep 17 00:00:00 2001 From: Jaime Liz Date: Wed, 3 Apr 2024 19:00:57 -0500 Subject: [PATCH 1/6] test: add a failing test --- tests/actions/IOUTest.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index 2ce72a58aead..51c09966810c 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); From 3dc5330f3a5e624c8810a4d4d0b3da48d18f67e4 Mon Sep 17 00:00:00 2001 From: Jaime Liz Date: Wed, 3 Apr 2024 19:14:27 -0500 Subject: [PATCH 2/6] refactor: use original time in optimistic iou report creation --- src/libs/ReportUtils.ts | 19 ++++++++++++++----- src/libs/actions/IOU.ts | 1 + 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 98577e73766a..e7df21a82355 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3193,9 +3193,18 @@ function buildOptimisticTaskCommentReportAction(taskReportID: string, taskTitle: * @param chatReportID - Report ID of the chat where the IOU is. * @param currency - IOU currency. * @param isSendingMoney - If we send money 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 : ''; @@ -3221,7 +3230,7 @@ function buildOptimisticIOUReport(payeeAccountID: number, payerAccountID: number reportName: `${payerEmail} owes ${formattedTotal}`, notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, parentReportID: chatReportID, - lastVisibleActionCreated: DateUtils.getDBTime(), + lastVisibleActionCreated: created, }; } @@ -3586,7 +3595,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, @@ -4234,10 +4243,10 @@ function buildOptimisticMoneyRequestEntities( receipt: Receipt = {}, isOwnPolicyExpenseChat = false, ): [OptimisticCreatedReportAction, OptimisticCreatedReportAction, OptimisticIOUReportAction, OptimisticChatReport, OptimisticCreatedReportAction] { - 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 ?? DateUtils.getDBTime(); const createdActionForIOUReport = buildOptimisticCreatedReportAction(payeeEmail, DateUtils.subtractMillisecondsFromDateTime(iouActionCreationTime, 1)); const iouAction = buildOptimisticIOUReportAction( type, diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 5c92cd87a2bc..eabcfbb64520 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -523,6 +523,7 @@ function buildOnyxDataForMoneyRequest( key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, value: { ...chatReport, + lastVisibleActionCreated: iouReport.lastVisibleActionCreated, lastReadTime: DateUtils.getDBTime(), lastMessageTranslationKey: '', iouReportID: iouReport.reportID, From ed24e3b96db98bbf33120fd927d4e62d9ff659e5 Mon Sep 17 00:00:00 2001 From: Jaime Liz Date: Thu, 4 Apr 2024 17:12:04 -0500 Subject: [PATCH 3/6] feat: update optimistic iou report date and only update last visible for new ious --- src/libs/actions/IOU.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 1e4b7df76944..2196e89b7b68 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -485,7 +485,8 @@ function buildOnyxDataForMoneyRequest( key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, value: { ...chatReport, - lastVisibleActionCreated: iouReport.lastVisibleActionCreated, + // if iouReport exist, the last visible action created time does not change. + lastVisibleActionCreated: isNewChatReport ? undefined : iouReport.lastVisibleActionCreated, lastReadTime: DateUtils.getDBTime(), lastMessageTranslationKey: '', iouReportID: iouReport.reportID, @@ -1034,7 +1035,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') { From e9c2e1aa6aaad3e494930a2b6c58ae0e970a8682 Mon Sep 17 00:00:00 2001 From: Jaime Liz Date: Mon, 15 Apr 2024 19:16:34 -0500 Subject: [PATCH 4/6] fix: avoid setting iouCreationTime to empty str --- src/libs/ReportUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 07b455c3632d..f237334de9ba 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4385,7 +4385,7 @@ function buildOptimisticMoneyRequestEntities( 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 = iouReport.lastVisibleActionCreated ?? DateUtils.getDBTime(); + const iouActionCreationTime = !iouReport.lastVisibleActionCreated || isEmpty(iouReport.lastVisibleActionCreated) ? DateUtils.getDBTime() : iouReport.lastVisibleActionCreated; const createdActionForIOUReport = buildOptimisticCreatedReportAction(payeeEmail, DateUtils.subtractMillisecondsFromDateTime(iouActionCreationTime, 1)); const iouAction = buildOptimisticIOUReportAction( type, From e40dd6e6b684a09f54b95afbd1a85e945678316c Mon Sep 17 00:00:00 2001 From: Jaime Liz Date: Tue, 16 Apr 2024 19:57:08 -0500 Subject: [PATCH 5/6] fix: chat report last visible action should not change when an old iou is updated --- src/libs/actions/IOU.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 869ff3f614f7..d4d99cbbfff4 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -511,7 +511,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 @@ -519,8 +518,8 @@ function buildOnyxDataForMoneyRequest( key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, value: { ...chatReport, - // if iouReport exist, the last visible action created time does not change. - lastVisibleActionCreated: isNewChatReport ? undefined : iouReport.lastVisibleActionCreated, + // 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, @@ -1390,6 +1389,7 @@ function getMoneyRequestInformation( } else { iouReport = IOUUtils.updateIOUOwnerAndTotal(iouReport, payeeAccountID, amount, currency); } + // STEP 3: Build optimistic receipt and transaction const receiptObject: Receipt = {}; let filename; From f05942daf42e8687bf60c45b0a55160deee55572 Mon Sep 17 00:00:00 2001 From: Jaime Liz Date: Tue, 16 Apr 2024 19:57:38 -0500 Subject: [PATCH 6/6] fix: sometimes the last visible action is part of an old thread --- src/pages/home/report/ReportActionsList.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionsList.tsx b/src/pages/home/report/ReportActionsList.tsx index 19204958dd5f..6b1ebee23cf8 100644 --- a/src/pages/home/report/ReportActionsList.tsx +++ b/src/pages/home/report/ReportActionsList.tsx @@ -196,7 +196,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.some((reportAction) => reportAction.created === report.lastVisibleActionCreated); const hasNewestReportActionRef = useRef(hasNewestReportAction); hasNewestReportActionRef.current = hasNewestReportAction; const previousLastIndex = useRef(lastActionIndex);