From cf027e04fdafee49b8874ed97ad50ff264f5861d Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 28 Aug 2020 11:45:01 -0700 Subject: [PATCH 1/6] Surface chats that did not previously exist in realtime. Fix personal details bug. --- src/lib/actions/Report.js | 205 +++++++++++++------------ src/page/home/sidebar/SidebarBottom.js | 8 + 2 files changed, 119 insertions(+), 94 deletions(-) diff --git a/src/lib/actions/Report.js b/src/lib/actions/Report.js index 1fdbef6965ba5..524d20133f868 100644 --- a/src/lib/actions/Report.js +++ b/src/lib/actions/Report.js @@ -11,74 +11,6 @@ import ExpensiMark from '../ExpensiMark'; import Notification from '../Notification'; import * as PersonalDetails from './PersonalDetails'; -/** - * Updates a report in the store with a new report action - * - * @param {string} reportID - * @param {object} reportAction - */ -function updateReportWithNewAction(reportID, reportAction) { - let currentUserEmail; - Ion.get(`${IONKEYS.REPORT}_${reportID}`, 'reportID') - .then((ionReportID) => { - // This is necessary for local development because there will be pusher events from other engineers with - // different reportIDs - if (!CONFIG.IS_IN_PRODUCTION && !ionReportID) { - throw new Error('report does not exist in the store, so ignoring new comments'); - } - - // Get the report history and return that to the next chain - return Ion.get(`${IONKEYS.REPORT_HISTORY}_${reportID}`); - }) - - // Look to see if the report action from pusher already exists or not (it would exist if it's a comment just - // written by the user). If the action doesn't exist, then update the unread flag on the report so the user - // knows there is a new comment - .then((reportHistory) => { - if (reportHistory && !reportHistory[reportAction.sequenceNumber]) { - Ion.merge(`${IONKEYS.REPORT}_${reportID}`, {hasUnread: true}); - } - return reportHistory || {}; - }) - - // Put the report action from pusher into the history, it's OK to overwrite it if it already exists - .then(reportHistory => ({ - ...reportHistory, - [reportAction.sequenceNumber]: reportAction, - })) - - // Put the report history back into Ion - .then(reportHistory => Ion.set(`${IONKEYS.REPORT_HISTORY}_${reportID}`, reportHistory)) - - // Check to see if we need to show a notification for this report - .then(() => Ion.get(IONKEYS.SESSION, 'email')) - .then((email) => { - currentUserEmail = email; - return Ion.get(IONKEYS.CURRENT_URL); - }) - .then((currentUrl) => { - // If this comment is from the current user we don't want to parrot whatever they wrote back to them. - if (reportAction.actorEmail === currentUserEmail) { - return; - } - - const currentReportID = Number(lodashGet(currentUrl.split('/'), [1], 0)); - - // If we are currently viewing this report do not show a notification. - if (reportID === currentReportID) { - return; - } - - Notification.showCommentNotification({ - reportAction, - onClick: () => { - // Navigate to this report onClick - Ion.set(IONKEYS.APP_REDIRECT_TO, `/${reportID}`); - } - }); - }); -} - /** * Checks the report to see if there are any unread history items * @@ -126,21 +58,6 @@ function getSimplifiedReportObject(report, accountID) { }; } -/** - * Initialize our pusher subscriptions to listen for new report comments - * - * @returns {Promise} - */ -function subscribeToReportCommentEvents() { - return Ion.get(IONKEYS.SESSION, 'accountID') - .then((accountID) => { - const pusherChannelName = `private-user-accountID-${accountID}`; - Pusher.subscribe(pusherChannelName, 'reportComment', (pushJSON) => { - updateReportWithNewAction(pushJSON.reportID, pushJSON.reportAction); - }); - }); -} - /** * Returns a generated report title based on the participants * @@ -159,27 +76,27 @@ function getChatReportName(sharedReportList, personalDetails, currentUserEmail) } /** - * Get all chat reports and provide the proper report name - * by fetching sharedReportList and personalDetails + * Fetches chat reports when provided a list of + * chat report IDs * - * @returns {Promise} + * @param {Array} chatList + * + * @return {Promise} */ -function fetchChatReports() { +function fetchChatReportsByIDs(chatList) { let currentUserEmail; let currentUserAccountID; let fetchedReports; - return Ion.get(IONKEYS.SESSION) .then((session) => { currentUserEmail = session.email; currentUserAccountID = session.accountID; - return queueRequest('Get', {returnValueList: 'chatList'}); + return queueRequest('Get', { + returnValueList: 'reportStuff', + reportIDList: chatList.join(','), + shouldLoadOptionalKeys: true, + }); }) - .then(({chatList}) => queueRequest('Get', { - returnValueList: 'reportStuff', - reportIDList: chatList, - shouldLoadOptionalKeys: true, - })) .then(({reports}) => { fetchedReports = reports; @@ -220,6 +137,106 @@ function fetchChatReports() { }); } +/** + * Updates a report in the store with a new report action + * + * @param {string} reportID + * @param {object} reportAction + */ +function updateReportWithNewAction(reportID, reportAction) { + let currentUserEmail; + Ion.get(`${IONKEYS.REPORT}_${reportID}`, 'reportID') + .then((ionReportID) => { + // This is necessary for local development because there will be pusher events from other engineers with + // different reportIDs. This means that while in development it's not possible to make new chats appear + // by leaving creating chats and leaving comments in other windows + if (!CONFIG.IS_IN_PRODUCTION && !ionReportID) { + throw new Error('report does not exist in the store, so ignoring new comments'); + } + + if (CONFIG.IS_IN_PRODUCTION && !ionReportID) { + return fetchChatReportsByIDs([reportID]) + .then(() => Ion.get(`${IONKEYS.REPORT_HISTORY}_${reportID}`)); + } + + // Get the report history and return that to the next chain + return Ion.get(`${IONKEYS.REPORT_HISTORY}_${reportID}`); + }) + + // Look to see if the report action from pusher already exists or not (it would exist if it's a comment just + // written by the user). If the action doesn't exist, then update the unread flag on the report so the user + // knows there is a new comment + .then((reportHistory) => { + if (reportHistory && !reportHistory[reportAction.sequenceNumber]) { + Ion.merge(`${IONKEYS.REPORT}_${reportID}`, {hasUnread: true}); + } + return reportHistory || {}; + }) + + // Put the report action from pusher into the history, it's OK to overwrite it if it already exists + .then(reportHistory => ({ + ...reportHistory, + [reportAction.sequenceNumber]: reportAction, + })) + + // Put the report history back into Ion + .then(reportHistory => Ion.set(`${IONKEYS.REPORT_HISTORY}_${reportID}`, reportHistory)) + + // Check to see if we need to show a notification for this report + .then(() => Ion.get(IONKEYS.SESSION, 'email')) + .then((email) => { + currentUserEmail = email; + return Ion.get(IONKEYS.CURRENT_URL); + }) + .then((currentUrl) => { + // If this comment is from the current user we don't want to parrot whatever they wrote back to them. + if (reportAction.actorEmail === currentUserEmail) { + return; + } + + const currentReportID = Number(lodashGet(currentUrl.split('/'), [1], 0)); + + // If we are currently viewing this report do not show a notification. + if (reportID === currentReportID) { + return; + } + + Notification.showCommentNotification({ + reportAction, + onClick: () => { + // Navigate to this report onClick + Ion.set(IONKEYS.APP_REDIRECT_TO, `/${reportID}`); + } + }); + }); +} + +/** + * Initialize our pusher subscriptions to listen for new report comments + * + * @returns {Promise} + */ +function subscribeToReportCommentEvents() { + return Ion.get(IONKEYS.SESSION, 'accountID') + .then((accountID) => { + const pusherChannelName = `private-user-accountID-${accountID}`; + Pusher.subscribe(pusherChannelName, 'reportComment', (pushJSON) => { + updateReportWithNewAction(pushJSON.reportID, pushJSON.reportAction); + }); + }); +} + +/** + * Get all chat reports and provide the proper report name + * by fetching sharedReportList and personalDetails + * + * @returns {Promise} + */ +function fetchChatReports() { + return queueRequest('Get', {returnValueList: 'chatList'}) + .then(({chatList}) => fetchChatReportsByIDs(String(chatList).split(','))); +} + /** * Get all of our reports * diff --git a/src/page/home/sidebar/SidebarBottom.js b/src/page/home/sidebar/SidebarBottom.js index 65b166116e28b..4bb589f5aa879 100644 --- a/src/page/home/sidebar/SidebarBottom.js +++ b/src/page/home/sidebar/SidebarBottom.js @@ -39,6 +39,14 @@ const SidebarBottom = ({myPersonalDetails, isOffline, insets}) => { styles.statusIndicator, isOffline ? styles.statusIndicatorOffline : styles.statusIndicatorOnline ]; + + // On the very first sign in or after clearing storage these + // details will not be present on the first render so we'll just + // return nothing for now. + if (!myPersonalDetails) { + return null; + } + return ( From d2c502cca3938c62ecf0d574c5d3acbf38a9861b Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 28 Aug 2020 12:50:22 -0700 Subject: [PATCH 2/6] Remove the CONFIG.IS_IN_PRODUCTION --- src/lib/actions/Report.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/actions/Report.js b/src/lib/actions/Report.js index 524d20133f868..90ffc65ab0f0c 100644 --- a/src/lib/actions/Report.js +++ b/src/lib/actions/Report.js @@ -154,7 +154,7 @@ function updateReportWithNewAction(reportID, reportAction) { throw new Error('report does not exist in the store, so ignoring new comments'); } - if (CONFIG.IS_IN_PRODUCTION && !ionReportID) { + if (!ionReportID) { return fetchChatReportsByIDs([reportID]) .then(() => Ion.get(`${IONKEYS.REPORT_HISTORY}_${reportID}`)); } From ab381264bd9de7fe74de0be86feec88e909650c0 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 28 Aug 2020 12:58:40 -0700 Subject: [PATCH 3/6] fix comment --- src/lib/actions/Report.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib/actions/Report.js b/src/lib/actions/Report.js index 90ffc65ab0f0c..5e04a23a5955a 100644 --- a/src/lib/actions/Report.js +++ b/src/lib/actions/Report.js @@ -80,7 +80,6 @@ function getChatReportName(sharedReportList, personalDetails, currentUserEmail) * chat report IDs * * @param {Array} chatList - * * @return {Promise} */ function fetchChatReportsByIDs(chatList) { @@ -149,7 +148,7 @@ function updateReportWithNewAction(reportID, reportAction) { .then((ionReportID) => { // This is necessary for local development because there will be pusher events from other engineers with // different reportIDs. This means that while in development it's not possible to make new chats appear - // by leaving creating chats and leaving comments in other windows + // by creating chats then leaving comments in other windows. if (!CONFIG.IS_IN_PRODUCTION && !ionReportID) { throw new Error('report does not exist in the store, so ignoring new comments'); } From 7abe3cfa0cf066f170ed58bc75da8d88e4cc3241 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 28 Aug 2020 13:46:37 -0700 Subject: [PATCH 4/6] add comment --- src/lib/actions/Report.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/actions/Report.js b/src/lib/actions/Report.js index 5e04a23a5955a..9b890b95dcca5 100644 --- a/src/lib/actions/Report.js +++ b/src/lib/actions/Report.js @@ -153,6 +153,9 @@ function updateReportWithNewAction(reportID, reportAction) { throw new Error('report does not exist in the store, so ignoring new comments'); } + // When handling a realtime update for a chat that does not yet exist in our store we + // need to fetch it so that we can properly navigate to it. This enables us populate + // newly created chats in the LHN without requiring a full refresh of the app. if (!ionReportID) { return fetchChatReportsByIDs([reportID]) .then(() => Ion.get(`${IONKEYS.REPORT_HISTORY}_${reportID}`)); From fe7538cc3491872dc2a26f6343a79035516cdd71 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 28 Aug 2020 13:49:52 -0700 Subject: [PATCH 5/6] add another comment --- src/lib/actions/Report.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/actions/Report.js b/src/lib/actions/Report.js index 9b890b95dcca5..b6a4e188c615c 100644 --- a/src/lib/actions/Report.js +++ b/src/lib/actions/Report.js @@ -236,6 +236,7 @@ function subscribeToReportCommentEvents() { */ function fetchChatReports() { return queueRequest('Get', {returnValueList: 'chatList'}) + // The string cast below is necessary as Get rvl='chatList' may return an int .then(({chatList}) => fetchChatReportsByIDs(String(chatList).split(','))); } From 93c599e2c94645677a2aaafcef774e510afc8973 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 28 Aug 2020 13:55:00 -0700 Subject: [PATCH 6/6] add new line --- src/lib/actions/Report.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/actions/Report.js b/src/lib/actions/Report.js index b6a4e188c615c..7c7e98e3a5494 100644 --- a/src/lib/actions/Report.js +++ b/src/lib/actions/Report.js @@ -236,6 +236,7 @@ function subscribeToReportCommentEvents() { */ function fetchChatReports() { return queueRequest('Get', {returnValueList: 'chatList'}) + // The string cast below is necessary as Get rvl='chatList' may return an int .then(({chatList}) => fetchChatReportsByIDs(String(chatList).split(','))); }