From 7a0355dc347d1c4567312a785ccd8bcb4edff296 Mon Sep 17 00:00:00 2001 From: Carlos Alvarez Date: Mon, 25 Apr 2022 17:29:14 -0700 Subject: [PATCH 1/6] Add GetChats --- src/libs/API.js | 12 ++++++++++++ src/libs/actions/Report.js | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/libs/API.js b/src/libs/API.js index 255efbf221bd..3c0ee5bc6076 100644 --- a/src/libs/API.js +++ b/src/libs/API.js @@ -350,6 +350,17 @@ function GetAccountStatus(parameters) { return Network.post(commandName, parameters); } +/** + * @param {Object} parameters + * @param {String} parameters.reportIDList + * @returns {Promise} + */ +function GetChats(parameters) { + const commandName = 'Get_Chats'; + requireParameters(['reportIDList'], parameters, commandName); + return Network.post(commandName, parameters); +} + /** * Returns a short lived authToken for this account * @returns {Promise} @@ -1137,6 +1148,7 @@ export { DeleteBankAccount, Get, GetAccountStatus, + GetChats, GetShortLivedAuthToken, GetStatementPDF, GetIOUReport, diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index eb01d496f6a3..91079cce6970 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -1010,7 +1010,7 @@ function fetchAllReports( // Get all the chat reports if they have any, otherwise create one with concierge if (reportIDs.length > 0) { - return fetchChatReportsByIDs(reportIDs); + return API.GetChats({reportIDList: reportIDs}); } return fetchOrCreateChatReport([currentUserEmail, CONST.EMAIL.CONCIERGE], false); From 57ab5c9cf876cb59e3eb7690c87026e59a0185f4 Mon Sep 17 00:00:00 2001 From: Carlos Alvarez Date: Thu, 12 May 2022 18:27:21 -0700 Subject: [PATCH 2/6] Use GetChats --- src/libs/actions/Report.js | 41 +++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 91079cce6970..b4fb8da40035 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -397,6 +397,7 @@ function fetchChatReportsByIDs(chatList, shouldRedirectIfInaccessible = false) { // variable called simplifiedReports which hold the participants (minus the current user) for each report. // Using this simplifiedReport we can call PersonalDetails.getFromReportParticipants to get the // personal details of all the participants and even link up their avatars to report icons. + window.ioureports = iouReportObjects; const reportIOUData = {}; _.each(fetchedReports, (report) => { const simplifiedReport = getSimplifiedReportObject(report); @@ -1010,12 +1011,50 @@ function fetchAllReports( // Get all the chat reports if they have any, otherwise create one with concierge if (reportIDs.length > 0) { - return API.GetChats({reportIDList: reportIDs}); + // return fetchChatReportsByIDs(reportIDs); + let fetchedReports; + const simplifiedReports = {}; + return API.GetChats({reportIDList: reportIDs}) + .then((iouReportObjects) => { + fetchedReports = iouReportObjects.reportList; + // Process the reports and store them in Onyx. At the same time we'll save the simplified reports in this + // variable called simplifiedReports which hold the participants (minus the current user) for each report. + // Using this simplifiedReport we can call PersonalDetails.getFromReportParticipants to get the + // personal details of all the participants and even link up their avatars to report icons. + const reportIOUData = {}; + _.each(fetchedReports, (report) => { + const simplifiedReport = getSimplifiedReportObject(report); + simplifiedReports[`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`] = simplifiedReport; + }); + + window.fetchedReports = fetchedReports; + _.each(fetchedReports, (iouReportObject) => { + if (!iouReportObject) { + return; + } + + const iouReportKey = `${ONYXKEYS.COLLECTION.REPORT_IOUS}${iouReportObject.reportID}`; + const reportKey = `${ONYXKEYS.COLLECTION.REPORT}${iouReportObject.reportID}`; + reportIOUData[iouReportKey] = iouReportObject; + simplifiedReports[reportKey].iouReportID = iouReportObject.iouChatReportID; + }); + + // We use mergeCollection such that it updates the collection in one go. + // Any withOnyx subscribers to this key will also receive the complete updated props just once + // than updating props for each report and re-rendering had merge been used. + Onyx.mergeCollection(ONYXKEYS.COLLECTION.REPORT_IOUS, reportIOUData); + Onyx.mergeCollection(ONYXKEYS.COLLECTION.REPORT, simplifiedReports); + + // Fetch the personal details if there are any + PersonalDetails.getFromReportParticipants(_.values(simplifiedReports)); + return simplifiedReports; + }); } return fetchOrCreateChatReport([currentUserEmail, CONST.EMAIL.CONCIERGE], false); }) .then((returnedReports) => { + returnedReports = returnedReports.reportList; Onyx.set(ONYXKEYS.INITIAL_REPORT_DATA_LOADED, true); Onyx.set(ONYXKEYS.IS_LOADING_REPORT_DATA, false); From 43b0e31c70b606fdd02b23d4a3ac0dfe484be91f Mon Sep 17 00:00:00 2001 From: Carlos Alvarez Date: Fri, 13 May 2022 13:09:24 -0700 Subject: [PATCH 3/6] Handle improved response of GetChats --- src/libs/actions/Report.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index b4fb8da40035..386ab09a7bbd 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -1012,31 +1012,28 @@ function fetchAllReports( // Get all the chat reports if they have any, otherwise create one with concierge if (reportIDs.length > 0) { // return fetchChatReportsByIDs(reportIDs); - let fetchedReports; const simplifiedReports = {}; return API.GetChats({reportIDList: reportIDs}) - .then((iouReportObjects) => { - fetchedReports = iouReportObjects.reportList; + .then((chats) => { // Process the reports and store them in Onyx. At the same time we'll save the simplified reports in this // variable called simplifiedReports which hold the participants (minus the current user) for each report. // Using this simplifiedReport we can call PersonalDetails.getFromReportParticipants to get the // personal details of all the participants and even link up their avatars to report icons. const reportIOUData = {}; - _.each(fetchedReports, (report) => { + _.each(chats.reportList, (report) => { const simplifiedReport = getSimplifiedReportObject(report); simplifiedReports[`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`] = simplifiedReport; }); - window.fetchedReports = fetchedReports; - _.each(fetchedReports, (iouReportObject) => { + _.each(chats.iouReportList, (iouReportObject) => { if (!iouReportObject) { return; } const iouReportKey = `${ONYXKEYS.COLLECTION.REPORT_IOUS}${iouReportObject.reportID}`; - const reportKey = `${ONYXKEYS.COLLECTION.REPORT}${iouReportObject.reportID}`; - reportIOUData[iouReportKey] = iouReportObject; - simplifiedReports[reportKey].iouReportID = iouReportObject.iouChatReportID; + const reportKey = `${ONYXKEYS.COLLECTION.REPORT}${iouReportObject.chatReportID}`; + reportIOUData[iouReportKey] = getSimplifiedIOUReport(iouReportObject, iouReportObject.chatReportID); + simplifiedReports[reportKey].iouReportID = iouReportObject.reportID; }); // We use mergeCollection such that it updates the collection in one go. From c1d2236cce28d91dab8d1652c68f76dda978550c Mon Sep 17 00:00:00 2001 From: Carlos Alvarez Date: Fri, 20 May 2022 14:38:45 -0700 Subject: [PATCH 4/6] Add missing hasOutstandingIOU. Badges are showing --- src/libs/actions/Report.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 2c804d77718e..5e2122a5b1d6 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -1035,6 +1035,7 @@ function fetchAllReports( const reportKey = `${ONYXKEYS.COLLECTION.REPORT}${iouReportObject.chatReportID}`; reportIOUData[iouReportKey] = getSimplifiedIOUReport(iouReportObject, iouReportObject.chatReportID); simplifiedReports[reportKey].iouReportID = iouReportObject.reportID; + simplifiedReports[reportKey].hasOutstandingIOU = iouReportObject.stateNum === CONST.REPORT.STATE_NUM.PROCESSING && iouReportObject.total !== 0; }); // We use mergeCollection such that it updates the collection in one go. From edd00bdb48364360c9f23dc9813b627e3818d4e9 Mon Sep 17 00:00:00 2001 From: Carlos Alvarez Date: Tue, 7 Jun 2022 13:40:13 -0700 Subject: [PATCH 5/6] Use (new) DeprecatedAPI --- src/libs/actions/Report.js | 2 +- src/libs/deprecatedAPI.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index ec443644a12d..d1eec01da7cf 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -988,7 +988,7 @@ function fetchAllReports( if (reportIDs.length > 0) { // return fetchChatReportsByIDs(reportIDs); const simplifiedReports = {}; - return API.GetChats({reportIDList: reportIDs}) + return DeprecatedAPI.GetChats({reportIDList: reportIDs}) .then((chats) => { // Process the reports and store them in Onyx. At the same time we'll save the simplified reports in this // variable called simplifiedReports which hold the participants (minus the current user) for each report. diff --git a/src/libs/deprecatedAPI.js b/src/libs/deprecatedAPI.js index 4fa92ab6f208..11ed104ec3e7 100644 --- a/src/libs/deprecatedAPI.js +++ b/src/libs/deprecatedAPI.js @@ -945,6 +945,7 @@ export { DeleteBankAccount, Get, GetAccountStatus, + GetChats, GetShortLivedAuthToken, GetStatementPDF, GetIOUReport, From a21ae8b2fcad46eb424b47e61af20eabeb9c91c0 Mon Sep 17 00:00:00 2001 From: Carlos Alvarez Date: Mon, 20 Jun 2022 18:06:18 -0700 Subject: [PATCH 6/6] GetChats no longer needs a reportIDList --- src/libs/actions/Report.js | 134 +++++++++++++++++++++++++++---------- src/libs/deprecatedAPI.js | 4 +- 2 files changed, 99 insertions(+), 39 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 3f8fa50c835f..2e7d1f9b30f6 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -809,6 +809,101 @@ function fetchActionsWithLoadingState(reportID, offset) { .finally(() => Onyx.set(ONYXKEYS.IS_LOADING_REPORT_ACTIONS, false)); } +function getChats(shouldRecordHomePageTiming, shouldDelayActionsFetch) { + const simplifiedReports = {}; + return DeprecatedAPI.GetChats() + .then((chats) => { + // Process the reports and store them in Onyx. At the same time we'll save the simplified reports in this + // variable called simplifiedReports which hold the participants (minus the current user) for each report. + // Using this simplifiedReport we can call PersonalDetails.getFromReportParticipants to get the + // personal details of all the participants and even link up their avatars to report icons. + const reportIOUData = {}; + _.each(chats.reportList, (report) => { + const simplifiedReport = getSimplifiedReportObject(report); + simplifiedReports[`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`] = simplifiedReport; + }); + + _.each(chats.iouReportList, (iouReportObject) => { + if (!iouReportObject) { + return; + } + + const iouReportKey = `${ONYXKEYS.COLLECTION.REPORT_IOUS}${iouReportObject.reportID}`; + const reportKey = `${ONYXKEYS.COLLECTION.REPORT}${iouReportObject.chatReportID}`; + reportIOUData[iouReportKey] = getSimplifiedIOUReport(iouReportObject, iouReportObject.chatReportID); + simplifiedReports[reportKey].iouReportID = iouReportObject.reportID; + simplifiedReports[reportKey].hasOutstandingIOU = iouReportObject.stateNum === CONST.REPORT.STATE_NUM.PROCESSING && iouReportObject.total !== 0; + }); + + // We use mergeCollection such that it updates the collection in one go. + // Any withOnyx subscribers to this key will also receive the complete updated props just once + // than updating props for each report and re-rendering had merge been used. + Onyx.mergeCollection(ONYXKEYS.COLLECTION.REPORT_IOUS, reportIOUData); + Onyx.mergeCollection(ONYXKEYS.COLLECTION.REPORT, simplifiedReports); + + // Fetch the personal details if there are any + PersonalDetails.getFromReportParticipants(_.values(simplifiedReports)); + return simplifiedReports; + }) + .then((returnedReports) => { + returnedReports = returnedReports.reportList; + Onyx.set(ONYXKEYS.INITIAL_REPORT_DATA_LOADED, true); + Onyx.set(ONYXKEYS.IS_LOADING_REPORT_DATA, false); + + // If at this point the user still doesn't have a Concierge report, create it for them. + // This means they were a participant in reports before their account was created (e.g. default rooms) + const hasConciergeChat = _.some(returnedReports, report => ReportUtils.isConciergeChatReport(report)); + if (!hasConciergeChat) { + fetchOrCreateChatReport([currentUserEmail, CONST.EMAIL.CONCIERGE], false); + } + + if (shouldRecordHomePageTiming) { + Timing.end(CONST.TIMING.HOMEPAGE_REPORTS_LOADED); + } + + // Delay fetching report history as it significantly increases sign in to interactive time. + // Register the timer so we can clean it up if the user quickly logs out after logging in. If we don't + // cancel the timer we'll make unnecessary API requests from the sign in page. + Timers.register(setTimeout(() => { + // Filter reports to see which ones have actions we need to fetch so we can preload Onyx with new + // content and improve chat switching experience by only downloading content we don't have yet. + // This improves performance significantly when reconnecting by limiting API requests and unnecessary + // data processing by Onyx. + const reportIDsWithMissingActions = _.chain(returnedReports) + .map(report => report.reportID) + .filter(reportID => ReportActions.isReportMissingActions(reportID, reportMaxSequenceNumbers[reportID])) + .value(); + + // Once we have the reports that are missing actions we will find the intersection between the most + // recently accessed reports and reports missing actions. Then we'll fetch the history for a small + // set to avoid making too many network requests at once. + const reportIDsToFetchActions = _.chain(ReportUtils.sortReportsByLastVisited(allReports)) + .map(report => report.reportID) + .reverse() + .intersection(reportIDsWithMissingActions) + .slice(0, 10) + .value(); + + if (_.isEmpty(reportIDsToFetchActions)) { + Log.info('[Report] Local reportActions up to date. Not fetching additional actions.'); + return; + } + + Log.info('[Report] Fetching reportActions for reportIDs: ', false, { + reportIDs: reportIDsToFetchActions, + }); + _.each(reportIDsToFetchActions, (reportID) => { + const offset = ReportActions.dangerouslyGetReportActionsMaxSequenceNumber(reportID, false); + fetchActions(reportID, offset); + }); + + // We are waiting a set amount of time to allow the UI to finish loading before bogging it down with + // more requests and operations. Startup delay is longer since there is a lot more work done to build + // up the UI when the app first initializes. + }, shouldDelayActionsFetch ? CONST.FETCH_ACTIONS_DELAY.STARTUP : CONST.FETCH_ACTIONS_DELAY.RECONNECT)); + }); +} + /** * Get all of our reports * @@ -821,6 +916,7 @@ function fetchAllReports( shouldDelayActionsFetch = false, ) { Onyx.set(ONYXKEYS.IS_LOADING_REPORT_DATA, true); + // return getChats(shouldRecordHomePageTiming, shouldDelayActionsFetch); return DeprecatedAPI.Get({ returnValueList: 'chatList', }) @@ -834,48 +930,12 @@ function fetchAllReports( // Get all the chat reports if they have any, otherwise create one with concierge if (reportIDs.length > 0) { - // return fetchChatReportsByIDs(reportIDs); - const simplifiedReports = {}; - return DeprecatedAPI.GetChats({reportIDList: reportIDs}) - .then((chats) => { - // Process the reports and store them in Onyx. At the same time we'll save the simplified reports in this - // variable called simplifiedReports which hold the participants (minus the current user) for each report. - // Using this simplifiedReport we can call PersonalDetails.getFromReportParticipants to get the - // personal details of all the participants and even link up their avatars to report icons. - const reportIOUData = {}; - _.each(chats.reportList, (report) => { - const simplifiedReport = getSimplifiedReportObject(report); - simplifiedReports[`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`] = simplifiedReport; - }); - - _.each(chats.iouReportList, (iouReportObject) => { - if (!iouReportObject) { - return; - } - - const iouReportKey = `${ONYXKEYS.COLLECTION.REPORT_IOUS}${iouReportObject.reportID}`; - const reportKey = `${ONYXKEYS.COLLECTION.REPORT}${iouReportObject.chatReportID}`; - reportIOUData[iouReportKey] = getSimplifiedIOUReport(iouReportObject, iouReportObject.chatReportID); - simplifiedReports[reportKey].iouReportID = iouReportObject.reportID; - simplifiedReports[reportKey].hasOutstandingIOU = iouReportObject.stateNum === CONST.REPORT.STATE_NUM.PROCESSING && iouReportObject.total !== 0; - }); - - // We use mergeCollection such that it updates the collection in one go. - // Any withOnyx subscribers to this key will also receive the complete updated props just once - // than updating props for each report and re-rendering had merge been used. - Onyx.mergeCollection(ONYXKEYS.COLLECTION.REPORT_IOUS, reportIOUData); - Onyx.mergeCollection(ONYXKEYS.COLLECTION.REPORT, simplifiedReports); - - // Fetch the personal details if there are any - PersonalDetails.getFromReportParticipants(_.values(simplifiedReports)); - return simplifiedReports; - }); + return fetchChatReportsByIDs(reportIDs); } return fetchOrCreateChatReport([currentUserEmail, CONST.EMAIL.CONCIERGE], false); }) .then((returnedReports) => { - returnedReports = returnedReports.reportList; Onyx.set(ONYXKEYS.INITIAL_REPORT_DATA_LOADED, true); Onyx.set(ONYXKEYS.IS_LOADING_REPORT_DATA, false); diff --git a/src/libs/deprecatedAPI.js b/src/libs/deprecatedAPI.js index 11ed104ec3e7..fa63dd0a8756 100644 --- a/src/libs/deprecatedAPI.js +++ b/src/libs/deprecatedAPI.js @@ -152,9 +152,9 @@ function GetAccountStatus(parameters) { * @param {String} parameters.reportIDList * @returns {Promise} */ -function GetChats(parameters) { +function GetChats() { const commandName = 'Get_Chats'; - requireParameters(['reportIDList'], parameters, commandName); + const parameters = {}; return Network.post(commandName, parameters); }