From ac0617f097969dce4a3835b429548a8113ae3a24 Mon Sep 17 00:00:00 2001 From: rory Date: Tue, 15 Nov 2022 17:44:06 -0800 Subject: [PATCH 1/9] Create Onyx migration to add lastActionCreated --- src/libs/migrations/AddLastActionCreated.js | 37 +++++ tests/unit/MigrationTest.js | 151 +++++++++++++------- 2 files changed, 137 insertions(+), 51 deletions(-) create mode 100644 src/libs/migrations/AddLastActionCreated.js diff --git a/src/libs/migrations/AddLastActionCreated.js b/src/libs/migrations/AddLastActionCreated.js new file mode 100644 index 000000000000..f2c25880393e --- /dev/null +++ b/src/libs/migrations/AddLastActionCreated.js @@ -0,0 +1,37 @@ +import _ from 'underscore'; +import Onyx from 'react-native-onyx'; +import Log from '../Log'; +import ONYXKEYS from '../../ONYXKEYS'; + +/** + * This migration adds lastActionCreated to all reports in Onyx, using the value of lastMessageTimestamp + * + * @returns {Promise} + */ +export default function() { + return new Promise((resolve) => { + const connectionID = Onyx.connect({ + key: ONYXKEYS.COLLECTION.REPORT, + waitForCollectionCallbacks: true, + callback: (allReports) => { + Onyx.disconnect(connectionID); + Onyx.mergeCollection(ONYXKEYS.COLLECTION.REPORT, _.map(allReports, (report) => { + if (_.has(report, 'lastActionCreated')) { + return report; + } + + if (!_.has(report, 'lastMessageTimestamp')) { + return report; + } + + report.lastActionCreated = new Date(report.lastMessageTimestamp) + .toISOString() + .replace('T', ' ') + .replace('Z', ''); + return report; + })); + }, + }); + return resolve(); + }) +} diff --git a/tests/unit/MigrationTest.js b/tests/unit/MigrationTest.js index 0cd808350575..795542cd38d8 100644 --- a/tests/unit/MigrationTest.js +++ b/tests/unit/MigrationTest.js @@ -2,6 +2,7 @@ import Onyx from 'react-native-onyx'; import _ from 'underscore'; import CONST from '../../src/CONST'; import getPlatform from '../../src/libs/getPlatform'; +import AddLastActionCreated from '../../src/libs/migrations/AddLastActionCreated'; import MoveToIndexedDB from '../../src/libs/migrations/MoveToIndexedDB'; import ONYXKEYS from '../../src/ONYXKEYS'; @@ -11,66 +12,114 @@ jest.mock('../../src/libs/getPlatform'); // This seems related: https://github.com/facebook/jest/issues/11876 jest.useRealTimers(); -describe('MoveToIndexedDb', () => { - beforeEach(() => { - jest.resetAllMocks(); - getPlatform.mockImplementation(() => CONST.PLATFORM.WEB); - jest.spyOn(Onyx, 'multiSet').mockImplementation(() => Promise.resolve()); - localStorage.clear(); - }); +describe('Migrations', () => { + describe('MoveToIndexedDb', () => { + beforeEach(() => { + jest.resetAllMocks(); + getPlatform.mockImplementation(() => CONST.PLATFORM.WEB); + jest.spyOn(Onyx, 'multiSet').mockImplementation(() => Promise.resolve()); + localStorage.clear(); + }); - it('Should do nothing for non web/desktop platforms', () => { - // Given the migration is not running on web or desktop - getPlatform.mockImplementation(() => CONST.PLATFORM.ANDROID); + it('Should do nothing for non web/desktop platforms', () => { + // Given the migration is not running on web or desktop + getPlatform.mockImplementation(() => CONST.PLATFORM.ANDROID); - // When the migration runs - return MoveToIndexedDB() - .then(() => { - // Then we don't expect any storage calls - expect(Onyx.multiSet).not.toHaveBeenCalled(); - }); - }); + // When the migration runs + return MoveToIndexedDB() + .then(() => { + // Then we don't expect any storage calls + expect(Onyx.multiSet).not.toHaveBeenCalled(); + }); + }); - it('Should do nothing when there is no old session data', () => { - // Given no session in old storage medium (localStorage) - localStorage.removeItem(ONYXKEYS.SESSION); + it('Should do nothing when there is no old session data', () => { + // Given no session in old storage medium (localStorage) + localStorage.removeItem(ONYXKEYS.SESSION); - // When the migration runs - return MoveToIndexedDB() - .then(() => { - // Then we don't expect any storage calls - expect(Onyx.multiSet).not.toHaveBeenCalled(); - }); - }); + // When the migration runs + return MoveToIndexedDB() + .then(() => { + // Then we don't expect any storage calls + expect(Onyx.multiSet).not.toHaveBeenCalled(); + }); + }); - it('Should migrate Onyx keys in localStorage to (new) Onyx', () => { - // Given some old data exists in storage - const data = { - [ONYXKEYS.SESSION]: {authToken: 'mock-token', loading: false}, - [ONYXKEYS.ACCOUNT]: {email: 'test@mock.com'}, - [ONYXKEYS.NETWORK]: {isOffline: true}, - }; + it('Should migrate Onyx keys in localStorage to (new) Onyx', () => { + // Given some old data exists in storage + const data = { + [ONYXKEYS.SESSION]: {authToken: 'mock-token', loading: false}, + [ONYXKEYS.ACCOUNT]: {email: 'test@mock.com'}, + [ONYXKEYS.NETWORK]: {isOffline: true}, + }; - _.forEach(data, (value, key) => localStorage.setItem(key, JSON.stringify(value))); + _.forEach(data, (value, key) => localStorage.setItem(key, JSON.stringify(value))); - // When the migration runs - return MoveToIndexedDB() - .then(() => { - // Then multiset should be called with all the data available in localStorage - expect(Onyx.multiSet).toHaveBeenCalledWith(data); - }); + // When the migration runs + return MoveToIndexedDB() + .then(() => { + // Then multiset should be called with all the data available in localStorage + expect(Onyx.multiSet).toHaveBeenCalledWith(data); + }); + }); + + it('Should not clear non Onyx keys from localStorage', () => { + // Given some Onyx and non-Onyx data exists in localStorage + localStorage.setItem(ONYXKEYS.SESSION, JSON.stringify({authToken: 'mock-token'})); + localStorage.setItem('non-onyx-item', 'MOCK'); + + // When the migration runs + return MoveToIndexedDB() + .then(() => { + // Then non-Onyx data should remain in localStorage + expect(localStorage.getItem('non-onyx-item')).toEqual('MOCK'); + }); + }); }); - it('Should not clear non Onyx keys from localStorage', () => { - // Given some Onyx and non-Onyx data exists in localStorage - localStorage.setItem(ONYXKEYS.SESSION, JSON.stringify({authToken: 'mock-token'})); - localStorage.setItem('non-onyx-item', 'MOCK'); + describe('AddLastActionCreated', () => { + it('Should add lastActionCreated wherever lastMessageTimestamp currently is', () => { + Onyx.init({ + keys: {COLLECTION: {REPORT: ONYXKEYS.COLLECTION.REPORT}}, + initialKeyStates: { + report_1: { + lastMessageTimestamp: 1668562273702, + }, + report_2: { + lastMessageTimestamp: 1668562314821, + }, + }, + }); + AddLastActionCreated(); + const connectionID = Onyx.connect({ + key: ONYXKEYS.COLLECTION.REPORT, + waitForCollectionCallbacks: true, + callback: (allReports) => { + Onyx.disconnect(connectionID); + expect(_.keys(allReports).length).toBe(2); + _.each(allReports, (report) => { + expect(_.has(report, 'lastActionCreated')).toBe(true); + }); + expect(allReports.report_1.lastActionCreated).toBe('2022-11-16 01:31:13.702'); + expect(allReports.report_2.lastActionCreated).toBe('2022-11-16 01:31:54.821'); + }, + }); + }); - // When the migration runs - return MoveToIndexedDB() - .then(() => { - // Then non-Onyx data should remain in localStorage - expect(localStorage.getItem('non-onyx-item')).toEqual('MOCK'); + it('Should work even if there is no report data', () => { + Onyx.init({ + keys: {COLLECTION: {REPORT: ONYXKEYS.COLLECTION.REPORT}}, + initialKeyStates: {}, + }); + AddLastActionCreated(); + const connectionID = Onyx.connect({ + key: ONYXKEYS.COLLECTION.REPORT, + waitForCollectionCallbacks: true, + callback: (allReports) => { + Onyx.disconnect(connectionID); + expect(allReports).toBeEmpty(); + }, }); + }); }); -}); +}) From 3128a58a0d5412de7c1bd14e9bf35e0b08c889c2 Mon Sep 17 00:00:00 2001 From: rory Date: Mon, 21 Nov 2022 15:38:42 -0800 Subject: [PATCH 2/9] Fix JS style --- src/libs/migrations/AddLastActionCreated.js | 25 ++++++++++++++------- tests/unit/MigrationTest.js | 2 +- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/libs/migrations/AddLastActionCreated.js b/src/libs/migrations/AddLastActionCreated.js index f2c25880393e..38c6a715614b 100644 --- a/src/libs/migrations/AddLastActionCreated.js +++ b/src/libs/migrations/AddLastActionCreated.js @@ -8,30 +8,39 @@ import ONYXKEYS from '../../ONYXKEYS'; * * @returns {Promise} */ -export default function() { +export default function () { return new Promise((resolve) => { const connectionID = Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT, waitForCollectionCallbacks: true, callback: (allReports) => { Onyx.disconnect(connectionID); - Onyx.mergeCollection(ONYXKEYS.COLLECTION.REPORT, _.map(allReports, (report) => { + const reportsToUpdate = {}; + _.each(allReports, (report, key) => { if (_.has(report, 'lastActionCreated')) { - return report; + return; } if (!_.has(report, 'lastMessageTimestamp')) { - return report; + return; } - report.lastActionCreated = new Date(report.lastMessageTimestamp) + reportsToUpdate[key] = report; + reportsToUpdate[key].lastActionCreated = new Date(report.lastMessageTimestamp) .toISOString() .replace('T', ' ') .replace('Z', ''); - return report; - })); + }); + + if (_.isEmpty(reportsToUpdate)) { + Log.info('[Migrate Onyx] Skipped migration AddLastActionCreated'); + } else { + Log.info(`[Migrate Onyx] Adding lastActionCreated field to ${_.keys(reportsToUpdate).length} reports`); + // eslint-disable-next-line rulesdir/prefer-actions-set-data + Onyx.mergeCollection(ONYXKEYS.COLLECTION.REPORT, reportsToUpdate); + } }, }); return resolve(); - }) + }); } diff --git a/tests/unit/MigrationTest.js b/tests/unit/MigrationTest.js index 795542cd38d8..a731d033259d 100644 --- a/tests/unit/MigrationTest.js +++ b/tests/unit/MigrationTest.js @@ -122,4 +122,4 @@ describe('Migrations', () => { }); }); }); -}) +}); From 3e6b310d719059eff8d6dfc47eceb981a8d83997 Mon Sep 17 00:00:00 2001 From: rory Date: Mon, 21 Nov 2022 17:28:38 -0800 Subject: [PATCH 3/9] Fix migration tests --- tests/unit/MigrationTest.js | 83 ++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/tests/unit/MigrationTest.js b/tests/unit/MigrationTest.js index a731d033259d..095ebd4c1f2a 100644 --- a/tests/unit/MigrationTest.js +++ b/tests/unit/MigrationTest.js @@ -1,5 +1,6 @@ import Onyx from 'react-native-onyx'; import _ from 'underscore'; +import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; import CONST from '../../src/CONST'; import getPlatform from '../../src/libs/getPlatform'; import AddLastActionCreated from '../../src/libs/migrations/AddLastActionCreated'; @@ -13,14 +14,23 @@ jest.mock('../../src/libs/getPlatform'); jest.useRealTimers(); describe('Migrations', () => { + beforeAll(() => { + Onyx.init({keys: ONYXKEYS}); + return waitForPromisesToResolve(); + }); + + beforeEach(() => { + Onyx.clear(); + return waitForPromisesToResolve(); + }); + describe('MoveToIndexedDb', () => { beforeEach(() => { - jest.resetAllMocks(); + jest.clearAllMocks(); getPlatform.mockImplementation(() => CONST.PLATFORM.WEB); jest.spyOn(Onyx, 'multiSet').mockImplementation(() => Promise.resolve()); localStorage.clear(); }); - it('Should do nothing for non web/desktop platforms', () => { // Given the migration is not running on web or desktop getPlatform.mockImplementation(() => CONST.PLATFORM.ANDROID); @@ -79,47 +89,44 @@ describe('Migrations', () => { describe('AddLastActionCreated', () => { it('Should add lastActionCreated wherever lastMessageTimestamp currently is', () => { - Onyx.init({ - keys: {COLLECTION: {REPORT: ONYXKEYS.COLLECTION.REPORT}}, - initialKeyStates: { - report_1: { - lastMessageTimestamp: 1668562273702, - }, - report_2: { - lastMessageTimestamp: 1668562314821, - }, + Onyx.set(ONYXKEYS.COLLECTION.REPORT, { + report_1: { + lastMessageTimestamp: 1668562273702, }, - }); - AddLastActionCreated(); - const connectionID = Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - waitForCollectionCallbacks: true, - callback: (allReports) => { - Onyx.disconnect(connectionID); - expect(_.keys(allReports).length).toBe(2); - _.each(allReports, (report) => { - expect(_.has(report, 'lastActionCreated')).toBe(true); - }); - expect(allReports.report_1.lastActionCreated).toBe('2022-11-16 01:31:13.702'); - expect(allReports.report_2.lastActionCreated).toBe('2022-11-16 01:31:54.821'); + report_2: { + lastMessageTimestamp: 1668562314821, }, - }); + }) + .then(AddLastActionCreated) + .then(() => { + const connectionID = Onyx.connect({ + key: ONYXKEYS.COLLECTION.REPORT, + waitForCollectionCallbacks: true, + callback: (allReports) => { + Onyx.disconnect(connectionID); + expect(_.keys(allReports).length).toBe(2); + _.each(allReports, (report) => { + expect(_.has(report, 'lastActionCreated')).toBe(true); + }); + expect(allReports.report_1.lastActionCreated).toBe('2022-11-16 01:31:13.702'); + expect(allReports.report_2.lastActionCreated).toBe('2022-11-16 01:31:54.821'); + }, + }); + }); }); it('Should work even if there is no report data', () => { - Onyx.init({ - keys: {COLLECTION: {REPORT: ONYXKEYS.COLLECTION.REPORT}}, - initialKeyStates: {}, - }); - AddLastActionCreated(); - const connectionID = Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - waitForCollectionCallbacks: true, - callback: (allReports) => { - Onyx.disconnect(connectionID); - expect(allReports).toBeEmpty(); - }, - }); + AddLastActionCreated() + .then(() => { + const connectionID = Onyx.connect({ + key: ONYXKEYS.COLLECTION.REPORT, + waitForCollectionCallbacks: true, + callback: (allReports) => { + Onyx.disconnect(connectionID); + expect(allReports).toBeEmpty(); + }, + }); + }); }); }); }); From 045b759282dccd09a522450202aa4e47ad98b3a5 Mon Sep 17 00:00:00 2001 From: rory Date: Mon, 21 Nov 2022 17:41:09 -0800 Subject: [PATCH 4/9] Add more test cases --- tests/unit/MigrationTest.js | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/tests/unit/MigrationTest.js b/tests/unit/MigrationTest.js index 095ebd4c1f2a..b2d4a81fcd80 100644 --- a/tests/unit/MigrationTest.js +++ b/tests/unit/MigrationTest.js @@ -2,6 +2,7 @@ import Onyx from 'react-native-onyx'; import _ from 'underscore'; import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; import CONST from '../../src/CONST'; +import Log from '../../src/libs/Log'; import getPlatform from '../../src/libs/getPlatform'; import AddLastActionCreated from '../../src/libs/migrations/AddLastActionCreated'; import MoveToIndexedDB from '../../src/libs/migrations/MoveToIndexedDB'; @@ -13,20 +14,23 @@ jest.mock('../../src/libs/getPlatform'); // This seems related: https://github.com/facebook/jest/issues/11876 jest.useRealTimers(); +let LogSpy; + describe('Migrations', () => { beforeAll(() => { Onyx.init({keys: ONYXKEYS}); + LogSpy = jest.spyOn(Log, 'info'); return waitForPromisesToResolve(); }); beforeEach(() => { + jest.clearAllMocks(); Onyx.clear(); return waitForPromisesToResolve(); }); describe('MoveToIndexedDb', () => { beforeEach(() => { - jest.clearAllMocks(); getPlatform.mockImplementation(() => CONST.PLATFORM.WEB); jest.spyOn(Onyx, 'multiSet').mockImplementation(() => Promise.resolve()); localStorage.clear(); @@ -99,6 +103,7 @@ describe('Migrations', () => { }) .then(AddLastActionCreated) .then(() => { + expect(LogSpy).toHaveBeenCalledWith('[Migrate Onyx] Adding lastActionCreated field to 2 reports'); const connectionID = Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT, waitForCollectionCallbacks: true, @@ -115,9 +120,25 @@ describe('Migrations', () => { }); }); + it('Should skip if the report data already has the correct fields', () => { + Onyx.set(ONYXKEYS.COLLECTION.REPORT, { + report_1: { + lastActionCreated: '2022-11-16 01:31:13.702', + }, + report_2: { + lastActionCreated: '2022-11-16 01:31:54.821', + }, + }) + .then(AddLastActionCreated) + .then(() => { + expect(LogSpy).toHaveBeenCalledWith('[Migrate Onyx] Skipped migration AddLastActionCreated'); + }); + }); + it('Should work even if there is no report data', () => { AddLastActionCreated() .then(() => { + expect(LogSpy).toHaveBeenCalledWith('[Migrate Onyx] Skipped migration AddLastActionCreated'); const connectionID = Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT, waitForCollectionCallbacks: true, From 66def584388330d67c1798c6326585ff89121273 Mon Sep 17 00:00:00 2001 From: rory Date: Mon, 21 Nov 2022 19:18:35 -0800 Subject: [PATCH 5/9] Update currentDBTime to take a timestamp prop --- src/libs/DateUtils.js | 8 ++++++-- tests/unit/DateUtilsTest.js | 26 +++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/libs/DateUtils.js b/src/libs/DateUtils.js index b3fbbbd03d8a..32146e1d1d8b 100644 --- a/src/libs/DateUtils.js +++ b/src/libs/DateUtils.js @@ -163,10 +163,14 @@ function getMicroseconds() { /** * Returns the current time in milliseconds in the format expected by the database + * + * @param {String|Number} [timestamp] + * * @returns {String} */ -function currentDBTime() { - return new Date().toISOString() +function currentDBTime(timestamp = '') { + const datetime = timestamp ? new Date(timestamp) : new Date(); + return datetime.toISOString() .replace('T', ' ') .replace('Z', ''); } diff --git a/tests/unit/DateUtilsTest.js b/tests/unit/DateUtilsTest.js index bd0b55b1fdc7..569846b7879d 100644 --- a/tests/unit/DateUtilsTest.js +++ b/tests/unit/DateUtilsTest.js @@ -47,8 +47,28 @@ describe('DateUtils', () => { expect(DateUtils.datetimeToRelative(LOCALE, anHourAgo)).toBe('an hour ago'); }); - it('should return the date in the format expected by the database when calling currentDBTime', () => { - const currentDBTime = DateUtils.currentDBTime(); - expect(currentDBTime).toBe(moment(currentDBTime).format('YYYY-MM-DD HH:mm:ss.SSS')); + describe('currentDBTime', () => { + it('should return the date in the format expected by the database', () => { + const currentDBTime = DateUtils.currentDBTime(); + expect(currentDBTime).toBe(moment(currentDBTime).format('YYYY-MM-DD HH:mm:ss.SSS')); + }); + + it('should represent the correct moment in utc when used with a standard datetime string', () => { + const timestamp = 'Mon Nov 21 2022 19:04:14 GMT-0800 (Pacific Standard Time)'; + const currentDBTime = DateUtils.currentDBTime(timestamp); + expect(currentDBTime).toBe('2022-11-22 03:04:14.000'); + }); + + it('should represent the correct moment in time when used with an ISO string', () => { + const timestamp = '2022-11-22T03:08:04.326Z'; + const currentDBTime = DateUtils.currentDBTime(timestamp); + expect(currentDBTime).toBe('2022-11-22 03:08:04.326'); + }); + + it('should represent the correct moment in time when used with a unix timestamp', () => { + const timestamp = 1669086850792; + const currentDBTime = DateUtils.currentDBTime(timestamp); + expect(currentDBTime).toBe('2022-11-22 03:14:10.792'); + }); }); }); From da8aa2786296ce928d45ae61768d77809d3a9771 Mon Sep 17 00:00:00 2001 From: rory Date: Mon, 21 Nov 2022 19:22:14 -0800 Subject: [PATCH 6/9] Rename currentDBTime to getDBTime --- src/libs/DateUtils.js | 4 ++-- src/libs/ReportUtils.js | 6 +++--- tests/actions/ReportTest.js | 4 ++-- tests/unit/DateUtilsTest.js | 18 +++++++++--------- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/libs/DateUtils.js b/src/libs/DateUtils.js index 32146e1d1d8b..56e406ba0ca5 100644 --- a/src/libs/DateUtils.js +++ b/src/libs/DateUtils.js @@ -168,7 +168,7 @@ function getMicroseconds() { * * @returns {String} */ -function currentDBTime(timestamp = '') { +function getDBTime(timestamp = '') { const datetime = timestamp ? new Date(timestamp) : new Date(); return datetime.toISOString() .replace('T', ' ') @@ -187,7 +187,7 @@ const DateUtils = { canUpdateTimezone, setTimezoneUpdated, getMicroseconds, - currentDBTime, + getDBTime, }; export default DateUtils; diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index b0035909d1d4..cb306f620038 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -643,7 +643,7 @@ function buildOptimisticReportAction(sequenceNumber, text, file) { sequenceNumber, clientID: NumberUtils.generateReportActionClientID(), avatar: lodashGet(allPersonalDetails, [currentUserEmail, 'avatar'], getDefaultAvatar(currentUserEmail)), - created: DateUtils.currentDBTime(), + created: DateUtils.getDBTime(), message: [ { type: CONST.REPORT.MESSAGE.TYPE.COMMENT, @@ -795,7 +795,7 @@ function buildOptimisticIOUReportAction(sequenceNumber, type, amount, currency, reportActionID: NumberUtils.rand64(), sequenceNumber, shouldShow: true, - created: DateUtils.currentDBTime(), + created: DateUtils.getDBTime(), pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }; } @@ -883,7 +883,7 @@ function buildOptimisticCreatedReportAction(ownerEmail) { automatic: false, sequenceNumber: 0, avatar: lodashGet(allPersonalDetails, [currentUserEmail, 'avatar'], getDefaultAvatar(currentUserEmail)), - created: DateUtils.currentDBTime(), + created: DateUtils.getDBTime(), shouldShow: true, }, }; diff --git a/tests/actions/ReportTest.js b/tests/actions/ReportTest.js index ee7d5f6320db..47be25e102b9 100644 --- a/tests/actions/ReportTest.js +++ b/tests/actions/ReportTest.js @@ -260,7 +260,7 @@ describe('actions/Report', () => { person: [{type: 'TEXT', style: 'strong', text: 'Test User'}], sequenceNumber: 1, shouldShow: true, - created: DateUtils.currentDBTime(), + created: DateUtils.getDBTime(), }, }, }, @@ -325,7 +325,7 @@ describe('actions/Report', () => { avatar: 'https://d2k5nsl2zxldvw.cloudfront.net/images/avatars/avatar_3.png', person: [{type: 'TEXT', style: 'strong', text: 'Test User'}], shouldShow: true, - created: DateUtils.currentDBTime(), + created: DateUtils.getDBTime(), reportActionID: 'derp', }; diff --git a/tests/unit/DateUtilsTest.js b/tests/unit/DateUtilsTest.js index 569846b7879d..bae1b3df06f2 100644 --- a/tests/unit/DateUtilsTest.js +++ b/tests/unit/DateUtilsTest.js @@ -47,28 +47,28 @@ describe('DateUtils', () => { expect(DateUtils.datetimeToRelative(LOCALE, anHourAgo)).toBe('an hour ago'); }); - describe('currentDBTime', () => { + describe('getDBTime', () => { it('should return the date in the format expected by the database', () => { - const currentDBTime = DateUtils.currentDBTime(); - expect(currentDBTime).toBe(moment(currentDBTime).format('YYYY-MM-DD HH:mm:ss.SSS')); + const getDBTime = DateUtils.getDBTime(); + expect(getDBTime).toBe(moment(getDBTime).format('YYYY-MM-DD HH:mm:ss.SSS')); }); it('should represent the correct moment in utc when used with a standard datetime string', () => { const timestamp = 'Mon Nov 21 2022 19:04:14 GMT-0800 (Pacific Standard Time)'; - const currentDBTime = DateUtils.currentDBTime(timestamp); - expect(currentDBTime).toBe('2022-11-22 03:04:14.000'); + const getDBTime = DateUtils.getDBTime(timestamp); + expect(getDBTime).toBe('2022-11-22 03:04:14.000'); }); it('should represent the correct moment in time when used with an ISO string', () => { const timestamp = '2022-11-22T03:08:04.326Z'; - const currentDBTime = DateUtils.currentDBTime(timestamp); - expect(currentDBTime).toBe('2022-11-22 03:08:04.326'); + const getDBTime = DateUtils.getDBTime(timestamp); + expect(getDBTime).toBe('2022-11-22 03:08:04.326'); }); it('should represent the correct moment in time when used with a unix timestamp', () => { const timestamp = 1669086850792; - const currentDBTime = DateUtils.currentDBTime(timestamp); - expect(currentDBTime).toBe('2022-11-22 03:14:10.792'); + const getDBTime = DateUtils.getDBTime(timestamp); + expect(getDBTime).toBe('2022-11-22 03:14:10.792'); }); }); }); From 06a95bcd99e23dffd9f6f572d49b3da7f4ab7dad Mon Sep 17 00:00:00 2001 From: rory Date: Mon, 21 Nov 2022 19:56:26 -0800 Subject: [PATCH 7/9] Migrate from lastMessageTimestamp to lastActionCreated --- src/libs/OptionsListUtils.js | 2 +- src/libs/ReportUtils.js | 1 + src/libs/SidebarUtils.js | 8 ++++---- src/libs/actions/Report.js | 6 ++++-- src/pages/home/sidebar/SidebarLinks.js | 1 + src/pages/reportPropTypes.js | 3 +++ tests/actions/ReportTest.js | 3 +++ tests/ui/UnreadIndicatorsTest.js | 4 ++++ tests/unit/OptionsListUtilsTest.js | 17 +++++++++++++++-- tests/unit/SidebarFilterTest.js | 13 +++++++++++-- tests/unit/SidebarOrderTest.js | 6 +++++- tests/utils/LHNTestUtils.js | 2 ++ 12 files changed, 54 insertions(+), 12 deletions(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index faac86e5f6f2..0ea6448bb802 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -470,7 +470,7 @@ function getOptions(reports, personalDetails, { return -Infinity; } - return report.lastMessageTimestamp; + return report.lastActionCreated; }); orderedReports.reverse(); diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index cb306f620038..e4826f6c2791 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -834,6 +834,7 @@ function buildOptimisticChatReport( lastMessageHtml: '', lastMessageText: null, lastReadSequenceNumber: 0, + lastActionCreated: '', lastMessageTimestamp: 0, lastVisitedTimestamp: 0, maxSequenceNumber: 0, diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 0a0f35531902..b0932f85b1e7 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -114,10 +114,10 @@ function getOrderedReportIDs(reportIDFromRoute) { // 2. Outstanding IOUs - Always sorted by iouReportAmount with the largest amounts at the top of the group // 3. Drafts - Always sorted by reportDisplayName // 4. Non-archived reports - // - Sorted by lastMessageTimestamp in default (most recent) view mode + // - Sorted by lastActionCreated in default (most recent) view mode // - Sorted by reportDisplayName in GSD (focus) view mode // 5. Archived reports - // - Sorted by lastMessageTimestamp in default (most recent) view mode + // - Sorted by lastActionCreated in default (most recent) view mode // - Sorted by reportDisplayName in GSD (focus) view mode let pinnedReports = []; let outstandingIOUReports = []; @@ -153,8 +153,8 @@ function getOrderedReportIDs(reportIDFromRoute) { pinnedReports = _.sortBy(pinnedReports, report => report.displayName.toLowerCase()); outstandingIOUReports = _.sortBy(outstandingIOUReports, 'iouReportAmount').reverse(); draftReports = _.sortBy(draftReports, report => report.displayName.toLowerCase()); - nonArchivedReports = _.sortBy(nonArchivedReports, report => (isInDefaultMode ? report.lastMessageTimestamp : report.displayName.toLowerCase())); - archivedReports = _.sortBy(archivedReports, report => (isInDefaultMode ? report.lastMessageTimestamp : report.displayName.toLowerCase())); + nonArchivedReports = _.sortBy(nonArchivedReports, report => (isInDefaultMode ? report.lastActionCreated : report.displayName.toLowerCase())); + archivedReports = _.sortBy(archivedReports, report => (isInDefaultMode ? report.lastActionCreated : report.displayName.toLowerCase())); // For archived and non-archived reports, ensure that most recent reports are at the top by reversing the order of the arrays because underscore will only sort them in ascending order if (isInDefaultMode) { diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 164d0e60bbbb..ed4a7af39a82 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -90,8 +90,8 @@ function getParticipantEmailsFromReport({sharedReportList, reportNameValuePairs, * @returns {Object} */ function getSimplifiedReportObject(report) { - const createTimestamp = lodashGet(report, 'lastActionCreated', 0); - const lastMessageTimestamp = moment.utc(createTimestamp).unix(); + const lastActionCreated = lodashGet(report, 'lastActionCreated', 0); + const lastMessageTimestamp = moment.utc(lastActionCreated).unix(); const lastActionMessage = lodashGet(report, ['lastActionMessage', 'html'], ''); const isLastMessageAttachment = new RegExp(`]*${CONST.ATTACHMENT_SOURCE_ATTRIBUTE}\\s*=\\s*"[^"]*"[^>]*>`, 'gi').test(lastActionMessage); const chatType = lodashGet(report, ['reportNameValuePairs', 'chatType'], ''); @@ -135,6 +135,7 @@ function getSimplifiedReportObject(report) { 'timestamp', ], 0), lastReadSequenceNumber, + lastActionCreated, lastMessageTimestamp, lastMessageText: isLastMessageAttachment ? '[Attachment]' : lastMessageText, lastActorEmail, @@ -414,6 +415,7 @@ function addActions(reportID, text = '', file) { // Update the report in Onyx to have the new sequence number const optimisticReport = { maxSequenceNumber: newSequenceNumber, + lastActionCreated: DateUtils.getDBTime(), lastMessageTimestamp: Date.now(), lastMessageText: ReportUtils.formatReportLastMessageText(lastAction.message[0].text), lastActorEmail: currentUserEmail, diff --git a/src/pages/home/sidebar/SidebarLinks.js b/src/pages/home/sidebar/SidebarLinks.js index f2a8ed496220..32e320682eee 100644 --- a/src/pages/home/sidebar/SidebarLinks.js +++ b/src/pages/home/sidebar/SidebarLinks.js @@ -214,6 +214,7 @@ const reportSelector = report => report && ({ lastReadSequenceNumber: report.lastReadSequenceNumber, lastMessageText: report.lastMessageText, lastMessageTimestamp: report.lastMessageTimestamp, + lastActionCreated: report.lastActionCreated, iouReportID: report.iouReportID, hasOutstandingIOU: report.hasOutstandingIOU, statusNum: report.statusNum, diff --git a/src/pages/reportPropTypes.js b/src/pages/reportPropTypes.js index 5c26bb2905a1..0ce6dfcbe729 100644 --- a/src/pages/reportPropTypes.js +++ b/src/pages/reportPropTypes.js @@ -32,6 +32,9 @@ export default PropTypes.shape({ lastMessageText: PropTypes.string, /** The time of the last message on the report */ + lastActionCreated: PropTypes.string, + + /** The time of the last message on the report (in unix timestamp form) */ lastMessageTimestamp: PropTypes.number, /** The sequence number of the last action read by the user */ diff --git a/tests/actions/ReportTest.js b/tests/actions/ReportTest.js index 47be25e102b9..e4ca092fc645 100644 --- a/tests/actions/ReportTest.js +++ b/tests/actions/ReportTest.js @@ -112,6 +112,7 @@ describe('actions/Report', () => { maxSequenceNumber: 1, notificationPreference: 'always', lastMessageTimestamp: 0, + lastActionCreated: '2022-11-22 03:48:27.267', lastMessageText: 'Testing a comment', lastActorEmail: TEST_USER_LOGIN, }, @@ -241,6 +242,7 @@ describe('actions/Report', () => { maxSequenceNumber: 1, notificationPreference: 'always', lastMessageTimestamp: 0, + lastActionCreated: '2022-11-22 03:48:27.267', lastMessageText: 'Comment 1', lastActorEmail: USER_2_LOGIN, lastReadSequenceNumber: 0, @@ -339,6 +341,7 @@ describe('actions/Report', () => { maxSequenceNumber: 4, notificationPreference: 'always', lastMessageTimestamp: 0, + lastActionCreated: '2022-11-22 03:48:27.267', lastMessageText: 'Current User Comment 3', lastActorEmail: 'test@test.com', lastReadSequenceNumber: 4, diff --git a/tests/ui/UnreadIndicatorsTest.js b/tests/ui/UnreadIndicatorsTest.js index 7796e66f27dd..7ccf1eb6cbea 100644 --- a/tests/ui/UnreadIndicatorsTest.js +++ b/tests/ui/UnreadIndicatorsTest.js @@ -17,6 +17,7 @@ import * as NumberUtils from '../../src/libs/NumberUtils'; import LocalNotification from '../../src/libs/Notification/LocalNotification'; import * as Report from '../../src/libs/actions/Report'; import * as CollectionUtils from '../../src/libs/CollectionUtils'; +import DateUtils from '../../src/libs/DateUtils'; jest.mock('../../src/libs/Notification/LocalNotification'); @@ -134,6 +135,7 @@ function signInAndGetAppWithUnreadChat() { maxSequenceNumber: 9, lastReadSequenceNumber: 1, lastMessageTimestamp: MOMENT_TEN_MINUTES_AGO.utc().valueOf(), + lastActionCreated: DateUtils.getDBTime(MOMENT_TEN_MINUTES_AGO.utc().valueOf()), lastMessageText: 'Test', participants: [USER_B_EMAIL], }); @@ -269,6 +271,7 @@ describe('Unread Indicators', () => { maxSequenceNumber: 1, lastReadSequenceNumber: 0, lastMessageTimestamp: NEW_REPORT_CREATED_MOMENT.utc().valueOf(), + lastActionCreated: DateUtils.getDBTime(NEW_REPORT_CREATED_MOMENT.utc().valueOf()), lastMessageText: 'Comment 1', participants: [USER_C_EMAIL], }); @@ -498,6 +501,7 @@ describe('Unread Indicators', () => { Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, { lastMessageText: lastReportAction.message[0].text, lastMessageTimestamp: lastReportAction.timestamp, + lastActionCreated: DateUtils.getDBTime(lastReportAction.timestamp), lastActorEmail: lastReportAction.actorEmail, maxSequenceNumber: lastReportAction.sequenceNumber, reportID: REPORT_ID, diff --git a/tests/unit/OptionsListUtilsTest.js b/tests/unit/OptionsListUtilsTest.js index c9680467b81f..8bf168fa7bc3 100644 --- a/tests/unit/OptionsListUtilsTest.js +++ b/tests/unit/OptionsListUtilsTest.js @@ -12,6 +12,7 @@ describe('OptionsListUtils', () => { const REPORTS = { 1: { lastVisitedTimestamp: 1610666739295, + lastActionCreated: '2022-11-22 03:26:02.015', lastMessageTimestamp: 15, isPinned: false, reportID: 1, @@ -23,6 +24,7 @@ describe('OptionsListUtils', () => { }, 2: { lastVisitedTimestamp: 1610666739296, + lastActionCreated: '2022-11-22 03:26:02.016', lastMessageTimestamp: 16, isPinned: false, reportID: 2, @@ -35,6 +37,7 @@ describe('OptionsListUtils', () => { // This is the only report we are pinning in this test 3: { lastVisitedTimestamp: 1610666739297, + lastActionCreated: '2022-11-22 03:26:02.170', lastMessageTimestamp: 170, isPinned: true, reportID: 3, @@ -45,6 +48,7 @@ describe('OptionsListUtils', () => { }, 4: { lastVisitedTimestamp: 1610666739298, + lastActionCreated: '2022-11-22 03:26:02.180', lastMessageTimestamp: 180, isPinned: false, reportID: 4, @@ -55,6 +59,7 @@ describe('OptionsListUtils', () => { }, 5: { lastVisitedTimestamp: 1610666739299, + lastActionCreated: '2022-11-22 03:26:02.019', lastMessageTimestamp: 19, isPinned: false, reportID: 5, @@ -65,6 +70,7 @@ describe('OptionsListUtils', () => { }, 6: { lastVisitedTimestamp: 1610666739300, + lastActionCreated: '2022-11-22 03:26:02.020', lastMessageTimestamp: 20, isPinned: false, reportID: 6, @@ -77,7 +83,8 @@ describe('OptionsListUtils', () => { // Note: This report has the largest lastMessageTimestamp 7: { lastVisitedTimestamp: 1610666739301, - lastMessageTimestamp: 1611282169, + lastActionCreated: '2022-11-22 03:26:03.999', + lastMessageTimestamp: 999, isPinned: false, reportID: 7, participants: ['steverogers@expensify.com'], @@ -89,6 +96,7 @@ describe('OptionsListUtils', () => { // Note: This report has no lastMessageTimestamp 8: { lastVisitedTimestamp: 1610666739301, + lastActionCreated: '2022-11-22 03:26:02.000', lastMessageTimestamp: 0, isPinned: false, reportID: 8, @@ -101,7 +109,8 @@ describe('OptionsListUtils', () => { // Note: This report has an IOU 9: { lastVisitedTimestamp: 1610666739302, - lastMessageTimestamp: 1611282168, + lastActionCreated: '2022-11-22 03:26:02.998', + lastMessageTimestamp: 998, isPinned: false, reportID: 9, participants: ['mistersinister@marauders.com'], @@ -115,6 +124,7 @@ describe('OptionsListUtils', () => { // This report is an archived room – it does not have a name and instead falls back on oldPolicyName 10: { lastVisitedTimestamp: 1610666739200, + lastActionCreated: '2022-11-22 03:26:02.001', lastMessageTimestamp: 1, reportID: 10, isPinned: false, @@ -180,6 +190,7 @@ describe('OptionsListUtils', () => { 11: { lastVisitedTimestamp: 1610666739302, + lastActionCreated: '2022-11-22 03:26:02.022', lastMessageTimestamp: 22, isPinned: false, reportID: 11, @@ -194,6 +205,7 @@ describe('OptionsListUtils', () => { ...REPORTS, 12: { lastVisitedTimestamp: 1610666739302, + lastActionCreated: '2022-11-22 03:26:02.022', lastMessageTimestamp: 22, isPinned: false, reportID: 12, @@ -208,6 +220,7 @@ describe('OptionsListUtils', () => { ...REPORTS, 13: { lastVisitedTimestamp: 1610666739302, + lastActionCreated: '2022-11-22 03:26:02.022', lastMessageTimestamp: 22, isPinned: false, reportID: 13, diff --git a/tests/unit/SidebarFilterTest.js b/tests/unit/SidebarFilterTest.js index 769e3b8438b3..0b33be6a7d80 100644 --- a/tests/unit/SidebarFilterTest.js +++ b/tests/unit/SidebarFilterTest.js @@ -4,6 +4,7 @@ import lodashGet from 'lodash/get'; import * as LHNTestUtils from '../utils/LHNTestUtils'; import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; import CONST from '../../src/CONST'; +import DateUtils from '../../src/libs/DateUtils'; // Be sure to include the mocked permissions library or else the beta tests won't work jest.mock('../../src/libs/Permissions'); @@ -599,6 +600,7 @@ describe('Sidebar', () => { // Given an archived report with no comments const report = { ...LHNTestUtils.getFakeReport(), + lastActionCreated: '2022-11-22 03:48:27.267', lastMessageTimestamp: 0, statusNum: CONST.REPORT.STATUS.CLOSED, stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, @@ -628,7 +630,10 @@ describe('Sidebar', () => { }) // When the report has comments - .then(() => Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`, {lastMessageTimestamp: Date.now()})) + .then(() => Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`, { + lastMessageTimestamp: Date.now(), + lastActionCreated: DateUtils.getDBTime(), + })) // Then the report is rendered in the LHN .then(() => { @@ -779,6 +784,7 @@ describe('Sidebar', () => { // Given an archived report with no comments const report = { ...LHNTestUtils.getFakeReport(), + lastActionCreated: '2022-11-22 03:48:27.267', lastMessageTimestamp: 0, statusNum: CONST.REPORT.STATUS.CLOSED, stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, @@ -808,7 +814,10 @@ describe('Sidebar', () => { }) // When the report has comments - .then(() => Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`, {lastMessageTimestamp: Date.now()})) + .then(() => Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`, { + lastMessageTimestamp: Date.now(), + lastActionCreated: DateUtils.getDBTime(), + })) // Then the report is not rendered in the LHN .then(() => { diff --git a/tests/unit/SidebarOrderTest.js b/tests/unit/SidebarOrderTest.js index 466ebd425d60..1c4668a31fff 100644 --- a/tests/unit/SidebarOrderTest.js +++ b/tests/unit/SidebarOrderTest.js @@ -4,6 +4,7 @@ import lodashGet from 'lodash/get'; import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; import * as LHNTestUtils from '../utils/LHNTestUtils'; import CONST from '../../src/CONST'; +import DateUtils from "../../src/libs/DateUtils"; // Be sure to include the mocked Permissions and Expensicons libraries or else the beta tests won't work jest.mock('../../src/libs/Permissions'); @@ -181,7 +182,10 @@ describe('Sidebar', () => { })) // When a new comment is added to report 1 (eg. it's lastMessageTimestamp is updated) - .then(() => Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`, {lastMessageTimestamp: Date.now()})) + .then(() => Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`, { + lastMessageTimestamp: Date.now(), + lastActionCreated: DateUtils.getDBTime(), + })) // Then the order of the reports should be 1 > 3 > 2 // ^--- (1 goes to the front and pushes other two down) diff --git a/tests/utils/LHNTestUtils.js b/tests/utils/LHNTestUtils.js index e671c8f9e1f2..cc53d71c672c 100644 --- a/tests/utils/LHNTestUtils.js +++ b/tests/utils/LHNTestUtils.js @@ -5,6 +5,7 @@ import OnyxProvider from '../../src/components/OnyxProvider'; import {LocaleContextProvider} from '../../src/components/withLocalize'; import SidebarLinks from '../../src/pages/home/sidebar/SidebarLinks'; import CONST from '../../src/CONST'; +import DateUtils from "../../src/libs/DateUtils"; const TEST_MAX_SEQUENCE_NUMBER = 10; @@ -78,6 +79,7 @@ function getFakeReport(participants = ['email1@test.com', 'email2@test.com'], mi reportName: 'Report', maxSequenceNumber: TEST_MAX_SEQUENCE_NUMBER, lastReadSequenceNumber: TEST_MAX_SEQUENCE_NUMBER, + lastActionCreated: DateUtils.getDBTime(Date.now() - millisecondsInThePast), lastMessageTimestamp: Date.now() - millisecondsInThePast, participants, }; From 2189b24f75729dbfdd2b65e3284a98fef4e99061 Mon Sep 17 00:00:00 2001 From: rory Date: Mon, 21 Nov 2022 20:00:43 -0800 Subject: [PATCH 8/9] Fix JS style --- tests/unit/SidebarOrderTest.js | 2 +- tests/utils/LHNTestUtils.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/SidebarOrderTest.js b/tests/unit/SidebarOrderTest.js index 1c4668a31fff..55aed3a2513b 100644 --- a/tests/unit/SidebarOrderTest.js +++ b/tests/unit/SidebarOrderTest.js @@ -4,7 +4,7 @@ import lodashGet from 'lodash/get'; import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; import * as LHNTestUtils from '../utils/LHNTestUtils'; import CONST from '../../src/CONST'; -import DateUtils from "../../src/libs/DateUtils"; +import DateUtils from '../../src/libs/DateUtils'; // Be sure to include the mocked Permissions and Expensicons libraries or else the beta tests won't work jest.mock('../../src/libs/Permissions'); diff --git a/tests/utils/LHNTestUtils.js b/tests/utils/LHNTestUtils.js index cc53d71c672c..94f40a1a9c91 100644 --- a/tests/utils/LHNTestUtils.js +++ b/tests/utils/LHNTestUtils.js @@ -5,7 +5,7 @@ import OnyxProvider from '../../src/components/OnyxProvider'; import {LocaleContextProvider} from '../../src/components/withLocalize'; import SidebarLinks from '../../src/pages/home/sidebar/SidebarLinks'; import CONST from '../../src/CONST'; -import DateUtils from "../../src/libs/DateUtils"; +import DateUtils from '../../src/libs/DateUtils'; const TEST_MAX_SEQUENCE_NUMBER = 10; From e65107b36f4266c477e57049e06af4f43e022fb4 Mon Sep 17 00:00:00 2001 From: rory Date: Mon, 21 Nov 2022 20:05:05 -0800 Subject: [PATCH 9/9] Remove references to lastMessageTimestamp --- src/libs/ReportUtils.js | 1 - src/libs/actions/Report.js | 3 --- src/pages/home/sidebar/SidebarLinks.js | 1 - src/pages/reportPropTypes.js | 3 --- tests/actions/ReportTest.js | 3 --- tests/ui/UnreadIndicatorsTest.js | 3 --- tests/unit/OptionsListUtilsTest.js | 21 ++++----------------- tests/unit/SidebarFilterTest.js | 4 ---- tests/unit/SidebarOrderTest.js | 3 +-- tests/utils/LHNTestUtils.js | 1 - 10 files changed, 5 insertions(+), 38 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index e4826f6c2791..9f7ffd1a082f 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -835,7 +835,6 @@ function buildOptimisticChatReport( lastMessageText: null, lastReadSequenceNumber: 0, lastActionCreated: '', - lastMessageTimestamp: 0, lastVisitedTimestamp: 0, maxSequenceNumber: 0, notificationPreference, diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index ed4a7af39a82..d6c5220d2785 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -91,7 +91,6 @@ function getParticipantEmailsFromReport({sharedReportList, reportNameValuePairs, */ function getSimplifiedReportObject(report) { const lastActionCreated = lodashGet(report, 'lastActionCreated', 0); - const lastMessageTimestamp = moment.utc(lastActionCreated).unix(); const lastActionMessage = lodashGet(report, ['lastActionMessage', 'html'], ''); const isLastMessageAttachment = new RegExp(`]*${CONST.ATTACHMENT_SOURCE_ATTRIBUTE}\\s*=\\s*"[^"]*"[^>]*>`, 'gi').test(lastActionMessage); const chatType = lodashGet(report, ['reportNameValuePairs', 'chatType'], ''); @@ -136,7 +135,6 @@ function getSimplifiedReportObject(report) { ], 0), lastReadSequenceNumber, lastActionCreated, - lastMessageTimestamp, lastMessageText: isLastMessageAttachment ? '[Attachment]' : lastMessageText, lastActorEmail, notificationPreference, @@ -416,7 +414,6 @@ function addActions(reportID, text = '', file) { const optimisticReport = { maxSequenceNumber: newSequenceNumber, lastActionCreated: DateUtils.getDBTime(), - lastMessageTimestamp: Date.now(), lastMessageText: ReportUtils.formatReportLastMessageText(lastAction.message[0].text), lastActorEmail: currentUserEmail, lastReadSequenceNumber: newSequenceNumber, diff --git a/src/pages/home/sidebar/SidebarLinks.js b/src/pages/home/sidebar/SidebarLinks.js index 32e320682eee..c5bc3bc7a0a3 100644 --- a/src/pages/home/sidebar/SidebarLinks.js +++ b/src/pages/home/sidebar/SidebarLinks.js @@ -213,7 +213,6 @@ const reportSelector = report => report && ({ maxSequenceNumber: report.maxSequenceNumber, lastReadSequenceNumber: report.lastReadSequenceNumber, lastMessageText: report.lastMessageText, - lastMessageTimestamp: report.lastMessageTimestamp, lastActionCreated: report.lastActionCreated, iouReportID: report.iouReportID, hasOutstandingIOU: report.hasOutstandingIOU, diff --git a/src/pages/reportPropTypes.js b/src/pages/reportPropTypes.js index 0ce6dfcbe729..bc233b305676 100644 --- a/src/pages/reportPropTypes.js +++ b/src/pages/reportPropTypes.js @@ -34,9 +34,6 @@ export default PropTypes.shape({ /** The time of the last message on the report */ lastActionCreated: PropTypes.string, - /** The time of the last message on the report (in unix timestamp form) */ - lastMessageTimestamp: PropTypes.number, - /** The sequence number of the last action read by the user */ lastReadSequenceNumber: PropTypes.number, diff --git a/tests/actions/ReportTest.js b/tests/actions/ReportTest.js index e4ca092fc645..6cfba6aca324 100644 --- a/tests/actions/ReportTest.js +++ b/tests/actions/ReportTest.js @@ -111,7 +111,6 @@ describe('actions/Report', () => { reportID: REPORT_ID, maxSequenceNumber: 1, notificationPreference: 'always', - lastMessageTimestamp: 0, lastActionCreated: '2022-11-22 03:48:27.267', lastMessageText: 'Testing a comment', lastActorEmail: TEST_USER_LOGIN, @@ -241,7 +240,6 @@ describe('actions/Report', () => { reportID: REPORT_ID, maxSequenceNumber: 1, notificationPreference: 'always', - lastMessageTimestamp: 0, lastActionCreated: '2022-11-22 03:48:27.267', lastMessageText: 'Comment 1', lastActorEmail: USER_2_LOGIN, @@ -340,7 +338,6 @@ describe('actions/Report', () => { reportID: REPORT_ID, maxSequenceNumber: 4, notificationPreference: 'always', - lastMessageTimestamp: 0, lastActionCreated: '2022-11-22 03:48:27.267', lastMessageText: 'Current User Comment 3', lastActorEmail: 'test@test.com', diff --git a/tests/ui/UnreadIndicatorsTest.js b/tests/ui/UnreadIndicatorsTest.js index 7ccf1eb6cbea..81c954d6f3fd 100644 --- a/tests/ui/UnreadIndicatorsTest.js +++ b/tests/ui/UnreadIndicatorsTest.js @@ -134,7 +134,6 @@ function signInAndGetAppWithUnreadChat() { reportName: CONST.REPORT.DEFAULT_REPORT_NAME, maxSequenceNumber: 9, lastReadSequenceNumber: 1, - lastMessageTimestamp: MOMENT_TEN_MINUTES_AGO.utc().valueOf(), lastActionCreated: DateUtils.getDBTime(MOMENT_TEN_MINUTES_AGO.utc().valueOf()), lastMessageText: 'Test', participants: [USER_B_EMAIL], @@ -270,7 +269,6 @@ describe('Unread Indicators', () => { reportName: CONST.REPORT.DEFAULT_REPORT_NAME, maxSequenceNumber: 1, lastReadSequenceNumber: 0, - lastMessageTimestamp: NEW_REPORT_CREATED_MOMENT.utc().valueOf(), lastActionCreated: DateUtils.getDBTime(NEW_REPORT_CREATED_MOMENT.utc().valueOf()), lastMessageText: 'Comment 1', participants: [USER_C_EMAIL], @@ -500,7 +498,6 @@ describe('Unread Indicators', () => { delete lastReportAction[lastReportAction.clientID]; Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, { lastMessageText: lastReportAction.message[0].text, - lastMessageTimestamp: lastReportAction.timestamp, lastActionCreated: DateUtils.getDBTime(lastReportAction.timestamp), lastActorEmail: lastReportAction.actorEmail, maxSequenceNumber: lastReportAction.sequenceNumber, diff --git a/tests/unit/OptionsListUtilsTest.js b/tests/unit/OptionsListUtilsTest.js index 8bf168fa7bc3..db6dffdc0f1a 100644 --- a/tests/unit/OptionsListUtilsTest.js +++ b/tests/unit/OptionsListUtilsTest.js @@ -13,7 +13,6 @@ describe('OptionsListUtils', () => { 1: { lastVisitedTimestamp: 1610666739295, lastActionCreated: '2022-11-22 03:26:02.015', - lastMessageTimestamp: 15, isPinned: false, reportID: 1, participants: ['tonystark@expensify.com', 'reedrichards@expensify.com'], @@ -25,7 +24,6 @@ describe('OptionsListUtils', () => { 2: { lastVisitedTimestamp: 1610666739296, lastActionCreated: '2022-11-22 03:26:02.016', - lastMessageTimestamp: 16, isPinned: false, reportID: 2, participants: ['peterparker@expensify.com'], @@ -38,7 +36,6 @@ describe('OptionsListUtils', () => { 3: { lastVisitedTimestamp: 1610666739297, lastActionCreated: '2022-11-22 03:26:02.170', - lastMessageTimestamp: 170, isPinned: true, reportID: 3, participants: ['reedrichards@expensify.com'], @@ -49,7 +46,6 @@ describe('OptionsListUtils', () => { 4: { lastVisitedTimestamp: 1610666739298, lastActionCreated: '2022-11-22 03:26:02.180', - lastMessageTimestamp: 180, isPinned: false, reportID: 4, participants: ['tchalla@expensify.com'], @@ -60,7 +56,6 @@ describe('OptionsListUtils', () => { 5: { lastVisitedTimestamp: 1610666739299, lastActionCreated: '2022-11-22 03:26:02.019', - lastMessageTimestamp: 19, isPinned: false, reportID: 5, participants: ['suestorm@expensify.com'], @@ -71,7 +66,6 @@ describe('OptionsListUtils', () => { 6: { lastVisitedTimestamp: 1610666739300, lastActionCreated: '2022-11-22 03:26:02.020', - lastMessageTimestamp: 20, isPinned: false, reportID: 6, participants: ['thor@expensify.com'], @@ -80,11 +74,10 @@ describe('OptionsListUtils', () => { maxSequenceNumber: TEST_MAX_SEQUENCE_NUMBER, }, - // Note: This report has the largest lastMessageTimestamp + // Note: This report has the largest lastActionCreated 7: { lastVisitedTimestamp: 1610666739301, lastActionCreated: '2022-11-22 03:26:03.999', - lastMessageTimestamp: 999, isPinned: false, reportID: 7, participants: ['steverogers@expensify.com'], @@ -93,11 +86,10 @@ describe('OptionsListUtils', () => { maxSequenceNumber: TEST_MAX_SEQUENCE_NUMBER, }, - // Note: This report has no lastMessageTimestamp + // Note: This report has no lastActionCreated 8: { lastVisitedTimestamp: 1610666739301, lastActionCreated: '2022-11-22 03:26:02.000', - lastMessageTimestamp: 0, isPinned: false, reportID: 8, participants: ['galactus_herald@expensify.com'], @@ -110,7 +102,6 @@ describe('OptionsListUtils', () => { 9: { lastVisitedTimestamp: 1610666739302, lastActionCreated: '2022-11-22 03:26:02.998', - lastMessageTimestamp: 998, isPinned: false, reportID: 9, participants: ['mistersinister@marauders.com'], @@ -125,7 +116,6 @@ describe('OptionsListUtils', () => { 10: { lastVisitedTimestamp: 1610666739200, lastActionCreated: '2022-11-22 03:26:02.001', - lastMessageTimestamp: 1, reportID: 10, isPinned: false, participants: ['tonystark@expensify.com', 'steverogers@expensify.com'], @@ -191,7 +181,6 @@ describe('OptionsListUtils', () => { 11: { lastVisitedTimestamp: 1610666739302, lastActionCreated: '2022-11-22 03:26:02.022', - lastMessageTimestamp: 22, isPinned: false, reportID: 11, participants: ['concierge@expensify.com'], @@ -206,7 +195,6 @@ describe('OptionsListUtils', () => { 12: { lastVisitedTimestamp: 1610666739302, lastActionCreated: '2022-11-22 03:26:02.022', - lastMessageTimestamp: 22, isPinned: false, reportID: 12, participants: ['chronos@expensify.com'], @@ -221,7 +209,6 @@ describe('OptionsListUtils', () => { 13: { lastVisitedTimestamp: 1610666739302, lastActionCreated: '2022-11-22 03:26:02.022', - lastMessageTimestamp: 22, isPinned: false, reportID: 13, participants: ['receipts@expensify.com'], @@ -310,7 +297,7 @@ describe('OptionsListUtils', () => { // When we filter again but provide a searchValue that should match multiple times results = OptionsListUtils.getSearchOptions(REPORTS, PERSONAL_DETAILS, 'fantastic'); - // Value with latest lastMessageTimestamp should be at the top. + // Value with latest lastActionCreated should be at the top. expect(results.recentReports.length).toBe(2); expect(results.recentReports[0].text).toBe('Mister Fantastic'); expect(results.recentReports[1].text).toBe('Mister Fantastic'); @@ -383,7 +370,7 @@ describe('OptionsListUtils', () => { // Then several options will be returned and they will be each have the search string in their email or name // even though the currently logged in user matches they should not show. - // Should be ordered by lastMessageTimestamp values. + // Should be ordered by lastActionCreated values. expect(results.personalDetails.length).toBe(4); expect(results.recentReports.length).toBe(5); expect(results.personalDetails[0].login).toBe('natasharomanoff@expensify.com'); diff --git a/tests/unit/SidebarFilterTest.js b/tests/unit/SidebarFilterTest.js index 0b33be6a7d80..b9b5da13aca4 100644 --- a/tests/unit/SidebarFilterTest.js +++ b/tests/unit/SidebarFilterTest.js @@ -601,7 +601,6 @@ describe('Sidebar', () => { const report = { ...LHNTestUtils.getFakeReport(), lastActionCreated: '2022-11-22 03:48:27.267', - lastMessageTimestamp: 0, statusNum: CONST.REPORT.STATUS.CLOSED, stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, }; @@ -631,7 +630,6 @@ describe('Sidebar', () => { // When the report has comments .then(() => Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`, { - lastMessageTimestamp: Date.now(), lastActionCreated: DateUtils.getDBTime(), })) @@ -785,7 +783,6 @@ describe('Sidebar', () => { const report = { ...LHNTestUtils.getFakeReport(), lastActionCreated: '2022-11-22 03:48:27.267', - lastMessageTimestamp: 0, statusNum: CONST.REPORT.STATUS.CLOSED, stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, }; @@ -815,7 +812,6 @@ describe('Sidebar', () => { // When the report has comments .then(() => Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`, { - lastMessageTimestamp: Date.now(), lastActionCreated: DateUtils.getDBTime(), })) diff --git a/tests/unit/SidebarOrderTest.js b/tests/unit/SidebarOrderTest.js index 55aed3a2513b..0f5a313e00cb 100644 --- a/tests/unit/SidebarOrderTest.js +++ b/tests/unit/SidebarOrderTest.js @@ -181,9 +181,8 @@ describe('Sidebar', () => { [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, })) - // When a new comment is added to report 1 (eg. it's lastMessageTimestamp is updated) + // When a new comment is added to report 1 (eg. it's lastActionCreated is updated) .then(() => Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`, { - lastMessageTimestamp: Date.now(), lastActionCreated: DateUtils.getDBTime(), })) diff --git a/tests/utils/LHNTestUtils.js b/tests/utils/LHNTestUtils.js index 94f40a1a9c91..aedd71d6ccdc 100644 --- a/tests/utils/LHNTestUtils.js +++ b/tests/utils/LHNTestUtils.js @@ -80,7 +80,6 @@ function getFakeReport(participants = ['email1@test.com', 'email2@test.com'], mi maxSequenceNumber: TEST_MAX_SEQUENCE_NUMBER, lastReadSequenceNumber: TEST_MAX_SEQUENCE_NUMBER, lastActionCreated: DateUtils.getDBTime(Date.now() - millisecondsInThePast), - lastMessageTimestamp: Date.now() - millisecondsInThePast, participants, }; }