From 7265063b634d582579254377b1c50c835191cb91 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Wed, 3 May 2023 11:57:34 -0600 Subject: [PATCH 01/56] Add new param for parentReportID --- src/libs/ReportUtils.js | 1 + src/libs/actions/Report.js | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index f7a9c869c0bd..cd6a984ee0a8 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1185,6 +1185,7 @@ function buildOptimisticChatReport( oldPolicyName = '', visibility = undefined, notificationPreference = CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, + parentReportAction, ) { const currentTime = DateUtils.getDBTime(); return { diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 6991ae7f316d..657e0d0db854 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -311,8 +311,9 @@ function addComment(reportID, text) { * @param {String} reportID * @param {Array} participantList The list of users that are included in a new chat, not including the user creating it * @param {Object} newReportObject The optimistic report object created when making a new chat, saved as optimistic data + * @param {String} parentReportActionID The parent report action that a thread was created from (only passed for new threads) */ -function openReport(reportID, participantList = [], newReportObject = {}) { +function openReport(reportID, participantList = [], newReportObject = {}, parentReportActionID = '0') { const optimisticReportData = { onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, @@ -354,6 +355,7 @@ function openReport(reportID, participantList = [], newReportObject = {}) { const params = { reportID, emailList: participantList ? participantList.join(',') : '', + parentReportActionID, }; // If we are creating a new report, we need to add the optimistic report data and a report action From c33c50499fe8e9006ce728aff493262a435f51cb Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Wed, 3 May 2023 11:58:06 -0600 Subject: [PATCH 02/56] Add new params for threads, and build different optimisticData --- src/libs/actions/Report.js | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 657e0d0db854..6eaffe690212 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -395,18 +395,40 @@ function openReport(reportID, participantList = [], newReportObject = {}, parent * This will find an existing chat, or create a new one if none exists, for the given user or set of users. It will then navigate to this chat. * * @param {Array} userLogins list of user logins. + * @param {String} reportID The reportID we are trying to open + * @param {Object} parentReportAction the parent comment of a thread. This will not be passed for normal chats. + * */ -function navigateToAndOpenReport(userLogins) { - const formattedUserLogins = _.map(userLogins, login => OptionsListUtils.addSMSDomainIfPhoneNumber(login).toLowerCase()); +function navigateToAndOpenReport(userLogins, reportID = '0', parentReportAction = {}) { + let chatReportID = reportID; let newChat = {}; - const chat = ReportUtils.getChatByParticipants(formattedUserLogins); - if (!chat) { - newChat = ReportUtils.buildOptimisticChatReport(formattedUserLogins); + if (!reportID) { + const formattedUserLogins = _.map(userLogins, login => OptionsListUtils.addSMSDomainIfPhoneNumber(login).toLowerCase()); + const chat = ReportUtils.getChatByParticipants(formattedUserLogins); + if (!chat) { + if (parentReportAction) { + newChat = ReportUtils.buildOptimisticChatReport( + formattedUserLogins, + lodashGet(parentReportAction, + ['message', 0, 'text']), + '', + CONST.POLICY.OWNER_EMAIL_FAKE, + CONST.POLICY.OWNER_EMAIL_FAKE, + false, + '', + undefined, + CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, + parentReportAction.reportActionID, + ); + } else { + newChat = ReportUtils.buildOptimisticChatReport(formattedUserLogins); + } + } + chatReportID = chat ? chat.reportID : newChat.reportID; } - const reportID = chat ? chat.reportID : newChat.reportID; // We want to pass newChat here because if anything is passed in that param (even an existing chat), we will try to create a chat on the server - openReport(reportID, newChat.participants, newChat); + openReport(chatReportID, newChat.participants, newChat); Navigation.navigate(ROUTES.getReportRoute(reportID)); } From 8f641d4a3c3343e2b2a07622c95568af49080ffd Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Wed, 3 May 2023 12:10:41 -0600 Subject: [PATCH 03/56] Add new method for threads and revert old method --- src/libs/actions/Report.js | 70 ++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 29 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 6eaffe690212..530b262ba8ea 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -395,43 +395,54 @@ function openReport(reportID, participantList = [], newReportObject = {}, parent * This will find an existing chat, or create a new one if none exists, for the given user or set of users. It will then navigate to this chat. * * @param {Array} userLogins list of user logins. - * @param {String} reportID The reportID we are trying to open - * @param {Object} parentReportAction the parent comment of a thread. This will not be passed for normal chats. - * */ -function navigateToAndOpenReport(userLogins, reportID = '0', parentReportAction = {}) { - let chatReportID = reportID; +function navigateToAndOpenReport(userLogins) { + const formattedUserLogins = _.map(userLogins, login => OptionsListUtils.addSMSDomainIfPhoneNumber(login).toLowerCase()); let newChat = {}; - if (!reportID) { - const formattedUserLogins = _.map(userLogins, login => OptionsListUtils.addSMSDomainIfPhoneNumber(login).toLowerCase()); - const chat = ReportUtils.getChatByParticipants(formattedUserLogins); - if (!chat) { - if (parentReportAction) { - newChat = ReportUtils.buildOptimisticChatReport( - formattedUserLogins, - lodashGet(parentReportAction, - ['message', 0, 'text']), - '', - CONST.POLICY.OWNER_EMAIL_FAKE, - CONST.POLICY.OWNER_EMAIL_FAKE, - false, - '', - undefined, - CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, - parentReportAction.reportActionID, - ); - } else { - newChat = ReportUtils.buildOptimisticChatReport(formattedUserLogins); - } - } - chatReportID = chat ? chat.reportID : newChat.reportID; + const chat = ReportUtils.getChatByParticipants(formattedUserLogins); + if (!chat) { + newChat = ReportUtils.buildOptimisticChatReport(formattedUserLogins); } + const reportID = chat ? chat.reportID : newChat.reportID; // We want to pass newChat here because if anything is passed in that param (even an existing chat), we will try to create a chat on the server - openReport(chatReportID, newChat.participants, newChat); + openReport(reportID, newChat.participants, newChat); Navigation.navigate(ROUTES.getReportRoute(reportID)); } +/** + * This will navigate to an existing thread, or create a new one if necessary + * + * @param {String} reportID The reportID we are trying to open + * @param {Array} participants list of user logins. + * @param {Object} parentReportAction the parent comment of a thread + * + */ +function navigateToAndOpenChildReport(reportID = '0', participants = [], parentReportAction = {}) { + if (reportID !== '0') { + openReport(reportID); + Navigation.navigate(ROUTES.getReportRoute(reportID)); + } else { + const formattedUserLogins = _.map(participants, login => OptionsListUtils.addSMSDomainIfPhoneNumber(login).toLowerCase()); + const newChat = ReportUtils.buildOptimisticChatReport( + formattedUserLogins, + lodashGet(parentReportAction, + ['message', 0, 'text']), + '', + CONST.POLICY.OWNER_EMAIL_FAKE, + CONST.POLICY.OWNER_EMAIL_FAKE, + false, + '', + undefined, + CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, + parentReportAction.reportActionID, + ); + + openReport(reportID, newChat.participants, newChat); + Navigation.navigate(ROUTES.getReportRoute(reportID)); + } +} + /** * Get the latest report history without marking the report as read. * @@ -1511,6 +1522,7 @@ export { openReport, openReportFromDeepLink, navigateToAndOpenReport, + navigateToAndOpenChildReport, openPaymentDetailsPage, openMoneyRequestsReportPage, updatePolicyRoomName, From 129cb0e48eb0d2e0231893138571bf38568ad2bb Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Wed, 3 May 2023 20:01:07 -0600 Subject: [PATCH 04/56] Update openReport to support threads --- src/languages/en.js | 1 + src/languages/es.js | 1 + src/libs/ReportUtils.js | 5 +- src/libs/actions/Report.js | 54 ++++++++++--------- .../PopoverReportActionContextMenu.js | 5 ++ .../ContextMenu/ReportActionContextMenu.js | 3 ++ src/pages/home/report/ReportActionItem.js | 2 + 7 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/languages/en.js b/src/languages/en.js index fbb220273cc7..565d813bbcf7 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -253,6 +253,7 @@ export default { deleteComment: 'Delete comment', deleteConfirmation: 'Are you sure you want to delete this comment?', onlyVisible: 'Only visible to', + replyInThread: 'Reply in thread', }, emojiReactions: { addReactionTooltip: 'Add reaction', diff --git a/src/languages/es.js b/src/languages/es.js index 9713c780381b..69f52f8f63c3 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -252,6 +252,7 @@ export default { deleteComment: 'Eliminar comentario', deleteConfirmation: '¿Estás seguro de que quieres eliminar este comentario?', onlyVisible: 'Visible sólo para', + replyInThread: 'Responder en el hilo', }, emojiReactions: { addReactionTooltip: 'Añadir una reacción', diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index cd6a984ee0a8..dfc6b71b6226 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1185,7 +1185,8 @@ function buildOptimisticChatReport( oldPolicyName = '', visibility = undefined, notificationPreference = CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, - parentReportAction, + parentReportActionID, + parentReportID, ) { const currentTime = DateUtils.getDBTime(); return { @@ -1202,6 +1203,8 @@ function buildOptimisticChatReport( notificationPreference, oldPolicyName, ownerEmail: ownerEmail || CONST.REPORT.OWNER_EMAIL_FAKE, + parentReportActionID, + parentReportID, participants: participantList, policyID, reportID: generateReportID(), diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 530b262ba8ea..491944ff4b8c 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -355,7 +355,7 @@ function openReport(reportID, participantList = [], newReportObject = {}, parent const params = { reportID, emailList: participantList ? participantList.join(',') : '', - parentReportActionID, + parentReportActionID: parentReportActionID === '0' ? null : parentReportActionID, }; // If we are creating a new report, we need to add the optimistic report data and a report action @@ -372,20 +372,23 @@ function openReport(reportID, participantList = [], newReportObject = {}, parent isOptimisticReport: true, }; - const optimisticCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(newReportObject.ownerEmail); - onyxData.optimisticData.push({ - onyxMethod: CONST.ONYX.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, - value: {[optimisticCreatedAction.reportActionID]: optimisticCreatedAction}, - }); - onyxData.successData.push({ - onyxMethod: CONST.ONYX.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, - value: {[optimisticCreatedAction.reportActionID]: {pendingAction: null}}, - }); + // Add a created action, unless we are creating a thread + if (parentReportActionID !== '0') { + const optimisticCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(newReportObject.ownerEmail); + onyxData.optimisticData.push({ + onyxMethod: CONST.ONYX.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, + value: {[optimisticCreatedAction.reportActionID]: optimisticCreatedAction}, + }); + onyxData.successData.push({ + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, + value: {[optimisticCreatedAction.reportActionID]: {pendingAction: null}}, + }); - // Add the createdReportActionID parameter to the API call - params.createdReportActionID = optimisticCreatedAction.reportActionID; + // Add the createdReportActionID parameter to the API call + params.createdReportActionID = optimisticCreatedAction.reportActionID; + } } API.write('OpenReport', params, onyxData); @@ -413,21 +416,23 @@ function navigateToAndOpenReport(userLogins) { /** * This will navigate to an existing thread, or create a new one if necessary * - * @param {String} reportID The reportID we are trying to open - * @param {Array} participants list of user logins. + * @param {String} childReportID The reportID we are trying to open * @param {Object} parentReportAction the parent comment of a thread + * @param {String} parentReportID The reportID of the parent * */ -function navigateToAndOpenChildReport(reportID = '0', participants = [], parentReportAction = {}) { - if (reportID !== '0') { - openReport(reportID); - Navigation.navigate(ROUTES.getReportRoute(reportID)); +function navigateToAndOpenChildReport(childReportID = '0', parentReportAction = {}, parentReportID = '0') { + if (childReportID !== '0') { + openReport(childReportID); + Navigation.navigate(ROUTES.getReportRoute(childReportID)); } else { + const participants = _.uniq([currentUserEmail, parentReportAction.actorEmail]); const formattedUserLogins = _.map(participants, login => OptionsListUtils.addSMSDomainIfPhoneNumber(login).toLowerCase()); + const name = lodashGet(parentReportAction, ['message', 0, 'text']); + debugger; const newChat = ReportUtils.buildOptimisticChatReport( formattedUserLogins, - lodashGet(parentReportAction, - ['message', 0, 'text']), + lodashGet(parentReportAction, ['message', 0, 'text']), '', CONST.POLICY.OWNER_EMAIL_FAKE, CONST.POLICY.OWNER_EMAIL_FAKE, @@ -436,10 +441,11 @@ function navigateToAndOpenChildReport(reportID = '0', participants = [], parentR undefined, CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, parentReportAction.reportActionID, + parentReportID, ); - openReport(reportID, newChat.participants, newChat); - Navigation.navigate(ROUTES.getReportRoute(reportID)); + openReport(newChat.reportID, newChat.participants, newChat); + Navigation.navigate(ROUTES.getReportRoute(newChat.reportID)); } } diff --git a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js index 4883d2f37aa7..59c054e06787 100644 --- a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js +++ b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js @@ -39,6 +39,7 @@ class PopoverReportActionContextMenu extends React.Component { }, isArchivedRoom: false, isChronosReport: false, + childReportID: '0', }; this.onPopoverShow = () => {}; this.onPopoverHide = () => {}; @@ -138,6 +139,7 @@ class PopoverReportActionContextMenu extends React.Component { onHide = () => {}, isArchivedRoom, isChronosReport, + childReportID, ) { const nativeEvent = event.nativeEvent || {}; this.contextMenuAnchor = contextMenuAnchor; @@ -168,6 +170,7 @@ class PopoverReportActionContextMenu extends React.Component { reportActionDraftMessage: draftMessage, isArchivedRoom, isChronosReport, + childReportID, }); }); } @@ -273,6 +276,7 @@ class PopoverReportActionContextMenu extends React.Component { shouldSetModalVisibilityForDeleteConfirmation: true, isArchivedRoom: false, isChronosReport: false, + childReportID: '0', }); } @@ -319,6 +323,7 @@ class PopoverReportActionContextMenu extends React.Component { draftMessage={this.state.reportActionDraftMessage} isArchivedRoom={this.state.isArchivedRoom} isChronosReport={this.state.isChronosReport} + childReportID={this.state.childReportID} anchor={this.contextMenuTargetNode} contentRef={this.contentRef} /> diff --git a/src/pages/home/report/ContextMenu/ReportActionContextMenu.js b/src/pages/home/report/ContextMenu/ReportActionContextMenu.js index df544f2e7202..42ef5498e9de 100644 --- a/src/pages/home/report/ContextMenu/ReportActionContextMenu.js +++ b/src/pages/home/report/ContextMenu/ReportActionContextMenu.js @@ -16,6 +16,7 @@ const contextMenuRef = React.createRef(); * @param {Function} [onHide=() => {}] - Run a callback when Menu is hidden * @param {Boolean} isArchivedRoom - Whether the provided report is an archived room * @param {Boolean} isChronosReport - Flag to check if the chat participant is Chronos + * @param {String} childReportID - The child report (thread) of this action */ function showContextMenu( type, @@ -29,6 +30,7 @@ function showContextMenu( onHide = () => {}, isArchivedRoom = false, isChronosReport = false, + childReportID = '', ) { if (!contextMenuRef.current) { return; @@ -45,6 +47,7 @@ function showContextMenu( onHide, isArchivedRoom, isChronosReport, + childReportID, ); } diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index c43da3092177..0be1cee6a908 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -163,6 +163,7 @@ class ReportActionItem extends Component { this.checkIfContextMenuActive, ReportUtils.isArchivedRoom(this.props.report), ReportUtils.chatIncludesChronos(this.props.report), + this.props.action.childReportID, ); } @@ -290,6 +291,7 @@ class ReportActionItem extends Component { } draftMessage={this.props.draftMessage} isChronosReport={ReportUtils.chatIncludesChronos(this.props.report)} + childReportActionID={this.props.action.childReportActionID} /> {this.props.shouldDisplayNewMarker && ( From 10a1729ecd2ca0a3897fcdf57d67e71eda04cb31 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Wed, 3 May 2023 20:01:29 -0600 Subject: [PATCH 05/56] Don't find threads when finding reports by participants --- src/libs/ReportUtils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index dfc6b71b6226..de880a899921 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1566,7 +1566,7 @@ function shouldReportBeInOptionList(report, reportIDFromRoute, isInGSDMode, curr } /** - * Attempts to find a report in onyx with the provided list of participants + * Attempts to find a report in onyx with the provided list of participants. Does not include threads * @param {Array} newParticipantList * @returns {Array|undefined} */ @@ -1574,7 +1574,7 @@ function getChatByParticipants(newParticipantList) { newParticipantList.sort(); return _.find(allReports, (report) => { // If the report has been deleted, or there are no participants (like an empty #admins room) then skip it - if (!report || !report.participants) { + if (!report || !report.participants || report.parentReportID) { return false; } From 1333574ee8a776546e3f48ba6dd5c3611f35256a Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Wed, 3 May 2023 20:01:39 -0600 Subject: [PATCH 06/56] Add the 'reply in thread' button --- .../home/report/ContextMenu/ContextMenuActions.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index b4ad16ce1bf7..6df3259958fc 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -108,6 +108,20 @@ export default [ }, getDescription: () => {}, }, + { + textTranslateKey: 'reportActionContextMenu.replyInThread', + icon: Expensicons.ChatBubble, + successTextTranslateKey: '', + successIcon: null, + shouldShow: (type, reportAction) => type === CONTEXT_MENU_TYPES.REPORT_ACTION && reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT, + onPress: (closePopover, {childReportID, reportAction, reportID}) => { + Report.navigateToAndOpenChildReport(childReportID, reportAction, reportID); + if (closePopover) { + hideContextMenu(true, ReportActionComposeFocusManager.focus); + } + }, + getDescription: () => {}, + }, { textTranslateKey: 'reportActionContextMenu.copyURLToClipboard', icon: Expensicons.Copy, From 22f561d40db3f4d31b2c06b7b8e4e6a3211c2d61 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Wed, 3 May 2023 20:15:51 -0600 Subject: [PATCH 07/56] Fix logic and correctly pass reportActionID --- src/libs/actions/Report.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 491944ff4b8c..2e5c55afd4c5 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -373,7 +373,7 @@ function openReport(reportID, participantList = [], newReportObject = {}, parent }; // Add a created action, unless we are creating a thread - if (parentReportActionID !== '0') { + if (parentReportActionID === '0') { const optimisticCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(newReportObject.ownerEmail); onyxData.optimisticData.push({ onyxMethod: CONST.ONYX.METHOD.SET, @@ -444,7 +444,7 @@ function navigateToAndOpenChildReport(childReportID = '0', parentReportAction = parentReportID, ); - openReport(newChat.reportID, newChat.participants, newChat); + openReport(newChat.reportID, newChat.participants, newChat, parentReportAction.reportActionID); Navigation.navigate(ROUTES.getReportRoute(newChat.reportID)); } } From 0aacb498f9d67962a2f9f068b36a14e58b0cef3d Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Wed, 3 May 2023 20:16:02 -0600 Subject: [PATCH 08/56] Fix reportActions type --- src/pages/home/ReportScreen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 6068e2de9cdc..e88def278a36 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -90,7 +90,7 @@ const propTypes = { const defaultProps = { isSidebarLoaded: false, - reportActions: {}, + reportActions: [], report: { hasOutstandingIOU: false, isLoadingReportActions: false, From 0c9ed140f1e0808de133dbec26fcfe26afb8154a Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Wed, 3 May 2023 20:18:51 -0600 Subject: [PATCH 09/56] Remove test vars --- src/libs/actions/Report.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 2e5c55afd4c5..5e24feeb0172 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -428,8 +428,6 @@ function navigateToAndOpenChildReport(childReportID = '0', parentReportAction = } else { const participants = _.uniq([currentUserEmail, parentReportAction.actorEmail]); const formattedUserLogins = _.map(participants, login => OptionsListUtils.addSMSDomainIfPhoneNumber(login).toLowerCase()); - const name = lodashGet(parentReportAction, ['message', 0, 'text']); - debugger; const newChat = ReportUtils.buildOptimisticChatReport( formattedUserLogins, lodashGet(parentReportAction, ['message', 0, 'text']), From 4266c410d4db0bbb285cf013e8a44207a336a996 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Sat, 6 May 2023 09:29:18 +0100 Subject: [PATCH 10/56] Hardcoded New Thread Report --- src/libs/ReportUtils.js | 16 ++++++++++++++++ src/pages/home/report/ReportActionItem.js | 11 +++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 0cb9307083fd..af39154e33d7 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -419,6 +419,19 @@ function isPolicyExpenseChatAdmin(report, policies) { return policyRole === CONST.POLICY.ROLE.ADMIN; } +/** + * Returns true if report has a parent and is therefore a Thread. + * + * @param {Object} report + * @returns {Boolean} + */ +function isThread(report) { + if (!report.parentReportID) { + return false; + } + return true; +} + /** * Get either the policyName or domainName the chat is tied to * @param {Object} report @@ -1192,6 +1205,8 @@ function buildOptimisticIOUReportAction(type, amount, currency, comment, partici * @param {String} oldPolicyName * @param {String} visibility * @param {String} notificationPreference + * @param {String} parentReportActionID + * @param {String} parentReportID * @returns {Object} */ function buildOptimisticChatReport( @@ -1892,4 +1907,5 @@ export { canRequestMoney, getWhisperDisplayNames, getWorkspaceAvatar, + isThread, }; diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index adcb538a1d86..d502d4ae9495 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -17,6 +17,8 @@ import ReportActionItemMessage from './ReportActionItemMessage'; import UnreadActionIndicator from '../../../components/UnreadActionIndicator'; import ReportActionItemMessageEdit from './ReportActionItemMessageEdit'; import ReportActionItemCreated from './ReportActionItemCreated'; +// eslint-disable-next-line import/no-cycle +import ReportActionItemParentAction from './ReportActionItemParentAction'; import compose from '../../../libs/compose'; import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions'; import ControlSelection from '../../../libs/ControlSelection'; @@ -295,6 +297,15 @@ class ReportActionItem extends Component { render() { if (this.props.action.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED) { + if (ReportUtils.isThread(this.props.report)) { + return ( + + ); + } return ; } if (this.props.action.actionName === CONST.REPORT.ACTIONS.TYPE.RENAMED) { From 1410cff23d7ad5af1dbd4aa821524c5307c42c3a Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Sat, 6 May 2023 09:30:11 +0100 Subject: [PATCH 11/56] Add empty state for threads --- .../report/ReportActionItemParentAction.js | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 src/pages/home/report/ReportActionItemParentAction.js diff --git a/src/pages/home/report/ReportActionItemParentAction.js b/src/pages/home/report/ReportActionItemParentAction.js new file mode 100644 index 000000000000..133bcdb9afed --- /dev/null +++ b/src/pages/home/report/ReportActionItemParentAction.js @@ -0,0 +1,131 @@ +import React from 'react'; +import {Pressable, View, Image, Text} from 'react-native'; +import lodashGet from 'lodash/get'; +import {withOnyx} from 'react-native-onyx'; +import PropTypes from 'prop-types'; +import ONYXKEYS from '../../../ONYXKEYS'; +import RoomHeaderAvatars from '../../../components/RoomHeaderAvatars'; +import ReportWelcomeText from '../../../components/ReportWelcomeText'; +import participantPropTypes from '../../../components/participantPropTypes'; +import * as ReportUtils from '../../../libs/ReportUtils'; +import styles from '../../../styles/styles'; +import OfflineWithFeedback from '../../../components/OfflineWithFeedback'; +import * as Report from '../../../libs/actions/Report'; +import reportPropTypes from '../../reportPropTypes'; +import EmptyStateBackgroundImage from '../../../../assets/images/empty-state_background-fade.png'; +import * as StyleUtils from '../../../styles/StyleUtils'; +import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions'; +import compose from '../../../libs/compose'; +import withLocalize from '../../../components/withLocalize'; +import ReportActionItem from './ReportActionItem'; +import reportActionPropTypes from './reportActionPropTypes'; + +const propTypes = { + /** The id of the report */ + reportID: PropTypes.string.isRequired, + + parentReportID: PropTypes.number.isRequired, + + parentReportActionID: PropTypes.number.isRequired, + + /** The report currently being looked at */ + report: reportPropTypes, + + parentReport: reportPropTypes, + + parentReportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)), + + parentReportAction: PropTypes.shape(reportActionPropTypes), + + /** Personal details of all the users */ + personalDetails: PropTypes.objectOf(participantPropTypes), + + ...windowDimensionsPropTypes, +}; +const defaultProps = { + report: {}, + personalDetails: {}, + parentReportActions: [], + parentReportAction: {}, + parentReport: {}, +}; + +const ReportActionItemParentAction = (props) => { + const icons = ReportUtils.getIcons(props.report, props.personalDetails); + console.log('RESULTING ReportActionItemParentAction PROPS: ', props); + return ( + Report.navigateToConciergeChatAndDeleteReport(props.report.reportID)} + > + + + + ReportUtils.navigateToDetailsPage(props.report)} + style={[styles.ph5, styles.pb3, styles.alignSelfStart]} + > + + + + + + This is a thread! + + + + + { (props.parentReport && props.parentReportActions && props.parentReportAction) ? + () : null + } + + + ); +}; + +ReportActionItemParentAction.defaultProps = defaultProps; +ReportActionItemParentAction.propTypes = propTypes; +ReportActionItemParentAction.displayName = 'ReportActionItemParentAction'; + +export default compose( + withWindowDimensions, + withLocalize, + withOnyx({ + report: { + key: ({reportID}) => `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + }, + parentReport: { + key: ({parentReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${parentReportID}`, + }, + parentReportActions: { + key: ({parentReportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`, + canEvict: false, + }, + parentReportAction: { + key: ({parentReportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`, + canEvict: false, + selector: (reportActions, props) => {console.log('SELECTOR PROPS', reportActions, props); return lodashGet(reportActions, '2998605018361368979', {});} + }, + personalDetails: { + key: ONYXKEYS.PERSONAL_DETAILS, + }, + }), +)(ReportActionItemParentAction); From 1146e6209b53fe1bd3bd1af999d568a7ba40657e Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Sat, 6 May 2023 11:42:39 +0100 Subject: [PATCH 12/56] Fix reportActions type, dev comments --- src/pages/home/ReportScreen.js | 2 +- .../report/ReportActionItemParentAction.js | 31 ++++++++++++------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 09359a3bc612..6d573fe567bc 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -91,7 +91,7 @@ const propTypes = { const defaultProps = { isSidebarLoaded: false, - reportActions: [], + reportActions: {}, report: { hasOutstandingIOU: false, isLoadingReportActions: false, diff --git a/src/pages/home/report/ReportActionItemParentAction.js b/src/pages/home/report/ReportActionItemParentAction.js index 133bcdb9afed..aa0aa965eaf4 100644 --- a/src/pages/home/report/ReportActionItemParentAction.js +++ b/src/pages/home/report/ReportActionItemParentAction.js @@ -35,7 +35,7 @@ const propTypes = { parentReportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)), - parentReportAction: PropTypes.shape(reportActionPropTypes), + // parentReportAction: PropTypes.shape(reportActionPropTypes), /** Personal details of all the users */ personalDetails: PropTypes.objectOf(participantPropTypes), @@ -45,8 +45,9 @@ const propTypes = { const defaultProps = { report: {}, personalDetails: {}, - parentReportActions: [], - parentReportAction: {}, + parentReportActions: {}, + + // parentReportAction: {}, parentReport: {}, }; @@ -86,15 +87,22 @@ const ReportActionItemParentAction = (props) => { - { (props.parentReport && props.parentReportActions && props.parentReportAction) ? + { console.log('>>>>', props, 'for ', props.parentReportID, ' id: ', props.parentReportActionID, props.parentReportActions)} + { (props.parentReport && props.parentReportActions && props.parentReportActionID && props.parentReportActions[`${props.parentReportActionID}`]) ? () : null + />) : ( + + + {`ReportName: ${props.report.reportName} The parent report is: ${props.parentReportID} and the action is: ${props.parentReportActionID}!`} + + + ) } @@ -119,11 +127,12 @@ export default compose( key: ({parentReportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`, canEvict: false, }, - parentReportAction: { - key: ({parentReportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`, - canEvict: false, - selector: (reportActions, props) => {console.log('SELECTOR PROPS', reportActions, props); return lodashGet(reportActions, '2998605018361368979', {});} - }, + + // parentReportAction: { + // key: ({parentReportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`, + // canEvict: false, + // selector: (reportActions, props) => {console.log('SELECTOR PROPS', reportActions, props); return lodashGet(reportActions, '2998605018361368979', {});} + // }, personalDetails: { key: ONYXKEYS.PERSONAL_DETAILS, }, From 021ee2ebd48a3f407ac91b3f4cdda7bdcb89e804 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Sat, 6 May 2023 12:17:04 +0100 Subject: [PATCH 13/56] Fix LHN name (will work when reportName data is the parent message) --- src/components/LHNOptionsList/OptionRowLHN.js | 2 +- src/libs/ReportUtils.js | 8 +++++++- src/libs/SidebarUtils.js | 1 + src/libs/actions/Report.js | 2 ++ 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHN.js b/src/components/LHNOptionsList/OptionRowLHN.js index 3acc336929de..fd48e69537ae 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.js +++ b/src/components/LHNOptionsList/OptionRowLHN.js @@ -171,7 +171,7 @@ const OptionRowLHN = (props) => { accessibilityLabel={props.translate('accessibilityHints.chatUserDisplayNames')} fullTitle={optionItem.text} displayNamesWithTooltips={optionItem.displayNamesWithTooltips} - tooltipEnabled + tooltipEnabled={!optionItem.isThread} numberOfLines={1} textStyles={displayNameStyle} shouldUseFullTitle={optionItem.isChatRoom || optionItem.isPolicyExpenseChat} diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index af39154e33d7..9c8cb5823d2b 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -438,6 +438,12 @@ function isThread(report) { * @returns {String} */ function getChatRoomSubtitle(report) { + if (isThread(report)) { + if (isPolicyExpenseChat(report)) { + return 'workspace Thread subtitle'; + } + return 'DM thread subtitle'; + } if (!isDefaultRoom(report) && !isUserCreatedPolicyRoom(report) && !isPolicyExpenseChat(report)) { return ''; } @@ -916,7 +922,7 @@ function getPolicyExpenseChatName(report) { */ function getReportName(report) { let formattedName; - if (isChatRoom(report)) { + if (isChatRoom(report) || isThread(report)) { formattedName = report.reportName; } diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 99ffdf273c05..f310f60b94b2 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -233,6 +233,7 @@ function getOptionData(reportID) { const participantPersonalDetailList = _.values(OptionsListUtils.getPersonalDetailsForLogins(report.participants, personalDetails)); const personalDetail = participantPersonalDetailList[0] || {}; + result.isThread = ReportUtils.isThread(report); result.isChatRoom = ReportUtils.isChatRoom(report); result.isArchivedRoom = ReportUtils.isArchivedRoom(report); result.isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(report); diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 619cd3e10b47..c208de3bd7db 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -454,6 +454,8 @@ function navigateToAndOpenChildReport(childReportID = '0', parentReportAction = parentReportAction.reportActionID, parentReportID, ); + // eslint-disable-next-line no-console + console.log('OPENING CHILD REPORT for ', parentReportAction, parentReportID, lodashGet(parentReportAction, ['message', 0, 'text']), newChat); openReport(newChat.reportID, newChat.participants, newChat, parentReportAction.reportActionID); Navigation.navigate(ROUTES.getReportRoute(newChat.reportID)); From fffd148e0b119728bfeea984d59693748a956cfc Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Sat, 6 May 2023 23:49:28 +0100 Subject: [PATCH 14/56] This is where we will set the LHN header to the parent message --- src/libs/SidebarUtils.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index f310f60b94b2..33fc3c6cfd35 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -322,7 +322,12 @@ function getOptionData(reportID) { } const reportName = ReportUtils.getReportName(report); - result.text = reportName; + // eslint-disable-next-line no-unused-expressions, no-undef, no-console, max-len + const parentReportAction = (ReportUtils.isThread(report) && report.parentReportActionID && report.parentReportID) ? reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}4444742227669619`]['2969097651817343818'] : {}; + const parentReportActionMessage = lodashGet(parentReportAction, ['message', 0, 'text']); + // eslint-disable-next-line no-console + console.log('rip ', parentReportAction, parentReportActionMessage, lastMessageText); + result.text = ReportUtils.isThread(report) ? parentReportActionMessage : reportName; result.subtitle = subtitle; result.participantsList = participantPersonalDetailList; From af69c87bbb4f71c2b4f6e871b3b6b0bb9677bed6 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Sun, 7 May 2023 09:16:18 +0100 Subject: [PATCH 15/56] Show header and subtitle for threads (hard coded) --- src/pages/home/HeaderView.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index e6f74953e187..d6c0fedfc9b2 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -26,6 +26,7 @@ import colors from '../../styles/colors'; import reportPropTypes from '../reportPropTypes'; import ONYXKEYS from '../../ONYXKEYS'; import ThreeDotsMenu from '../../components/ThreeDotsMenu'; +import reportActionPropTypes from './report/reportActionPropTypes'; const propTypes = { /** Toggles the navigationMenu open and closed */ @@ -45,12 +46,15 @@ const propTypes = { guideCalendarLink: PropTypes.string, }), + parentReportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)), + ...windowDimensionsPropTypes, ...withLocalizePropTypes, }; const defaultProps = { personalDetails: {}, + parentReportActions: {}, report: null, account: { guideCalendarLink: null, @@ -58,6 +62,9 @@ const defaultProps = { }; const HeaderView = (props) => { + const parentReportAction = props.parentReportActions['5067383038721755115']; + // eslint-disable-next-line no-console + console.log('parent header', props.parentReportActions, parentReportAction); const participants = lodashGet(props.report, 'participants', []); const participantPersonalDetails = OptionsListUtils.getPersonalDetailsForLogins(participants, props.personalDetails); const isMultipleParticipant = participants.length > 1; @@ -65,7 +72,7 @@ const HeaderView = (props) => { const isChatRoom = ReportUtils.isChatRoom(props.report); const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(props.report); const isTaskReport = ReportUtils.isTaskReport(props.report); - const title = ReportUtils.getReportName(props.report); + const title = ReportUtils.isThread(props.report) ? lodashGet(parentReportAction, ['message', 0, 'text'], '[Thread Title Error]') : ReportUtils.getReportName(props.report); const subtitle = ReportUtils.getChatRoomSubtitle(props.report); const isConcierge = participants.length === 1 && _.contains(participants, CONST.EMAIL.CONCIERGE); @@ -163,9 +170,9 @@ const HeaderView = (props) => { tooltipEnabled numberOfLines={1} textStyles={[styles.headerText, styles.pre]} - shouldUseFullTitle={isChatRoom || isPolicyExpenseChat} + shouldUseFullTitle={isChatRoom || isPolicyExpenseChat || ReportUtils.isThread(props.report)} /> - {(isChatRoom || isPolicyExpenseChat) && ( + {(isChatRoom || isPolicyExpenseChat || ReportUtils.isThread(props.report)) && ( account && ({guideCalendarLink: account.guideCalendarLink}), }, + parentReportActions: { + key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${lodashGet(report, 'parentReportID')}`, + canEvict: false, + }, }), )(HeaderView); From d997131dd7c5dfefdf96b588a158f378bad36eae Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Sun, 7 May 2023 19:24:26 +0100 Subject: [PATCH 16/56] icons --- src/libs/ReportUtils.js | 36 ++++++++++++++++++++++++++++++++++++ src/libs/SidebarUtils.js | 3 +++ src/pages/home/HeaderView.js | 21 +++++++++++++++------ 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 9c8cb5823d2b..67a0db360d69 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -733,6 +733,42 @@ function getIcons(report, personalDetails, defaultIcon = null) { result.source = Expensicons.DeletedRoomAvatar; return [result]; } + if (isThread(report)) { + if (isPolicyExpenseChat(report) || isExpenseReport(report)) { + const workspaceName = lodashGet(allPolicies, [ + `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, 'name', + ]); + + const policyExpenseChatAvatarSource = getWorkspaceAvatar(report); + + // Return the workspace avatar if the user is the owner of the policy expense chat + if (report.isOwnPolicyExpenseChat && !isExpenseReport(report)) { + result.source = policyExpenseChatAvatarSource; + result.type = CONST.ICON_TYPE_WORKSPACE; + result.name = workspaceName; + return [result]; + } + + const adminIcon = { + source: getAvatar(lodashGet(personalDetails, [report.ownerEmail, 'avatar']), report.ownerEmail), + name: report.ownerEmail, + type: CONST.ICON_TYPE_AVATAR, + }; + + const workspaceIcon = { + source: policyExpenseChatAvatarSource, + type: CONST.ICON_TYPE_WORKSPACE, + name: workspaceName, + }; + + // If the user is an admin, return avatar source of the other participant of the report + // (their workspace chat) and the avatar source of the workspace + return [ + adminIcon, + workspaceIcon, + ]; + } + } if (isDomainRoom(report)) { result.source = Expensicons.DomainRoomAvatar; return [result]; diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 33fc3c6cfd35..0a2f0bfeb806 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -268,6 +268,9 @@ function getOptionData(reportID) { lastMessageTextFromReport = report ? report.lastMessageText || '' : ''; } + // eslint-disable-next-line no-console + console.log('lastMessageTextFromReport: ', lastMessageTextFromReport); + // If the last actor's details are not currently saved in Onyx Collection, // then try to get that from the last report action if that action is valid // to get data from. diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index d6c0fedfc9b2..9acffb114c48 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -37,6 +37,8 @@ const propTypes = { /** The report currently being looked at */ report: reportPropTypes, + parentReport: reportPropTypes, + /** Personal details of all the users */ personalDetails: PropTypes.objectOf(participantPropTypes), @@ -55,6 +57,7 @@ const propTypes = { const defaultProps = { personalDetails: {}, parentReportActions: {}, + parentReport: null, report: null, account: { guideCalendarLink: null, @@ -63,16 +66,19 @@ const defaultProps = { const HeaderView = (props) => { const parentReportAction = props.parentReportActions['5067383038721755115']; - // eslint-disable-next-line no-console - console.log('parent header', props.parentReportActions, parentReportAction); + if (parentReportAction) { + // eslint-disable-next-line no-console + console.log('parent header', props.parentReportActions, parentReportAction); + } const participants = lodashGet(props.report, 'participants', []); const participantPersonalDetails = OptionsListUtils.getPersonalDetailsForLogins(participants, props.personalDetails); const isMultipleParticipant = participants.length > 1; const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips(participantPersonalDetails, isMultipleParticipant); + const isThread = ReportUtils.isThread(props.report); const isChatRoom = ReportUtils.isChatRoom(props.report); const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(props.report); const isTaskReport = ReportUtils.isTaskReport(props.report); - const title = ReportUtils.isThread(props.report) ? lodashGet(parentReportAction, ['message', 0, 'text'], '[Thread Title Error]') : ReportUtils.getReportName(props.report); + const title = isThread ? lodashGet(parentReportAction, ['message', 0, 'text'], '[Thread Title Error]') : ReportUtils.getReportName(props.report); const subtitle = ReportUtils.getChatRoomSubtitle(props.report); const isConcierge = participants.length === 1 && _.contains(participants, CONST.EMAIL.CONCIERGE); @@ -121,7 +127,7 @@ const HeaderView = (props) => { const avatarTooltip = isChatRoom ? undefined : _.pluck(displayNamesWithTooltips, 'tooltip'); const shouldShowSubscript = isPolicyExpenseChat && !props.report.isOwnPolicyExpenseChat && !ReportUtils.isArchivedRoom(props.report); - const icons = ReportUtils.getIcons(props.report, props.personalDetails); + const icons = ReportUtils.getIcons(isThread ? props.parentReport : props.report, props.personalDetails); const brickRoadIndicator = ReportUtils.hasReportNameError(props.report) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''; return ( @@ -170,9 +176,9 @@ const HeaderView = (props) => { tooltipEnabled numberOfLines={1} textStyles={[styles.headerText, styles.pre]} - shouldUseFullTitle={isChatRoom || isPolicyExpenseChat || ReportUtils.isThread(props.report)} + shouldUseFullTitle={isChatRoom || isPolicyExpenseChat || isThread} /> - {(isChatRoom || isPolicyExpenseChat || ReportUtils.isThread(props.report)) && ( + {(isChatRoom || isPolicyExpenseChat || isThread) && ( account && ({guideCalendarLink: account.guideCalendarLink}), }, + parentReport: { + key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT}${lodashGet(report, 'parentReportID')}`, + }, parentReportActions: { key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${lodashGet(report, 'parentReportID')}`, canEvict: false, From 49187940c5e7a32a88910c1fd68b504e1c1fc502 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Mon, 8 May 2023 13:34:56 +0100 Subject: [PATCH 17/56] icons cont --- src/components/LHNOptionsList/OptionRowLHN.js | 4 +- src/libs/ReportActionsUtils.js | 25 +++ src/libs/ReportUtils.js | 149 ++++++++++-------- src/libs/SidebarUtils.js | 11 +- src/pages/home/HeaderView.js | 10 +- .../report/ReportActionItemParentAction.js | 13 +- 6 files changed, 139 insertions(+), 73 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHN.js b/src/components/LHNOptionsList/OptionRowLHN.js index fd48e69537ae..9909461d06b3 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.js +++ b/src/components/LHNOptionsList/OptionRowLHN.js @@ -176,7 +176,7 @@ const OptionRowLHN = (props) => { textStyles={displayNameStyle} shouldUseFullTitle={optionItem.isChatRoom || optionItem.isPolicyExpenseChat} /> - {optionItem.isChatRoom && ( + {optionItem.isChatRoom && !optionItem.isThread && ( { numberOfLines={1} accessibilityLabel={props.translate('accessibilityHints.lastChatMessagePreview')} > - {optionItem.alternateText} + {(optionItem.isThread && optionItem.subtitle) ? optionItem.subtitle : optionItem.alternateText} ) : null} diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index 1158f41e685e..0242e693ad94 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -40,6 +40,29 @@ function isDeletedAction(reportAction) { return message.length === 0 || lodashGet(message, [0, 'html']) === ''; } +/** + * @param {String} parentReportID + * @param {String} parentReportActionID + * @returns {Object} + */ +function getParentReportAction(parentReportID, parentReportActionID) { + // A deleted comment has either an empty array or an object with html field with empty string as value + // eslint-disable-next-line no-console + const reportAction = lodashGet(allReportActions, [parentReportID, parentReportActionID]); + return reportAction; +} + +/** + * @param {String} reportID + * @returns {Object} + */ +function getReportActions(reportID) { + // A deleted comment has either an empty array or an object with html field with empty string as value + // eslint-disable-next-line no-console + const reportAction = lodashGet(allReportActions, [reportID]); + return reportAction; +} + /** * Sort an array of reportActions by their created timestamp first, and reportActionID second * This gives us a stable order even in the case of multiple reportActions created on the same millisecond @@ -301,4 +324,6 @@ export { getLastClosedReportAction, getLatestReportActionFromOnyxData, getLinkedTransactionID, + getParentReportAction, + getReportActions, }; diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 67a0db360d69..f1bb5287680a 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -90,6 +90,14 @@ function getChatType(report) { return report ? report.chatType : ''; } +function findMatchingValueDEVTESTING(objList, parentID) { + if (!objList) { + return {}; + } + const matchingKey = _.find(_.keys(objList), key => key.includes(`${parentID.substring(0, 8)}`)); + return matchingKey ? objList[matchingKey] : null; +} + /** * Returns the concatenated title for the PrimaryLogins of a report * @@ -439,10 +447,15 @@ function isThread(report) { */ function getChatRoomSubtitle(report) { if (isThread(report)) { - if (isPolicyExpenseChat(report)) { - return 'workspace Thread subtitle'; + const parentReport = lodashGet(allReports, [ + `${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`]); + const chatType = getChatType(report); + if (chatType) { + const workspaceName = getPolicyName(parentReport); + const roomName = (parentReport.displayName === workspaceName) ? '' : parentReport.displayName; + return roomName ? `${workspaceName} • ${roomName}` : `${workspaceName}`; } - return 'DM thread subtitle'; + return ''; } if (!isDefaultRoom(report) && !isUserCreatedPolicyRoom(report) && !isPolicyExpenseChat(report)) { return ''; @@ -705,6 +718,54 @@ function getSmallSizeAvatar(avatarURL, login) { return `${source.substring(0, lastPeriodIndex)}_128${source.substring(lastPeriodIndex)}`; } +/** + * Returns the appropriate icons for the given chat report using the stored personalDetails. + * The Avatar sources can be URLs or Icon components according to the chat type. +// * +// * @param {Object} report +// * @param {Object} personalDetails +// * @param {Object} parentReportAction +// * @returns {Array<*>} +// */ +// function getThreadIcons(report, parentReport, parentReportAction) { +// return []; + +// // console.log() +// // const parentReport = lodashGet(allReports, [ +// // `${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`, {} +// // ]); +// } + +function buildAvatarArray(participants, personalDetails) { + const participantDetails = []; + const participantsList = participants || []; + + for (let i = 0; i < participantsList.length; i++) { + const login = participantsList[i]; + const avatarSource = getAvatar(lodashGet(personalDetails, [login, 'avatar'], ''), login); + participantDetails.push([ + login, + lodashGet(personalDetails, [login, 'firstName'], ''), + avatarSource, + ]); + } + + // Sort all logins by first name (which is the second element in the array) + const sortedParticipantDetails = participantDetails.sort((a, b) => a[1] - b[1]); + + // Now that things are sorted, gather only the avatars (third element in the array) and return those + const avatars = []; + for (let i = 0; i < sortedParticipantDetails.length; i++) { + const userIcon = { + source: sortedParticipantDetails[i][2], + type: CONST.ICON_TYPE_AVATAR, + name: sortedParticipantDetails[i][0], + }; + avatars.push(userIcon); + } + return avatars; +} + /** * Returns the appropriate icons for the given chat report using the stored personalDetails. * The Avatar sources can be URLs or Icon components according to the chat type. @@ -734,40 +795,27 @@ function getIcons(report, personalDetails, defaultIcon = null) { return [result]; } if (isThread(report)) { - if (isPolicyExpenseChat(report) || isExpenseReport(report)) { - const workspaceName = lodashGet(allPolicies, [ - `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, 'name', - ]); - - const policyExpenseChatAvatarSource = getWorkspaceAvatar(report); - - // Return the workspace avatar if the user is the owner of the policy expense chat - if (report.isOwnPolicyExpenseChat && !isExpenseReport(report)) { - result.source = policyExpenseChatAvatarSource; - result.type = CONST.ICON_TYPE_WORKSPACE; - result.name = workspaceName; - return [result]; - } - - const adminIcon = { - source: getAvatar(lodashGet(personalDetails, [report.ownerEmail, 'avatar']), report.ownerEmail), - name: report.ownerEmail, - type: CONST.ICON_TYPE_AVATAR, - }; - - const workspaceIcon = { - source: policyExpenseChatAvatarSource, - type: CONST.ICON_TYPE_WORKSPACE, - name: workspaceName, - }; - - // If the user is an admin, return avatar source of the other participant of the report - // (their workspace chat) and the avatar source of the workspace - return [ - adminIcon, - workspaceIcon, - ]; + const parentReport = lodashGet(allReports, [ + `${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`, + ]); + + const parentReportActions = ReportActionsUtils.getReportActions(report.parentReportID); + const parentReportActionTEST = findMatchingValueDEVTESTING(parentReportActions, `${report.parentReportActionID}`); + + if (getChatType(parentReport)) { + result.source = getWorkspaceAvatar(parentReport); + result.type = CONST.ICON_TYPE_WORKSPACE; + result.name = getPolicyName(parentReport); + return [result]; } + // eslint-disable-next-line no-console + // console.log('>>>>', parentReport, parentReportActions); + // const avatars = buildAvatarArray(parentReport.participants, personalDetails); + const actorEmail = lodashGet(parentReportActionTEST, 'actorEmail', ''); + result.source = parentReportActionTEST ? getAvatar(lodashGet(personalDetails, [actorEmail, 'avatar']), actorEmail) : ''; + result.type = CONST.ICON_TYPE_AVATAR; + result.name = actorEmail; + return [result]; } if (isDomainRoom(report)) { result.source = Expensicons.DomainRoomAvatar; @@ -827,32 +875,7 @@ function getIcons(report, personalDetails, defaultIcon = null) { }]; } - const participantDetails = []; - const participants = report.participants || []; - - for (let i = 0; i < participants.length; i++) { - const login = participants[i]; - const avatarSource = getAvatar(lodashGet(personalDetails, [login, 'avatar'], ''), login); - participantDetails.push([ - login, - lodashGet(personalDetails, [login, 'firstName'], ''), - avatarSource, - ]); - } - - // Sort all logins by first name (which is the second element in the array) - const sortedParticipantDetails = participantDetails.sort((a, b) => a[1] - b[1]); - - // Now that things are sorted, gather only the avatars (third element in the array) and return those - const avatars = []; - for (let i = 0; i < sortedParticipantDetails.length; i++) { - const userIcon = { - source: sortedParticipantDetails[i][2], - type: CONST.ICON_TYPE_AVATAR, - name: sortedParticipantDetails[i][0], - }; - avatars.push(userIcon); - } + const avatars = buildAvatarArray(report.participants, personalDetails); return avatars; } @@ -1950,4 +1973,6 @@ export { getWhisperDisplayNames, getWorkspaceAvatar, isThread, + findMatchingValueDEVTESTING, + buildAvatarArray, }; diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 0a2f0bfeb806..32cd1e3e3733 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -261,6 +261,13 @@ function getOptionData(reportID) { // We only create tooltips for the first 10 users or so since some reports have hundreds of users, causing performance to degrade. const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips((participantPersonalDetailList || []).slice(0, 10), hasMultipleParticipants); + const parentReportAction = (ReportUtils.isThread(report) + && report.parentReportActionID + && report.parentReportID + && reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`]) + ? ReportUtils.findMatchingValueDEVTESTING(reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`], `${report.parentReportActionID}`) + : {}; + let lastMessageTextFromReport = ''; if (ReportUtils.isReportMessageAttachment({text: report.lastMessageText, html: report.lastMessageHtml})) { lastMessageTextFromReport = `[${Localize.translateLocal('common.attachment')}]`; @@ -326,7 +333,9 @@ function getOptionData(reportID) { const reportName = ReportUtils.getReportName(report); // eslint-disable-next-line no-unused-expressions, no-undef, no-console, max-len - const parentReportAction = (ReportUtils.isThread(report) && report.parentReportActionID && report.parentReportID) ? reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}4444742227669619`]['2969097651817343818'] : {}; + + // const parentReportID = '2443650236419026'; + // const parentReportActionID = '7267239632810500313'; const parentReportActionMessage = lodashGet(parentReportAction, ['message', 0, 'text']); // eslint-disable-next-line no-console console.log('rip ', parentReportAction, parentReportActionMessage, lastMessageText); diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index 9acffb114c48..e41b494360bc 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -37,6 +37,7 @@ const propTypes = { /** The report currently being looked at */ report: reportPropTypes, + // eslint-disable-next-line react/no-unused-prop-types parentReport: reportPropTypes, /** Personal details of all the users */ @@ -65,7 +66,10 @@ const defaultProps = { }; const HeaderView = (props) => { - const parentReportAction = props.parentReportActions['5067383038721755115']; + let parentReportAction = props.parentReportActions['7267239632810500313']; + parentReportAction = ReportUtils.findMatchingValueDEVTESTING(props.parentReportActions, `${props.report.parentReportActionID}`); + // eslint-disable-next-line no-console + console.log('header', parentReportAction); if (parentReportAction) { // eslint-disable-next-line no-console console.log('parent header', props.parentReportActions, parentReportAction); @@ -127,7 +131,7 @@ const HeaderView = (props) => { const avatarTooltip = isChatRoom ? undefined : _.pluck(displayNamesWithTooltips, 'tooltip'); const shouldShowSubscript = isPolicyExpenseChat && !props.report.isOwnPolicyExpenseChat && !ReportUtils.isArchivedRoom(props.report); - const icons = ReportUtils.getIcons(isThread ? props.parentReport : props.report, props.personalDetails); + const icons = ReportUtils.getIcons(isThread ? props.report : props.report, props.personalDetails); const brickRoadIndicator = ReportUtils.hasReportNameError(props.report) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''; return ( @@ -178,7 +182,7 @@ const HeaderView = (props) => { textStyles={[styles.headerText, styles.pre]} shouldUseFullTitle={isChatRoom || isPolicyExpenseChat || isThread} /> - {(isChatRoom || isPolicyExpenseChat || isThread) && ( + {((isChatRoom || isPolicyExpenseChat || isThread) && !_.isEmpty(subtitle)) && ( { const icons = ReportUtils.getIcons(props.report, props.personalDetails); - console.log('RESULTING ReportActionItemParentAction PROPS: ', props); + // const icons = ReportUtils.buildAvatarArray(parentReportAction.childOldestFourEmails || [parentReportAction.actorEmail] , props.personalDetails); + + // const parentReportActionID = '7267239632810500313'; + // let parentReportAction = props.parentReportActions['7267239632810500313']; + const parentReportAction = ReportUtils.findMatchingValueDEVTESTING(props.parentReportActions, `${props.report.parentReportActionID}`); return ( { - + This is a thread! - { console.log('>>>>', props, 'for ', props.parentReportID, ' id: ', props.parentReportActionID, props.parentReportActions)} - { (props.parentReport && props.parentReportActions && props.parentReportActionID && props.parentReportActions[`${props.parentReportActionID}`]) ? + { (parentReportAction) ? ( Date: Mon, 8 May 2023 13:59:14 +0100 Subject: [PATCH 18/56] icons cont --- src/libs/ReportUtils.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index f1bb5287680a..ff06090196ea 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -809,8 +809,17 @@ function getIcons(report, personalDetails, defaultIcon = null) { return [result]; } // eslint-disable-next-line no-console - // console.log('>>>>', parentReport, parentReportActions); - // const avatars = buildAvatarArray(parentReport.participants, personalDetails); + console.log('>>>>', parentReport, parentReportActionTEST); + + // if (lodashGet(parentReportActionTEST, 'childOldestFourEmails', '')) { + // const avatars = _.isArray(parentReportActionTEST.childOldestFourEmails) + // ? buildAvatarArray(parentReportActionTEST.childOldestFourEmails, personalDetails) + // : buildAvatarArray([parentReportActionTEST.childOldestFourEmails], personalDetails); + // return avatars; + // } + + // const avatars = buildAvatarArray(report.participants, personalDetails); + const actorEmail = lodashGet(parentReportActionTEST, 'actorEmail', ''); result.source = parentReportActionTEST ? getAvatar(lodashGet(personalDetails, [actorEmail, 'avatar']), actorEmail) : ''; result.type = CONST.ICON_TYPE_AVATAR; From 18087c72fc401c095791241204c2ce57cbdd95fb Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Mon, 8 May 2023 16:33:48 +0100 Subject: [PATCH 19/56] Update Empty State --- .../report/ReportActionItemParentAction.js | 41 +++---------------- src/styles/styles.js | 7 ++++ 2 files changed, 12 insertions(+), 36 deletions(-) diff --git a/src/pages/home/report/ReportActionItemParentAction.js b/src/pages/home/report/ReportActionItemParentAction.js index 6c230b3c89d1..77e73fe3401d 100644 --- a/src/pages/home/report/ReportActionItemParentAction.js +++ b/src/pages/home/report/ReportActionItemParentAction.js @@ -9,6 +9,7 @@ import ReportWelcomeText from '../../../components/ReportWelcomeText'; import participantPropTypes from '../../../components/participantPropTypes'; import * as ReportUtils from '../../../libs/ReportUtils'; import styles from '../../../styles/styles'; +import themeColors from '../../../styles/themes/default'; import OfflineWithFeedback from '../../../components/OfflineWithFeedback'; import * as Report from '../../../libs/actions/Report'; import reportPropTypes from '../../reportPropTypes'; @@ -52,9 +53,6 @@ const defaultProps = { }; const ReportActionItemParentAction = (props) => { - const icons = ReportUtils.getIcons(props.report, props.personalDetails); - // const icons = ReportUtils.buildAvatarArray(parentReportAction.childOldestFourEmails || [parentReportAction.actorEmail] , props.personalDetails); - // const parentReportActionID = '7267239632810500313'; // let parentReportAction = props.parentReportActions['7267239632810500313']; const parentReportAction = ReportUtils.findMatchingValueDEVTESTING(props.parentReportActions, `${props.report.parentReportActionID}`); @@ -66,31 +64,7 @@ const ReportActionItemParentAction = (props) => { onClose={() => Report.navigateToConciergeChatAndDeleteReport(props.report.reportID)} > - - - ReportUtils.navigateToDetailsPage(props.report)} - style={[styles.ph5, styles.pb3, styles.alignSelfStart]} - > - - - - - - This is a thread! - - - - + { (parentReportAction) ? ( { />) : ( - {`ReportName: ${props.report.reportName} The parent report is: ${props.parentReportID} and the action is: ${props.parentReportActionID}!`} + {`Error Displaying ReportName: ${props.report.reportName} The parent report is: ${props.parentReportID} and the action is: ${props.parentReportActionID}!`} - + ) } + ); }; @@ -130,12 +105,6 @@ export default compose( key: ({parentReportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`, canEvict: false, }, - - // parentReportAction: { - // key: ({parentReportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`, - // canEvict: false, - // selector: (reportActions, props) => {console.log('SELECTOR PROPS', reportActions, props); return lodashGet(reportActions, '2998605018361368979', {});} - // }, personalDetails: { key: ONYXKEYS.PERSONAL_DETAILS, }, diff --git a/src/styles/styles.js b/src/styles/styles.js index 7d10688d0061..df71a12957c5 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -2181,6 +2181,13 @@ const styles = { opacity: 0.5, }, + threadDividerLine: { + height: 1, + backgroundColor: themeColors.border, + flexGrow: 1, + marginHorizontal: 20, + }, + unreadIndicatorText: { color: themeColors.unreadIndicator, fontFamily: fontFamily.EXP_NEUE_BOLD, From 5f35afbdc447cea9a1a3ba9753c8f9b672d26656 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Mon, 8 May 2023 17:03:32 +0100 Subject: [PATCH 20/56] Clean up icons --- src/libs/ReportUtils.js | 86 ++++++++++++----------------------------- 1 file changed, 25 insertions(+), 61 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index ff06090196ea..127b4511c190 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -718,54 +718,6 @@ function getSmallSizeAvatar(avatarURL, login) { return `${source.substring(0, lastPeriodIndex)}_128${source.substring(lastPeriodIndex)}`; } -/** - * Returns the appropriate icons for the given chat report using the stored personalDetails. - * The Avatar sources can be URLs or Icon components according to the chat type. -// * -// * @param {Object} report -// * @param {Object} personalDetails -// * @param {Object} parentReportAction -// * @returns {Array<*>} -// */ -// function getThreadIcons(report, parentReport, parentReportAction) { -// return []; - -// // console.log() -// // const parentReport = lodashGet(allReports, [ -// // `${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`, {} -// // ]); -// } - -function buildAvatarArray(participants, personalDetails) { - const participantDetails = []; - const participantsList = participants || []; - - for (let i = 0; i < participantsList.length; i++) { - const login = participantsList[i]; - const avatarSource = getAvatar(lodashGet(personalDetails, [login, 'avatar'], ''), login); - participantDetails.push([ - login, - lodashGet(personalDetails, [login, 'firstName'], ''), - avatarSource, - ]); - } - - // Sort all logins by first name (which is the second element in the array) - const sortedParticipantDetails = participantDetails.sort((a, b) => a[1] - b[1]); - - // Now that things are sorted, gather only the avatars (third element in the array) and return those - const avatars = []; - for (let i = 0; i < sortedParticipantDetails.length; i++) { - const userIcon = { - source: sortedParticipantDetails[i][2], - type: CONST.ICON_TYPE_AVATAR, - name: sortedParticipantDetails[i][0], - }; - avatars.push(userIcon); - } - return avatars; -} - /** * Returns the appropriate icons for the given chat report using the stored personalDetails. * The Avatar sources can be URLs or Icon components according to the chat type. @@ -808,17 +760,6 @@ function getIcons(report, personalDetails, defaultIcon = null) { result.name = getPolicyName(parentReport); return [result]; } - // eslint-disable-next-line no-console - console.log('>>>>', parentReport, parentReportActionTEST); - - // if (lodashGet(parentReportActionTEST, 'childOldestFourEmails', '')) { - // const avatars = _.isArray(parentReportActionTEST.childOldestFourEmails) - // ? buildAvatarArray(parentReportActionTEST.childOldestFourEmails, personalDetails) - // : buildAvatarArray([parentReportActionTEST.childOldestFourEmails], personalDetails); - // return avatars; - // } - - // const avatars = buildAvatarArray(report.participants, personalDetails); const actorEmail = lodashGet(parentReportActionTEST, 'actorEmail', ''); result.source = parentReportActionTEST ? getAvatar(lodashGet(personalDetails, [actorEmail, 'avatar']), actorEmail) : ''; @@ -884,8 +825,32 @@ function getIcons(report, personalDetails, defaultIcon = null) { }]; } - const avatars = buildAvatarArray(report.participants, personalDetails); + const participantDetails = []; + const participantsList = report.participants || []; + + for (let i = 0; i < participantsList.length; i++) { + const login = participantsList[i]; + const avatarSource = getAvatar(lodashGet(personalDetails, [login, 'avatar'], ''), login); + participantDetails.push([ + login, + lodashGet(personalDetails, [login, 'firstName'], ''), + avatarSource, + ]); + } + + // Sort all logins by first name (which is the second element in the array) + const sortedParticipantDetails = participantDetails.sort((a, b) => a[1] - b[1]); + // Now that things are sorted, gather only the avatars (third element in the array) and return those + const avatars = []; + for (let i = 0; i < sortedParticipantDetails.length; i++) { + const userIcon = { + source: sortedParticipantDetails[i][2], + type: CONST.ICON_TYPE_AVATAR, + name: sortedParticipantDetails[i][0], + }; + avatars.push(userIcon); + } return avatars; } @@ -1983,5 +1948,4 @@ export { getWorkspaceAvatar, isThread, findMatchingValueDEVTESTING, - buildAvatarArray, }; From ec852807f9e773b3a6e4b25fe53045f1ceacfae5 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Mon, 8 May 2023 20:15:50 +0100 Subject: [PATCH 21/56] Remove comments --- src/libs/ReportActionsUtils.js | 4 ---- src/libs/ReportUtils.js | 7 ++++--- src/libs/SidebarUtils.js | 9 +-------- src/pages/home/HeaderView.js | 10 ++-------- 4 files changed, 7 insertions(+), 23 deletions(-) diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index 0242e693ad94..bf7d7c9eec14 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -46,8 +46,6 @@ function isDeletedAction(reportAction) { * @returns {Object} */ function getParentReportAction(parentReportID, parentReportActionID) { - // A deleted comment has either an empty array or an object with html field with empty string as value - // eslint-disable-next-line no-console const reportAction = lodashGet(allReportActions, [parentReportID, parentReportActionID]); return reportAction; } @@ -57,8 +55,6 @@ function getParentReportAction(parentReportID, parentReportActionID) { * @returns {Object} */ function getReportActions(reportID) { - // A deleted comment has either an empty array or an object with html field with empty string as value - // eslint-disable-next-line no-console const reportAction = lodashGet(allReportActions, [reportID]); return reportAction; } diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 47f8e008997d..ec9c1792e9ec 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -828,10 +828,10 @@ function getIcons(report, personalDetails, defaultIcon = null) { } const participantDetails = []; - const participantsList = report.participants || []; + const participants = report.participants || []; - for (let i = 0; i < participantsList.length; i++) { - const login = participantsList[i]; + for (let i = 0; i < participants.length; i++) { + const login = participants[i]; const avatarSource = getAvatar(lodashGet(personalDetails, [login, 'avatar'], ''), login); participantDetails.push([ login, @@ -853,6 +853,7 @@ function getIcons(report, personalDetails, defaultIcon = null) { }; avatars.push(userIcon); } + return avatars; } diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 32cd1e3e3733..6cc5eda7e028 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -275,9 +275,6 @@ function getOptionData(reportID) { lastMessageTextFromReport = report ? report.lastMessageText || '' : ''; } - // eslint-disable-next-line no-console - console.log('lastMessageTextFromReport: ', lastMessageTextFromReport); - // If the last actor's details are not currently saved in Onyx Collection, // then try to get that from the last report action if that action is valid // to get data from. @@ -332,13 +329,9 @@ function getOptionData(reportID) { } const reportName = ReportUtils.getReportName(report); - // eslint-disable-next-line no-unused-expressions, no-undef, no-console, max-len - // const parentReportID = '2443650236419026'; - // const parentReportActionID = '7267239632810500313'; const parentReportActionMessage = lodashGet(parentReportAction, ['message', 0, 'text']); - // eslint-disable-next-line no-console - console.log('rip ', parentReportAction, parentReportActionMessage, lastMessageText); + result.text = ReportUtils.isThread(report) ? parentReportActionMessage : reportName; result.subtitle = subtitle; result.participantsList = participantPersonalDetailList; diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index e41b494360bc..ae6148325f18 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -66,14 +66,8 @@ const defaultProps = { }; const HeaderView = (props) => { - let parentReportAction = props.parentReportActions['7267239632810500313']; - parentReportAction = ReportUtils.findMatchingValueDEVTESTING(props.parentReportActions, `${props.report.parentReportActionID}`); - // eslint-disable-next-line no-console - console.log('header', parentReportAction); - if (parentReportAction) { - // eslint-disable-next-line no-console - console.log('parent header', props.parentReportActions, parentReportAction); - } + // TO DO: Replace with subscribing to specific action rather than all. + const parentReportAction = ReportUtils.findMatchingValueDEVTESTING(props.parentReportActions, `${props.report.parentReportActionID}`); const participants = lodashGet(props.report, 'participants', []); const participantPersonalDetails = OptionsListUtils.getPersonalDetailsForLogins(participants, props.personalDetails); const isMultipleParticipant = participants.length > 1; From b938973e33e5c9e4bfe8be0b223ae30ce4b2ecf1 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Tue, 9 May 2023 08:21:00 +0100 Subject: [PATCH 22/56] Clean up --- src/pages/home/HeaderView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index ae6148325f18..a23be063c910 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -125,7 +125,7 @@ const HeaderView = (props) => { const avatarTooltip = isChatRoom ? undefined : _.pluck(displayNamesWithTooltips, 'tooltip'); const shouldShowSubscript = isPolicyExpenseChat && !props.report.isOwnPolicyExpenseChat && !ReportUtils.isArchivedRoom(props.report); - const icons = ReportUtils.getIcons(isThread ? props.report : props.report, props.personalDetails); + const icons = ReportUtils.getIcons(props.report, props.personalDetails); const brickRoadIndicator = ReportUtils.hasReportNameError(props.report) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''; return ( From 6f9e3232b292f6bc47df029d0b564fa163967508 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Tue, 9 May 2023 13:24:42 +0100 Subject: [PATCH 23/56] Clean up --- src/libs/ReportUtils.js | 22 +++---- src/libs/SidebarUtils.js | 4 +- src/pages/home/HeaderView.js | 12 +--- .../report/ReportActionItemParentAction.js | 61 ++++++------------- 4 files changed, 34 insertions(+), 65 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index ec9c1792e9ec..dcaca9a11bd0 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -90,7 +90,7 @@ function getChatType(report) { return report ? report.chatType : ''; } -function findMatchingValueDEVTESTING(objList, parentID) { +function getParentReportAction_DEV(objList, parentID) { if (!objList) { return {}; } @@ -434,7 +434,7 @@ function isPolicyExpenseChatAdmin(report, policies) { * @returns {Boolean} */ function isThread(report) { - if (!report.parentReportID) { + if (!report || !report.parentReportID || !report.parentReportActionID) { return false; } return true; @@ -447,15 +447,13 @@ function isThread(report) { */ function getChatRoomSubtitle(report) { if (isThread(report)) { - const parentReport = lodashGet(allReports, [ - `${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`]); - const chatType = getChatType(report); - if (chatType) { - const workspaceName = getPolicyName(parentReport); - const roomName = (parentReport.displayName === workspaceName) ? '' : parentReport.displayName; - return roomName ? `${workspaceName} • ${roomName}` : `${workspaceName}`; + if (!getChatType(report)) { + return ''; } - return ''; + const parentReport = lodashGet(allReports, [`${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`]); + const workspaceName = getPolicyName(parentReport); + const roomName = (parentReport.displayName === workspaceName) ? '' : parentReport.displayName; + return roomName ? `${workspaceName} • ${roomName}` : `${workspaceName}`; } if (!isDefaultRoom(report) && !isUserCreatedPolicyRoom(report) && !isPolicyExpenseChat(report)) { return ''; @@ -752,7 +750,7 @@ function getIcons(report, personalDetails, defaultIcon = null) { ]); const parentReportActions = ReportActionsUtils.getReportActions(report.parentReportID); - const parentReportActionTEST = findMatchingValueDEVTESTING(parentReportActions, `${report.parentReportActionID}`); + const parentReportActionTEST = getParentReportAction_DEV(parentReportActions, `${report.parentReportActionID}`); if (getChatType(parentReport)) { result.source = getWorkspaceAvatar(parentReport); @@ -1977,5 +1975,5 @@ export { getWhisperDisplayNames, getWorkspaceAvatar, isThread, - findMatchingValueDEVTESTING, + getParentReportAction_DEV, }; diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 6cc5eda7e028..e475d310909a 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -265,7 +265,7 @@ function getOptionData(reportID) { && report.parentReportActionID && report.parentReportID && reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`]) - ? ReportUtils.findMatchingValueDEVTESTING(reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`], `${report.parentReportActionID}`) + ? ReportUtils.getParentReportAction_DEV(reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`], `${report.parentReportActionID}`) : {}; let lastMessageTextFromReport = ''; @@ -300,7 +300,7 @@ function getOptionData(reportID) { }); } - if ((result.isChatRoom || result.isPolicyExpenseChat) && !result.isArchivedRoom) { + if ((result.isChatRoom || result.isPolicyExpenseChat || result.isThread) && !result.isArchivedRoom) { result.alternateText = lastMessageTextFromReport.length > 0 ? lastMessageText : Localize.translate(preferredLocale, 'report.noActivityYet'); } else { if (!lastMessageText) { diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index a23be063c910..e5034ad3caf4 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -37,9 +37,6 @@ const propTypes = { /** The report currently being looked at */ report: reportPropTypes, - // eslint-disable-next-line react/no-unused-prop-types - parentReport: reportPropTypes, - /** Personal details of all the users */ personalDetails: PropTypes.objectOf(participantPropTypes), @@ -58,7 +55,6 @@ const propTypes = { const defaultProps = { personalDetails: {}, parentReportActions: {}, - parentReport: null, report: null, account: { guideCalendarLink: null, @@ -67,7 +63,7 @@ const defaultProps = { const HeaderView = (props) => { // TO DO: Replace with subscribing to specific action rather than all. - const parentReportAction = ReportUtils.findMatchingValueDEVTESTING(props.parentReportActions, `${props.report.parentReportActionID}`); + const parentReportAction = ReportUtils.getParentReportAction_DEV(props.parentReportActions, `${props.report.parentReportActionID}`); const participants = lodashGet(props.report, 'participants', []); const participantPersonalDetails = OptionsListUtils.getPersonalDetailsForLogins(participants, props.personalDetails); const isMultipleParticipant = participants.length > 1; @@ -76,8 +72,7 @@ const HeaderView = (props) => { const isChatRoom = ReportUtils.isChatRoom(props.report); const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(props.report); const isTaskReport = ReportUtils.isTaskReport(props.report); - const title = isThread ? lodashGet(parentReportAction, ['message', 0, 'text'], '[Thread Title Error]') : ReportUtils.getReportName(props.report); - + const title = isThread ? lodashGet(parentReportAction, ['message', 0, 'text'], '') : ReportUtils.getReportName(props.report); const subtitle = ReportUtils.getChatRoomSubtitle(props.report); const isConcierge = participants.length === 1 && _.contains(participants, CONST.EMAIL.CONCIERGE); const isAutomatedExpensifyAccount = (participants.length === 1 && ReportUtils.hasAutomatedExpensifyEmails(participants)); @@ -234,9 +229,6 @@ export default compose( key: ONYXKEYS.ACCOUNT, selector: account => account && ({guideCalendarLink: account.guideCalendarLink}), }, - parentReport: { - key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT}${lodashGet(report, 'parentReportID')}`, - }, parentReportActions: { key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${lodashGet(report, 'parentReportID')}`, canEvict: false, diff --git a/src/pages/home/report/ReportActionItemParentAction.js b/src/pages/home/report/ReportActionItemParentAction.js index 77e73fe3401d..b9b609be89df 100644 --- a/src/pages/home/report/ReportActionItemParentAction.js +++ b/src/pages/home/report/ReportActionItemParentAction.js @@ -1,23 +1,19 @@ import React from 'react'; -import {Pressable, View, Image, Text} from 'react-native'; +import {View, Text} from 'react-native'; import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; import PropTypes from 'prop-types'; import ONYXKEYS from '../../../ONYXKEYS'; -import RoomHeaderAvatars from '../../../components/RoomHeaderAvatars'; -import ReportWelcomeText from '../../../components/ReportWelcomeText'; -import participantPropTypes from '../../../components/participantPropTypes'; import * as ReportUtils from '../../../libs/ReportUtils'; import styles from '../../../styles/styles'; -import themeColors from '../../../styles/themes/default'; import OfflineWithFeedback from '../../../components/OfflineWithFeedback'; import * as Report from '../../../libs/actions/Report'; import reportPropTypes from '../../reportPropTypes'; -import EmptyStateBackgroundImage from '../../../../assets/images/empty-state_background-fade.png'; import * as StyleUtils from '../../../styles/StyleUtils'; import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions'; import compose from '../../../libs/compose'; import withLocalize from '../../../components/withLocalize'; +// eslint-disable-next-line import/no-cycle import ReportActionItem from './ReportActionItem'; import reportActionPropTypes from './reportActionPropTypes'; @@ -32,30 +28,18 @@ const propTypes = { /** The report currently being looked at */ report: reportPropTypes, - parentReport: reportPropTypes, - + /** The actions from the parent report */ parentReportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)), - // parentReportAction: PropTypes.shape(reportActionPropTypes), - - /** Personal details of all the users */ - personalDetails: PropTypes.objectOf(participantPropTypes), - ...windowDimensionsPropTypes, }; const defaultProps = { report: {}, - personalDetails: {}, parentReportActions: {}, - - // parentReportAction: {}, - parentReport: {}, }; const ReportActionItemParentAction = (props) => { - // const parentReportActionID = '7267239632810500313'; - // let parentReportAction = props.parentReportActions['7267239632810500313']; - const parentReportAction = ReportUtils.findMatchingValueDEVTESTING(props.parentReportActions, `${props.report.parentReportActionID}`); + const parentReportAction = ReportUtils.getParentReportAction_DEV(props.parentReportActions, `${props.report.parentReportActionID}`); return ( { onClose={() => Report.navigateToConciergeChatAndDeleteReport(props.report.reportID)} > - - { (parentReportAction) ? - () : ( + + { parentReportAction + ? ( + + ) : ( - - {`Error Displaying ReportName: ${props.report.reportName} The parent report is: ${props.parentReportID} and the action is: ${props.parentReportActionID}!`} - + + {`Error Displaying ReportName: ${props.report.reportName} The parent report is: ${props.parentReportID} and the action is: ${props.parentReportActionID}!`} + - ) - } + )} @@ -98,15 +83,9 @@ export default compose( report: { key: ({reportID}) => `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, }, - parentReport: { - key: ({parentReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${parentReportID}`, - }, parentReportActions: { key: ({parentReportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`, canEvict: false, }, - personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, - }, }), )(ReportActionItemParentAction); From 9b1884a5e8d8aafded28b72da60637144dba54f3 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Tue, 9 May 2023 18:52:12 +0100 Subject: [PATCH 24/56] Only show button in DEV environment --- src/pages/home/report/ContextMenu/ContextMenuActions.js | 2 +- src/pages/home/report/ReportActionItem.js | 4 ++-- src/pages/home/report/ReportActionItemParentAction.js | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 6df3259958fc..6852b8b026d5 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -113,7 +113,7 @@ export default [ icon: Expensicons.ChatBubble, successTextTranslateKey: '', successIcon: null, - shouldShow: (type, reportAction) => type === CONTEXT_MENU_TYPES.REPORT_ACTION && reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT, + shouldShow: (type, reportAction) => Environment.isDevelopment() && type === CONTEXT_MENU_TYPES.REPORT_ACTION && reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT, onPress: (closePopover, {childReportID, reportAction, reportID}) => { Report.navigateToAndOpenChildReport(childReportID, reportAction, reportID); if (closePopover) { diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index d502d4ae9495..7e4682621c13 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -301,8 +301,8 @@ class ReportActionItem extends Component { return ( ); } diff --git a/src/pages/home/report/ReportActionItemParentAction.js b/src/pages/home/report/ReportActionItemParentAction.js index b9b609be89df..6e3b75f56b31 100644 --- a/src/pages/home/report/ReportActionItemParentAction.js +++ b/src/pages/home/report/ReportActionItemParentAction.js @@ -21,9 +21,9 @@ const propTypes = { /** The id of the report */ reportID: PropTypes.string.isRequired, - parentReportID: PropTypes.number.isRequired, + parentReportID: PropTypes.string.isRequired, - parentReportActionID: PropTypes.number.isRequired, + parentReportActionID: PropTypes.string.isRequired, /** The report currently being looked at */ report: reportPropTypes, From 91eb65f200167ee85a52c5b15f822780f1685cf3 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Wed, 10 May 2023 08:51:47 +0100 Subject: [PATCH 25/56] Clean up comments, update helper function deescriptions --- src/components/LHNOptionsList/OptionRowLHN.js | 11 +++++--- src/libs/ReportActionsUtils.js | 13 ++-------- src/libs/ReportUtils.js | 26 +++++++++++++------ src/libs/SidebarUtils.js | 2 -- 4 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHN.js b/src/components/LHNOptionsList/OptionRowLHN.js index 9909461d06b3..0563d8717008 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.js +++ b/src/components/LHNOptionsList/OptionRowLHN.js @@ -98,6 +98,9 @@ const OptionRowLHN = (props) => { const hasBrickError = optionItem.brickRoadIndicator === CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR; const shouldShowGreenDotIndicator = !hasBrickError && (optionItem.isUnreadWithMention || (optionItem.hasOutstandingIOU && !optionItem.isIOUReportOwner)); + // If the item is a thread within a workspace, we will show the subtitle as the second line instead of in a pill + const alternativeText = (optionItem.isThread && optionItem.subtitle) ? optionItem.subtitle : optionItem.alternateText; + return ( { accessibilityLabel={props.translate('accessibilityHints.chatUserDisplayNames')} fullTitle={optionItem.text} displayNamesWithTooltips={optionItem.displayNamesWithTooltips} - tooltipEnabled={!optionItem.isThread} + tooltipEnabled numberOfLines={1} textStyles={displayNameStyle} - shouldUseFullTitle={optionItem.isChatRoom || optionItem.isPolicyExpenseChat} + shouldUseFullTitle={optionItem.isChatRoom || optionItem.isPolicyExpenseChat || optionItem.isThread} /> {optionItem.isChatRoom && !optionItem.isThread && ( { /> )} - {optionItem.alternateText ? ( + {alternativeText ? ( - {(optionItem.isThread && optionItem.subtitle) ? optionItem.subtitle : optionItem.alternateText} + {alternativeText} ) : null} diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index bf7d7c9eec14..1039b083a42f 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -41,16 +41,8 @@ function isDeletedAction(reportAction) { } /** - * @param {String} parentReportID - * @param {String} parentReportActionID - * @returns {Object} - */ -function getParentReportAction(parentReportID, parentReportActionID) { - const reportAction = lodashGet(allReportActions, [parentReportID, parentReportActionID]); - return reportAction; -} - -/** + * Returns the object of reportActions + * * @param {String} reportID * @returns {Object} */ @@ -320,6 +312,5 @@ export { getLastClosedReportAction, getLatestReportActionFromOnyxData, getLinkedTransactionID, - getParentReportAction, getReportActions, }; diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index dcaca9a11bd0..a9e165ed72c4 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -90,12 +90,20 @@ function getChatType(report) { return report ? report.chatType : ''; } -function getParentReportAction_DEV(objList, parentID) { - if (!objList) { +/** + * Returns the report action with key parentReportID. + * This function is to be replaced by a HOC. + * + * @param {Object} parentReportActions + * @param {string} parentReportID + * @returns {Object} + */ +function getParentReportAction_DEV(parentReportActions, parentReportID) { + if (!parentReportActions) { return {}; } - const matchingKey = _.find(_.keys(objList), key => key.includes(`${parentID.substring(0, 8)}`)); - return matchingKey ? objList[matchingKey] : null; + const matchingKey = _.find(_.keys(parentReportActions), key => _.isEqual(key, parentReportID)); + return matchingKey ? parentReportActions[matchingKey] : null; } /** @@ -450,6 +458,8 @@ function getChatRoomSubtitle(report) { if (!getChatType(report)) { return ''; } + + // If thread is not from a DM or group chat, the subtitle will follow the pattern 'Workspace Name • #roomName' const parentReport = lodashGet(allReports, [`${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`]); const workspaceName = getPolicyName(parentReport); const roomName = (parentReport.displayName === workspaceName) ? '' : parentReport.displayName; @@ -750,7 +760,7 @@ function getIcons(report, personalDetails, defaultIcon = null) { ]); const parentReportActions = ReportActionsUtils.getReportActions(report.parentReportID); - const parentReportActionTEST = getParentReportAction_DEV(parentReportActions, `${report.parentReportActionID}`); + const parentReportAction = getParentReportAction_DEV(parentReportActions, `${report.parentReportActionID}`); if (getChatType(parentReport)) { result.source = getWorkspaceAvatar(parentReport); @@ -759,8 +769,8 @@ function getIcons(report, personalDetails, defaultIcon = null) { return [result]; } - const actorEmail = lodashGet(parentReportActionTEST, 'actorEmail', ''); - result.source = parentReportActionTEST ? getAvatar(lodashGet(personalDetails, [actorEmail, 'avatar']), actorEmail) : ''; + const actorEmail = lodashGet(parentReportAction, 'actorEmail', ''); + result.source = getAvatar(lodashGet(personalDetails, [actorEmail, 'avatar']), actorEmail); result.type = CONST.ICON_TYPE_AVATAR; result.name = actorEmail; return [result]; @@ -1674,7 +1684,7 @@ function getChatByParticipants(newParticipantList) { newParticipantList.sort(); return _.find(allReports, (report) => { // If the report has been deleted, or there are no participants (like an empty #admins room) then skip it - if (!report || !report.participants || report.parentReportID) { + if (!report || !report.participants || isThread(report)) { return false; } diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index e475d310909a..a6408efd56da 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -262,8 +262,6 @@ function getOptionData(reportID) { const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips((participantPersonalDetailList || []).slice(0, 10), hasMultipleParticipants); const parentReportAction = (ReportUtils.isThread(report) - && report.parentReportActionID - && report.parentReportID && reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`]) ? ReportUtils.getParentReportAction_DEV(reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`], `${report.parentReportActionID}`) : {}; From 2092286da4482ab3ff2a8937b4845b5e2990e8a0 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Wed, 10 May 2023 08:57:38 +0100 Subject: [PATCH 26/56] clean up ReportActionItemParentAction props --- src/pages/home/report/ReportActionItem.js | 6 +----- .../home/report/ReportActionItemParentAction.js | 17 ++++------------- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 7e4682621c13..d7e7e12a0f66 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -299,11 +299,7 @@ class ReportActionItem extends Component { if (this.props.action.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED) { if (ReportUtils.isThread(this.props.report)) { return ( - + ); } return ; diff --git a/src/pages/home/report/ReportActionItemParentAction.js b/src/pages/home/report/ReportActionItemParentAction.js index 6e3b75f56b31..f4d9c9594555 100644 --- a/src/pages/home/report/ReportActionItemParentAction.js +++ b/src/pages/home/report/ReportActionItemParentAction.js @@ -1,5 +1,5 @@ import React from 'react'; -import {View, Text} from 'react-native'; +import {View} from 'react-native'; import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; import PropTypes from 'prop-types'; @@ -21,10 +21,6 @@ const propTypes = { /** The id of the report */ reportID: PropTypes.string.isRequired, - parentReportID: PropTypes.string.isRequired, - - parentReportActionID: PropTypes.string.isRequired, - /** The report currently being looked at */ report: reportPropTypes, @@ -39,7 +35,8 @@ const defaultProps = { }; const ReportActionItemParentAction = (props) => { - const parentReportAction = ReportUtils.getParentReportAction_DEV(props.parentReportActions, `${props.report.parentReportActionID}`); + // Will update in subsequent PR to use HOC to subscribe to action + const parentReportAction = ReportUtils.getParentReportAction_DEV(props.parentReportActions, props.report.parentReportActionID); return ( { { parentReportAction - ? ( + && ( { shouldDisplayNewMarker={false} index={0} /> - ) : ( - - - {`Error Displaying ReportName: ${props.report.reportName} The parent report is: ${props.parentReportID} and the action is: ${props.parentReportActionID}!`} - - )} From 23d0703b96f511730f7c31b1c35cb8cd5c92f67e Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Wed, 10 May 2023 08:58:51 +0100 Subject: [PATCH 27/56] Remove console statement --- src/libs/actions/Report.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index c208de3bd7db..619cd3e10b47 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -454,8 +454,6 @@ function navigateToAndOpenChildReport(childReportID = '0', parentReportAction = parentReportAction.reportActionID, parentReportID, ); - // eslint-disable-next-line no-console - console.log('OPENING CHILD REPORT for ', parentReportAction, parentReportID, lodashGet(parentReportAction, ['message', 0, 'text']), newChat); openReport(newChat.reportID, newChat.participants, newChat, parentReportAction.reportActionID); Navigation.navigate(ROUTES.getReportRoute(newChat.reportID)); From 6bbca5f8d12f1d7bc9257ee40131630be4620941 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Wed, 10 May 2023 09:06:57 +0100 Subject: [PATCH 28/56] supply parentReportID to ReportActionItemParentAction --- src/pages/home/report/ReportActionItem.js | 2 +- src/pages/home/report/ReportActionItemParentAction.js | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index d7e7e12a0f66..b93d19cd65c7 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -299,7 +299,7 @@ class ReportActionItem extends Component { if (this.props.action.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED) { if (ReportUtils.isThread(this.props.report)) { return ( - + ); } return ; diff --git a/src/pages/home/report/ReportActionItemParentAction.js b/src/pages/home/report/ReportActionItemParentAction.js index f4d9c9594555..268b557cebec 100644 --- a/src/pages/home/report/ReportActionItemParentAction.js +++ b/src/pages/home/report/ReportActionItemParentAction.js @@ -21,6 +21,10 @@ const propTypes = { /** The id of the report */ reportID: PropTypes.string.isRequired, + /** The id of the parent report */ + // eslint-disable-next-line react/no-unused-prop-types + parentReportID: PropTypes.string.isRequired, + /** The report currently being looked at */ report: reportPropTypes, From cd3b78fe2be03a0a5cd288fffeca1e6434099ce9 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Wed, 10 May 2023 09:28:38 +0100 Subject: [PATCH 29/56] Fix opening child report for already created thread --- src/pages/home/report/ContextMenu/ContextMenuActions.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 6852b8b026d5..b0204b09943d 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -114,8 +114,8 @@ export default [ successTextTranslateKey: '', successIcon: null, shouldShow: (type, reportAction) => Environment.isDevelopment() && type === CONTEXT_MENU_TYPES.REPORT_ACTION && reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT, - onPress: (closePopover, {childReportID, reportAction, reportID}) => { - Report.navigateToAndOpenChildReport(childReportID, reportAction, reportID); + onPress: (closePopover, {reportAction, reportID}) => { + Report.navigateToAndOpenChildReport(lodashGet(reportAction, 'childReportID', 0), reportAction, reportID); if (closePopover) { hideContextMenu(true, ReportActionComposeFocusManager.focus); } From 567dac63467e0752377aedf8db51a4ee6c5e79f4 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Wed, 10 May 2023 09:38:50 +0100 Subject: [PATCH 30/56] default childReportID to string --- src/pages/home/report/ContextMenu/ContextMenuActions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 9bb94953c58b..81c7757fbae2 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -111,7 +111,7 @@ export default [ successIcon: null, shouldShow: (type, reportAction) => Environment.isDevelopment() && type === CONTEXT_MENU_TYPES.REPORT_ACTION && reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT, onPress: (closePopover, {reportAction, reportID}) => { - Report.navigateToAndOpenChildReport(lodashGet(reportAction, 'childReportID', 0), reportAction, reportID); + Report.navigateToAndOpenChildReport(lodashGet(reportAction, 'childReportID', '0'), reportAction, reportID); if (closePopover) { hideContextMenu(true, ReportActionComposeFocusManager.focus); } From 719967095e86583fbe1539bd5c9e3281e3930853 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Wed, 10 May 2023 10:33:49 +0100 Subject: [PATCH 31/56] Prevent deleting thread parents for now. --- src/libs/ReportUtils.js | 14 ++++++++++++++ .../home/report/ContextMenu/ContextMenuActions.js | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 6514d980ec1d..08876a1f3295 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -446,6 +446,19 @@ function isThread(report) { return true; } +/** + * Returns true if reportAction has a child. + * + * @param {Object} reportAction + * @returns {Boolean} + */ +function isThreadParent(reportAction) { + if (!reportAction || !reportAction.childReportID || reportAction.childReportID === '0') { + return false; + } + return true; +} + /** * Get either the policyName or domainName the chat is tied to * @param {Object} report @@ -1954,5 +1967,6 @@ export { getWhisperDisplayNames, getWorkspaceAvatar, isThread, + isThreadParent, getParentReportAction_DEV, }; diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 81c7757fbae2..614e1b14a8e1 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -240,7 +240,8 @@ export default [ textTranslateKey: 'reportActionContextMenu.deleteComment', icon: Expensicons.Trashcan, shouldShow: (type, reportAction, isArchivedRoom, betas, menuTarget, isChronosReport) => - type === CONTEXT_MENU_TYPES.REPORT_ACTION && ReportUtils.canDeleteReportAction(reportAction) && !isArchivedRoom && !isChronosReport, + // Until deleting parent threads is supported in FE, we will prevent the user from deleting a thread parent + type === CONTEXT_MENU_TYPES.REPORT_ACTION && ReportUtils.canDeleteReportAction(reportAction) && !isArchivedRoom && !isChronosReport && !ReportUtils.isThreadParent(reportAction), onPress: (closePopover, {reportID, reportAction}) => { if (closePopover) { // Hide popover, then call showDeleteConfirmModal From 214bc12948726029d730684b350cf4bb2c27c4b4 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Wed, 10 May 2023 11:29:53 +0100 Subject: [PATCH 32/56] spacing --- src/libs/SidebarUtils.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 9dcfe84f966c..9c923e3a0a47 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -258,10 +258,10 @@ function getOptionData(reportID) { // We only create tooltips for the first 10 users or so since some reports have hundreds of users, causing performance to degrade. const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips((participantPersonalDetailList || []).slice(0, 10), hasMultipleParticipants); - const parentReportAction = (ReportUtils.isThread(report) - && reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`]) - ? ReportUtils.getParentReportAction_DEV(reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`], `${report.parentReportActionID}`) - : {}; + const parentReportAction = + ReportUtils.isThread(report) && reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`] + ? ReportUtils.getParentReportAction_DEV(reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`], `${report.parentReportActionID}`) + : {}; let lastMessageTextFromReport = ''; if (ReportUtils.isReportMessageAttachment({text: report.lastMessageText, html: report.lastMessageHtml})) { From 7a48a56c5d6bb1cb05263945594b299bc65d163b Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Wed, 10 May 2023 18:29:11 +0100 Subject: [PATCH 33/56] prettier --- src/components/LHNOptionsList/OptionRowLHN.js | 2 +- src/libs/OptionsListUtils.js | 2 +- src/libs/ReportUtils.js | 8 +++---- src/libs/SidebarUtils.js | 4 +++- src/libs/actions/Report.js | 2 +- src/pages/home/HeaderView.js | 2 +- .../PopoverReportActionContextMenu.js | 15 +------------ .../ContextMenu/ReportActionContextMenu.js | 15 +------------ src/pages/home/report/ReportActionItem.js | 5 ++++- .../report/ReportActionItemParentAction.js | 21 +++++++++---------- 10 files changed, 26 insertions(+), 50 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHN.js b/src/components/LHNOptionsList/OptionRowLHN.js index 62fa95795d61..843735079606 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.js +++ b/src/components/LHNOptionsList/OptionRowLHN.js @@ -82,7 +82,7 @@ const OptionRowLHN = (props) => { const shouldShowGreenDotIndicator = !hasBrickError && (optionItem.isUnreadWithMention || (optionItem.hasOutstandingIOU && !optionItem.isIOUReportOwner)); // If the item is a thread within a workspace, we will show the subtitle as the second line instead of in a pill - const alternativeText = (optionItem.isThread && optionItem.subtitle) ? optionItem.subtitle : optionItem.alternateText; + const alternativeText = optionItem.isThread && optionItem.subtitle ? optionItem.subtitle : optionItem.alternateText; return ( !personalDetails[key].login); + return !_.isEmpty(personalDetails) && !_.some(_.keys(personalDetails), (key) => !personalDetails[key].login); } /** diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 04a9ddb33f0b..c3d2499e5ff5 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -102,7 +102,7 @@ function getParentReportAction_DEV(parentReportActions, parentReportID) { if (!parentReportActions) { return {}; } - const matchingKey = _.find(_.keys(parentReportActions), key => _.isEqual(key, parentReportID)); + const matchingKey = _.find(_.keys(parentReportActions), (key) => _.isEqual(key, parentReportID)); return matchingKey ? parentReportActions[matchingKey] : null; } @@ -473,7 +473,7 @@ function getChatRoomSubtitle(report) { // If thread is not from a DM or group chat, the subtitle will follow the pattern 'Workspace Name • #roomName' const parentReport = lodashGet(allReports, [`${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`]); const workspaceName = getPolicyName(parentReport); - const roomName = (parentReport.displayName === workspaceName) ? '' : parentReport.displayName; + const roomName = isChatRoom(parentReport) ? parentReport.displayName : ''; return roomName ? `${workspaceName} • ${roomName}` : `${workspaceName}`; } if (!isDefaultRoom(report) && !isUserCreatedPolicyRoom(report) && !isPolicyExpenseChat(report)) { @@ -763,9 +763,7 @@ function getIcons(report, personalDetails, defaultIcon = null) { return [result]; } if (isThread(report)) { - const parentReport = lodashGet(allReports, [ - `${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`, - ]); + const parentReport = lodashGet(allReports, [`${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`]); const parentReportActions = ReportActionsUtils.getReportActions(report.parentReportID); const parentReportAction = getParentReportAction_DEV(parentReportActions, `${report.parentReportActionID}`); diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 9c923e3a0a47..cc3b7682ece8 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -333,7 +333,9 @@ function getOptionData(reportID) { const reportName = ReportUtils.getReportName(report); - const parentReportActionMessage = lodashGet(parentReportAction, ['message', 0, 'text']); + const parentReportActionMessage = lodashGet(parentReportAction, ['message', 0, 'text'], ''); + // eslint-disable-next-line no-console + console.log({result, parentReportActionMessage}); result.text = ReportUtils.isThread(report) ? parentReportActionMessage : reportName; result.subtitle = subtitle; diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 52108affa6a9..ea3a77561d62 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -442,7 +442,7 @@ function navigateToAndOpenChildReport(childReportID = '0', parentReportAction = Navigation.navigate(ROUTES.getReportRoute(childReportID)); } else { const participants = _.uniq([currentUserEmail, parentReportAction.actorEmail]); - const formattedUserLogins = _.map(participants, login => OptionsListUtils.addSMSDomainIfPhoneNumber(login).toLowerCase()); + const formattedUserLogins = _.map(participants, (login) => OptionsListUtils.addSMSDomainIfPhoneNumber(login).toLowerCase()); const newChat = ReportUtils.buildOptimisticChatReport( formattedUserLogins, lodashGet(parentReportAction, ['message', 0, 'text']), diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index 2a417f0c1413..6398e1b25e33 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -170,7 +170,7 @@ const HeaderView = (props) => { textStyles={[styles.headerText, styles.pre]} shouldUseFullTitle={isChatRoom || isPolicyExpenseChat || isThread} /> - {((isChatRoom || isPolicyExpenseChat || isThread) && !_.isEmpty(subtitle)) && ( + {(isChatRoom || isPolicyExpenseChat || isThread) && !_.isEmpty(subtitle) && ( {}, - onHide = () => {}, - isArchivedRoom, - isChronosReport, - childReportID, - ) { + showContextMenu(type, event, selection, contextMenuAnchor, reportID, reportAction, draftMessage, onShow = () => {}, onHide = () => {}, isArchivedRoom, isChronosReport, childReportID) { const nativeEvent = event.nativeEvent || {}; this.contextMenuAnchor = contextMenuAnchor; this.contextMenuTargetNode = nativeEvent.target; diff --git a/src/pages/home/report/ContextMenu/ReportActionContextMenu.js b/src/pages/home/report/ContextMenu/ReportActionContextMenu.js index baca1e553348..3358c2db6eea 100644 --- a/src/pages/home/report/ContextMenu/ReportActionContextMenu.js +++ b/src/pages/home/report/ContextMenu/ReportActionContextMenu.js @@ -35,20 +35,7 @@ function showContextMenu( if (!contextMenuRef.current) { return; } - contextMenuRef.current.showContextMenu( - type, - event, - selection, - contextMenuAnchor, - reportID, - reportAction, - draftMessage, - onShow, - onHide, - isArchivedRoom, - isChronosReport, - childReportID, - ); + contextMenuRef.current.showContextMenu(type, event, selection, contextMenuAnchor, reportID, reportAction, draftMessage, onShow, onHide, isArchivedRoom, isChronosReport, childReportID); } /** diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index f14c9b689e5c..a5f18e3fac4f 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -284,7 +284,10 @@ class ReportActionItem extends Component { if (this.props.action.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED) { if (ReportUtils.isThread(this.props.report)) { return ( - + ); } return ; diff --git a/src/pages/home/report/ReportActionItemParentAction.js b/src/pages/home/report/ReportActionItemParentAction.js index 268b557cebec..53fa29fc9239 100644 --- a/src/pages/home/report/ReportActionItemParentAction.js +++ b/src/pages/home/report/ReportActionItemParentAction.js @@ -50,17 +50,16 @@ const ReportActionItemParentAction = (props) => { > - { parentReportAction - && ( - - )} + {parentReportAction && ( + + )} From b5013f7733d9f615fd2eed2232eabca1a440e6e7 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Wed, 10 May 2023 18:35:08 +0100 Subject: [PATCH 34/56] Remove threads from search for users --- src/libs/ReportUtils.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index c3d2499e5ff5..668ba5d8c9cf 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1644,7 +1644,14 @@ function shouldReportBeInOptionList(report, reportIDFromRoute, isInGSDMode, curr // Exclude reports that have no data because there wouldn't be anything to show in the option item. // This can happen if data is currently loading from the server or a report is in various stages of being created. // This can also happen for anyone accessing a public room or archived room for which they don't have access to the underlying policy. - if (!report || !report.reportID || !report.participants || (_.isEmpty(report.participants) && !isPublicRoom(report) && !isArchivedRoom(report)) || isIOUReport(report)) { + if ( + !report || + !report.reportID || + !report.participants || + (_.isEmpty(report.participants) && !isPublicRoom(report) && !isArchivedRoom(report)) || + isIOUReport(report) || + isThread(report) + ) { return false; } From cd90b124c8dbed56e17ab4f627367d3a57c0b326 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Wed, 10 May 2023 19:25:35 +0100 Subject: [PATCH 35/56] Fix threads UI in search bar --- src/languages/en.js | 3 +++ src/languages/es.js | 3 +++ src/libs/OptionsListUtils.js | 12 ++++++++++++ src/libs/ReportUtils.js | 9 +-------- src/libs/SidebarUtils.js | 18 +++++++++--------- 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/languages/en.js b/src/languages/en.js index 946466024f15..5cfacf5d2b96 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -1296,4 +1296,7 @@ export default { chatUserDisplayNames: 'Chat user display names', scrollToNewestMessages: 'Scroll to newest messages', }, + threads: { + deletedMessage: '[Deleted Message]', + }, }; diff --git a/src/languages/es.js b/src/languages/es.js index ffba91d41a49..af3b8f7baefe 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -1761,4 +1761,7 @@ export default { chatUserDisplayNames: 'Nombres de los usuarios del chat', scrollToNewestMessages: 'Desplázate a los mensajes más recientes', }, + threads: { + deletedMessage: '[Mensaje Eliminado]', + }, }; diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 9839482efcae..3de0ca34b4a9 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -72,12 +72,14 @@ Onyx.connect({ }); const lastReportActions = {}; +const allReportActions = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT_ACTIONS, callback: (actions, key) => { if (!key || !actions) { return; } + allReportActions[key] = actions; const reportID = CollectionUtils.extractCollectionItemID(key); lastReportActions[reportID] = _.last(_.toArray(actions)); }, @@ -403,6 +405,7 @@ function createOption(logins, personalDetails, report, reportActions = {}, {show result.isDefaultRoom = ReportUtils.isDefaultRoom(report); result.isArchivedRoom = ReportUtils.isArchivedRoom(report); result.isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(report); + result.isThread = ReportUtils.isThread(report); result.shouldShowSubscript = result.isPolicyExpenseChat && !report.isOwnPolicyExpenseChat && !result.isArchivedRoom; result.allReportErrors = getAllReportErrors(report, reportActions); result.brickRoadIndicator = !_.isEmpty(result.allReportErrors) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''; @@ -464,6 +467,15 @@ function createOption(logins, personalDetails, report, reportActions = {}, {show } result.text = reportName; + + if (result.isThread) { + const parentReportAction = + ReportUtils.isThread(report) && allReportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`] + ? ReportUtils.getParentReportAction_DEV(allReportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`], `${report.parentReportActionID}`) + : {}; + const parentReportActionMessage = lodashGet(parentReportAction, ['message', 0, 'text']); + result.text = parentReportActionMessage || Localize.translateLocal('threads.deletedMessage'); + } result.searchText = getSearchText(report, reportName, personalDetailList, result.isChatRoom || result.isPolicyExpenseChat); result.icons = ReportUtils.getIcons(report, personalDetails, ReportUtils.getAvatar(personalDetail.avatar, personalDetail.login)); result.subtitle = subtitle; diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 668ba5d8c9cf..c3d2499e5ff5 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1644,14 +1644,7 @@ function shouldReportBeInOptionList(report, reportIDFromRoute, isInGSDMode, curr // Exclude reports that have no data because there wouldn't be anything to show in the option item. // This can happen if data is currently loading from the server or a report is in various stages of being created. // This can also happen for anyone accessing a public room or archived room for which they don't have access to the underlying policy. - if ( - !report || - !report.reportID || - !report.participants || - (_.isEmpty(report.participants) && !isPublicRoom(report) && !isArchivedRoom(report)) || - isIOUReport(report) || - isThread(report) - ) { + if (!report || !report.reportID || !report.participants || (_.isEmpty(report.participants) && !isPublicRoom(report) && !isArchivedRoom(report)) || isIOUReport(report)) { return false; } diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index cc3b7682ece8..5df3a9c35718 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -258,11 +258,6 @@ function getOptionData(reportID) { // We only create tooltips for the first 10 users or so since some reports have hundreds of users, causing performance to degrade. const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips((participantPersonalDetailList || []).slice(0, 10), hasMultipleParticipants); - const parentReportAction = - ReportUtils.isThread(report) && reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`] - ? ReportUtils.getParentReportAction_DEV(reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`], `${report.parentReportActionID}`) - : {}; - let lastMessageTextFromReport = ''; if (ReportUtils.isReportMessageAttachment({text: report.lastMessageText, html: report.lastMessageHtml})) { lastMessageTextFromReport = `[${Localize.translateLocal('common.attachment')}]`; @@ -333,11 +328,16 @@ function getOptionData(reportID) { const reportName = ReportUtils.getReportName(report); - const parentReportActionMessage = lodashGet(parentReportAction, ['message', 0, 'text'], ''); - // eslint-disable-next-line no-console - console.log({result, parentReportActionMessage}); + result.text = reportName; + if (result.isThread) { + const parentReportAction = + ReportUtils.isThread(report) && reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`] + ? ReportUtils.getParentReportAction_DEV(reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`], `${report.parentReportActionID}`) + : {}; + const parentReportActionMessage = lodashGet(parentReportAction, ['message', 0, 'text']); + result.text = parentReportActionMessage || Localize.translateLocal('threads.deletedMessage'); + } - result.text = ReportUtils.isThread(report) ? parentReportActionMessage : reportName; result.subtitle = subtitle; result.participantsList = participantPersonalDetailList; From 2ef1e035f8bf8adff77e1c61cf5d00748c440d5f Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Thu, 11 May 2023 09:16:47 +0100 Subject: [PATCH 36/56] Refactor getParentReportAction, update language key --- src/languages/en.js | 2 +- src/languages/es.js | 2 +- src/libs/OptionsListUtils.js | 9 ------ src/libs/ReportActionsUtils.js | 14 +++++---- src/libs/ReportUtils.js | 30 +++++-------------- src/libs/SidebarUtils.js | 9 ------ src/pages/home/HeaderView.js | 4 +-- .../report/ReportActionItemParentAction.js | 7 +++-- 8 files changed, 24 insertions(+), 53 deletions(-) diff --git a/src/languages/en.js b/src/languages/en.js index 5cfacf5d2b96..cbf0a19e075c 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -1296,7 +1296,7 @@ export default { chatUserDisplayNames: 'Chat user display names', scrollToNewestMessages: 'Scroll to newest messages', }, - threads: { + parentReportAction: { deletedMessage: '[Deleted Message]', }, }; diff --git a/src/languages/es.js b/src/languages/es.js index af3b8f7baefe..4090228aca77 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -1761,7 +1761,7 @@ export default { chatUserDisplayNames: 'Nombres de los usuarios del chat', scrollToNewestMessages: 'Desplázate a los mensajes más recientes', }, - threads: { + parentReportAction: { deletedMessage: '[Mensaje Eliminado]', }, }; diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 3de0ca34b4a9..3a92482fa780 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -467,15 +467,6 @@ function createOption(logins, personalDetails, report, reportActions = {}, {show } result.text = reportName; - - if (result.isThread) { - const parentReportAction = - ReportUtils.isThread(report) && allReportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`] - ? ReportUtils.getParentReportAction_DEV(allReportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`], `${report.parentReportActionID}`) - : {}; - const parentReportActionMessage = lodashGet(parentReportAction, ['message', 0, 'text']); - result.text = parentReportActionMessage || Localize.translateLocal('threads.deletedMessage'); - } result.searchText = getSearchText(report, reportName, personalDetailList, result.isChatRoom || result.isPolicyExpenseChat); result.icons = ReportUtils.getIcons(report, personalDetails, ReportUtils.getAvatar(personalDetail.avatar, personalDetail.login)); result.subtitle = subtitle; diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index 51dffec9745d..99a70451880d 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -41,14 +41,16 @@ function isDeletedAction(reportAction) { } /** - * Returns the object of reportActions + * Returns the parentReportAction if the given report is a thread. * - * @param {String} reportID + * @param {Object} report * @returns {Object} */ -function getReportActions(reportID) { - const reportAction = lodashGet(allReportActions, [reportID]); - return reportAction; +function getParentReportAction(report) { + if (!report || !report.parentReportID || !report.parentReportActionID) { + return {}; + } + return lodashGet(allReportActions, [report.parentReportID, report.parentReportActionID], {}); } /** @@ -309,5 +311,5 @@ export { getLastClosedReportAction, getLatestReportActionFromOnyxData, getLinkedTransactionID, - getReportActions, + getParentReportAction, }; diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index c3d2499e5ff5..d76497a9f932 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -90,22 +90,6 @@ function getChatType(report) { return report ? report.chatType : ''; } -/** - * Returns the report action with key parentReportID. - * This function is to be replaced by a HOC. - * - * @param {Object} parentReportActions - * @param {string} parentReportID - * @returns {Object} - */ -function getParentReportAction_DEV(parentReportActions, parentReportID) { - if (!parentReportActions) { - return {}; - } - const matchingKey = _.find(_.keys(parentReportActions), (key) => _.isEqual(key, parentReportID)); - return matchingKey ? parentReportActions[matchingKey] : null; -} - /** * Returns the concatenated title for the PrimaryLogins of a report * @@ -453,7 +437,7 @@ function isThread(report) { * @returns {Boolean} */ function isThreadParent(reportAction) { - if (!reportAction || !reportAction.childReportID || reportAction.childReportID === '0') { + if (!reportAction || !reportAction.childReportID || reportAction.childReportID === 0) { return false; } return true; @@ -764,9 +748,7 @@ function getIcons(report, personalDetails, defaultIcon = null) { } if (isThread(report)) { const parentReport = lodashGet(allReports, [`${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`]); - - const parentReportActions = ReportActionsUtils.getReportActions(report.parentReportID); - const parentReportAction = getParentReportAction_DEV(parentReportActions, `${report.parentReportActionID}`); + const parentReportAction = ReportActionsUtils.getParentReportAction(report); if (getChatType(parentReport)) { result.source = getWorkspaceAvatar(parentReport); @@ -963,7 +945,12 @@ function getPolicyExpenseChatName(report) { */ function getReportName(report) { let formattedName; - if (isChatRoom(report) || isThread(report)) { + if (isThread(report)) { + const parentReportAction = ReportActionsUtils.getParentReportAction(report); + const parentReportActionMessage = lodashGet(parentReportAction, ['message', 0, 'text']); + return parentReportActionMessage || Localize.translateLocal('parentReportAction.deletedMessage'); + } + if (isChatRoom(report)) { formattedName = report.reportName; } @@ -2005,5 +1992,4 @@ export { getWorkspaceAvatar, isThread, isThreadParent, - getParentReportAction_DEV, }; diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 5df3a9c35718..1c2ff4e43e6c 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -329,15 +329,6 @@ function getOptionData(reportID) { const reportName = ReportUtils.getReportName(report); result.text = reportName; - if (result.isThread) { - const parentReportAction = - ReportUtils.isThread(report) && reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`] - ? ReportUtils.getParentReportAction_DEV(reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`], `${report.parentReportActionID}`) - : {}; - const parentReportActionMessage = lodashGet(parentReportAction, ['message', 0, 'text']); - result.text = parentReportActionMessage || Localize.translateLocal('threads.deletedMessage'); - } - result.subtitle = subtitle; result.participantsList = participantPersonalDetailList; diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index 6398e1b25e33..5f070eb30649 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -62,8 +62,8 @@ const defaultProps = { }; const HeaderView = (props) => { - // TO DO: Replace with subscribing to specific action rather than all. - const parentReportAction = ReportUtils.getParentReportAction_DEV(props.parentReportActions, `${props.report.parentReportActionID}`); + // TO DO: Replace with HOC https://github.com/Expensify/App/issues/18769. + const parentReportAction = props.parentReportActions[`${props.report.parentReportActionID}`]; const participants = lodashGet(props.report, 'participants', []); const participantPersonalDetails = OptionsListUtils.getPersonalDetailsForLogins(participants, props.personalDetails); const isMultipleParticipant = participants.length > 1; diff --git a/src/pages/home/report/ReportActionItemParentAction.js b/src/pages/home/report/ReportActionItemParentAction.js index 53fa29fc9239..4baa9e080b20 100644 --- a/src/pages/home/report/ReportActionItemParentAction.js +++ b/src/pages/home/report/ReportActionItemParentAction.js @@ -4,7 +4,6 @@ import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; import PropTypes from 'prop-types'; import ONYXKEYS from '../../../ONYXKEYS'; -import * as ReportUtils from '../../../libs/ReportUtils'; import styles from '../../../styles/styles'; import OfflineWithFeedback from '../../../components/OfflineWithFeedback'; import * as Report from '../../../libs/actions/Report'; @@ -25,6 +24,8 @@ const propTypes = { // eslint-disable-next-line react/no-unused-prop-types parentReportID: PropTypes.string.isRequired, + /** ONYX PROPS */ + /** The report currently being looked at */ report: reportPropTypes, @@ -39,8 +40,8 @@ const defaultProps = { }; const ReportActionItemParentAction = (props) => { - // Will update in subsequent PR to use HOC to subscribe to action - const parentReportAction = ReportUtils.getParentReportAction_DEV(props.parentReportActions, props.report.parentReportActionID); + // TO DO: Replace with HOC https://github.com/Expensify/App/issues/18769. + const parentReportAction = props.parentReportActions[`${props.report.parentReportActionID}`]; return ( Date: Thu, 11 May 2023 09:36:27 +0100 Subject: [PATCH 37/56] Remove unnecessary lodashGet, clean code --- src/libs/ReportUtils.js | 17 ++++++++--------- src/libs/actions/Report.js | 2 +- src/pages/home/HeaderView.js | 3 ++- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index d76497a9f932..f1371e969f3a 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -424,10 +424,10 @@ function isPolicyExpenseChatAdmin(report, policies) { * @returns {Boolean} */ function isThread(report) { - if (!report || !report.parentReportID || !report.parentReportActionID) { - return false; + if (report && report.parentReportID && report.parentReportActionID) { + return true; } - return true; + return false; } /** @@ -437,10 +437,10 @@ function isThread(report) { * @returns {Boolean} */ function isThreadParent(reportAction) { - if (!reportAction || !reportAction.childReportID || reportAction.childReportID === 0) { - return false; + if (reportAction && reportAction.childReportID && reportAction.childReportID !== 0) { + return true; } - return true; + return false; } /** @@ -455,7 +455,7 @@ function getChatRoomSubtitle(report) { } // If thread is not from a DM or group chat, the subtitle will follow the pattern 'Workspace Name • #roomName' - const parentReport = lodashGet(allReports, [`${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`]); + const parentReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`]; const workspaceName = getPolicyName(parentReport); const roomName = isChatRoom(parentReport) ? parentReport.displayName : ''; return roomName ? `${workspaceName} • ${roomName}` : `${workspaceName}`; @@ -757,9 +757,8 @@ function getIcons(report, personalDetails, defaultIcon = null) { return [result]; } - const actorEmail = lodashGet(parentReportAction, 'actorEmail', ''); + const actorEmail = parentReportAction.actorEmail; result.source = getAvatar(lodashGet(personalDetails, [actorEmail, 'avatar']), actorEmail); - result.type = CONST.ICON_TYPE_AVATAR; result.name = actorEmail; return [result]; } diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index ea3a77561d62..6e8e5e0f962b 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -370,7 +370,7 @@ function openReport(reportID, participantList = [], newReportObject = {}, parent const params = { reportID, emailList: participantList ? participantList.join(',') : '', - parentReportActionID: parentReportActionID === '0' ? null : parentReportActionID, + parentReportActionID, }; // If we are creating a new report, we need to add the optimistic report data and a report action diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index 5f070eb30649..a27e15ae455b 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -46,6 +46,7 @@ const propTypes = { guideCalendarLink: PropTypes.string, }), + /** The report actions from the parent report */ parentReportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)), ...windowDimensionsPropTypes, @@ -232,7 +233,7 @@ export default compose( selector: (account) => account && {guideCalendarLink: account.guideCalendarLink}, }, parentReportActions: { - key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${lodashGet(report, 'parentReportID')}`, + key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`, canEvict: false, }, }), From d05b4a54609ea0d50f4c91d908d200644337edfd Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Thu, 11 May 2023 09:42:37 +0100 Subject: [PATCH 38/56] Use getReportName for title --- src/pages/home/HeaderView.js | 6 +++--- src/pages/home/report/ReportActionItemParentAction.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index a27e15ae455b..f1936b907856 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -47,6 +47,8 @@ const propTypes = { }), /** The report actions from the parent report */ + // TO DO: Replace with HOC https://github.com/Expensify/App/issues/18769. + // eslint-disable-next-line react/no-unused-prop-types parentReportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)), ...windowDimensionsPropTypes, @@ -63,8 +65,6 @@ const defaultProps = { }; const HeaderView = (props) => { - // TO DO: Replace with HOC https://github.com/Expensify/App/issues/18769. - const parentReportAction = props.parentReportActions[`${props.report.parentReportActionID}`]; const participants = lodashGet(props.report, 'participants', []); const participantPersonalDetails = OptionsListUtils.getPersonalDetailsForLogins(participants, props.personalDetails); const isMultipleParticipant = participants.length > 1; @@ -73,7 +73,7 @@ const HeaderView = (props) => { const isChatRoom = ReportUtils.isChatRoom(props.report); const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(props.report); const isTaskReport = ReportUtils.isTaskReport(props.report); - const title = isThread ? lodashGet(parentReportAction, ['message', 0, 'text'], '') : ReportUtils.getReportName(props.report); + const title = ReportUtils.getReportName(props.report); const subtitle = ReportUtils.getChatRoomSubtitle(props.report); const isConcierge = participants.length === 1 && _.contains(participants, CONST.EMAIL.CONCIERGE); const isAutomatedExpensifyAccount = participants.length === 1 && ReportUtils.hasAutomatedExpensifyEmails(participants); diff --git a/src/pages/home/report/ReportActionItemParentAction.js b/src/pages/home/report/ReportActionItemParentAction.js index 4baa9e080b20..5af9d05c2a29 100644 --- a/src/pages/home/report/ReportActionItemParentAction.js +++ b/src/pages/home/report/ReportActionItemParentAction.js @@ -30,6 +30,7 @@ const propTypes = { report: reportPropTypes, /** The actions from the parent report */ + // TO DO: Replace with HOC https://github.com/Expensify/App/issues/18769. parentReportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)), ...windowDimensionsPropTypes, @@ -40,7 +41,6 @@ const defaultProps = { }; const ReportActionItemParentAction = (props) => { - // TO DO: Replace with HOC https://github.com/Expensify/App/issues/18769. const parentReportAction = props.parentReportActions[`${props.report.parentReportActionID}`]; return ( Date: Thu, 11 May 2023 09:58:33 +0100 Subject: [PATCH 39/56] Refactor to fix import/no-cycle --- .../home/report/ContextMenu/ContextMenuActions.js | 2 +- .../home/report/ContextMenu/ReportActionContextMenu.js | 2 +- src/pages/home/report/ReportActionItem.js | 10 ---------- src/pages/home/report/ReportActionItemParentAction.js | 1 - src/pages/home/report/ReportActionsList.js | 9 ++++++++- 5 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 614e1b14a8e1..90069b3208b3 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -241,7 +241,7 @@ export default [ icon: Expensicons.Trashcan, shouldShow: (type, reportAction, isArchivedRoom, betas, menuTarget, isChronosReport) => // Until deleting parent threads is supported in FE, we will prevent the user from deleting a thread parent - type === CONTEXT_MENU_TYPES.REPORT_ACTION && ReportUtils.canDeleteReportAction(reportAction) && !isArchivedRoom && !isChronosReport && !ReportUtils.isThreadParent(reportAction), + type === CONTEXT_MENU_TYPES.REPORT_ACTION && ReportUtils.canDeleteReportAction(reportAction) && !isArchivedRoom && !isChronosReport, onPress: (closePopover, {reportID, reportAction}) => { if (closePopover) { // Hide popover, then call showDeleteConfirmModal diff --git a/src/pages/home/report/ContextMenu/ReportActionContextMenu.js b/src/pages/home/report/ContextMenu/ReportActionContextMenu.js index 3358c2db6eea..d3d0ce226794 100644 --- a/src/pages/home/report/ContextMenu/ReportActionContextMenu.js +++ b/src/pages/home/report/ContextMenu/ReportActionContextMenu.js @@ -30,7 +30,7 @@ function showContextMenu( onHide = () => {}, isArchivedRoom = false, isChronosReport = false, - childReportID = '', + childReportID = '0', ) { if (!contextMenuRef.current) { return; diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index a5f18e3fac4f..45f9a0cf09c7 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -17,8 +17,6 @@ import ReportActionItemMessage from './ReportActionItemMessage'; import UnreadActionIndicator from '../../../components/UnreadActionIndicator'; import ReportActionItemMessageEdit from './ReportActionItemMessageEdit'; import ReportActionItemCreated from './ReportActionItemCreated'; -// eslint-disable-next-line import/no-cycle -import ReportActionItemParentAction from './ReportActionItemParentAction'; import compose from '../../../libs/compose'; import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions'; import ControlSelection from '../../../libs/ControlSelection'; @@ -282,14 +280,6 @@ class ReportActionItem extends Component { render() { if (this.props.action.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED) { - if (ReportUtils.isThread(this.props.report)) { - return ( - - ); - } return ; } if (this.props.action.actionName === CONST.REPORT.ACTIONS.TYPE.RENAMED) { diff --git a/src/pages/home/report/ReportActionItemParentAction.js b/src/pages/home/report/ReportActionItemParentAction.js index 5af9d05c2a29..0714265a7899 100644 --- a/src/pages/home/report/ReportActionItemParentAction.js +++ b/src/pages/home/report/ReportActionItemParentAction.js @@ -12,7 +12,6 @@ import * as StyleUtils from '../../../styles/StyleUtils'; import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions'; import compose from '../../../libs/compose'; import withLocalize from '../../../components/withLocalize'; -// eslint-disable-next-line import/no-cycle import ReportActionItem from './ReportActionItem'; import reportActionPropTypes from './reportActionPropTypes'; diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index ce8fa004b471..dad2d29e5c5d 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -11,6 +11,7 @@ import * as ReportUtils from '../../../libs/ReportUtils'; import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions'; import {withNetwork, withPersonalDetails} from '../../../components/OnyxProvider'; import ReportActionItem from './ReportActionItem'; +import ReportActionItemParentAction from './ReportActionItemParentAction'; import ReportActionsSkeletonView from '../../../components/ReportActionsSkeletonView'; import variables from '../../../styles/variables'; import participantPropTypes from '../../../components/participantPropTypes'; @@ -113,7 +114,13 @@ const ReportActionsList = (props) => { ({item: reportAction, index}) => { // When the new indicator should not be displayed we explicitly set it to null const shouldDisplayNewMarker = reportAction.reportActionID === newMarkerReportActionID; - return ( + const shouldDisplayParentAction = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED && ReportUtils.isThread(report); + return shouldDisplayParentAction ? ( + + ) : ( Date: Thu, 11 May 2023 13:22:31 +0100 Subject: [PATCH 40/56] Show deleted parentActions --- src/libs/ReportActionsUtils.js | 5 +++-- src/libs/ReportUtils.js | 2 +- src/pages/home/report/ReportActionItemFragment.js | 4 ++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index e915a1265659..88e75a9a376a 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -219,10 +219,11 @@ function shouldReportActionBeVisible(reportAction, key) { return false; } - // All other actions are displayed except deleted, non-pending actions + // All other actions are displayed except thread parents, deleted, or non-pending actions const isDeleted = isDeletedAction(reportAction); const isPending = !_.isEmpty(reportAction.pendingAction); - return !isDeleted || isPending; + const isDeletedParent = lodashGet(reportAction, ['message', 0, 'isDeletedParentAction'], false); + return !isDeleted || isPending || isDeletedParent; } /** diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 5d9bb99ec4c9..5ef270593828 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -759,7 +759,7 @@ function getIcons(report, personalDetails, defaultIcon = null) { return [result]; } - const actorEmail = parentReportAction.actorEmail; + const actorEmail = lodashGet(parentReportAction, 'actorEmail', ''); result.source = getAvatar(lodashGet(personalDetails, [actorEmail, 'avatar']), actorEmail); result.name = actorEmail; return [result]; diff --git a/src/pages/home/report/ReportActionItemFragment.js b/src/pages/home/report/ReportActionItemFragment.js index 35c0f52a5aa6..390a1f6e15ad 100644 --- a/src/pages/home/report/ReportActionItemFragment.js +++ b/src/pages/home/report/ReportActionItemFragment.js @@ -96,6 +96,10 @@ const ReportActionItemFragment = (props) => { } const {html, text} = props.fragment; + if (props.fragment.isDeletedParentAction) { + return ${props.translate('parentReportAction.deletedMessage')}`} />; + } + // If the only difference between fragment.text and fragment.html is
tags // we render it as text, not as html. // This is done to render emojis with line breaks between them as text. From 0752bd4ddcc1921bcdd7488d40393f55ef8efb10 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Thu, 11 May 2023 19:01:54 +0100 Subject: [PATCH 41/56] Remove childReportID --- src/components/LHNOptionsList/OptionRowLHN.js | 4 +++- src/libs/ReportActionsUtils.js | 4 ++-- .../report/ContextMenu/PopoverReportActionContextMenu.js | 6 +----- src/pages/home/report/ReportActionItem.js | 1 - 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHN.js b/src/components/LHNOptionsList/OptionRowLHN.js index 0d2f7654f6a1..8d063ea4a172 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.js +++ b/src/components/LHNOptionsList/OptionRowLHN.js @@ -150,7 +150,9 @@ const OptionRowLHN = (props) => { tooltipEnabled numberOfLines={1} textStyles={displayNameStyle} - shouldUseFullTitle={optionItem.isChatRoom || optionItem.isPolicyExpenseChat || optionItem.isTaskReport || optionItem.isThread || optionItem.isMoneyRequestReport} + shouldUseFullTitle={ + optionItem.isChatRoom || optionItem.isPolicyExpenseChat || optionItem.isTaskReport || optionItem.isThread || optionItem.isMoneyRequestReport + } /> {optionItem.isChatRoom && !optionItem.isThread && ( {}; this.onPopoverHide = () => {}; @@ -128,7 +127,7 @@ class PopoverReportActionContextMenu extends React.Component { * @param {Boolean} isChronosReport - Flag to check if the chat participant is Chronos * @param {String} childReportID - ReportAction childReportID */ - showContextMenu(type, event, selection, contextMenuAnchor, reportID, reportAction, draftMessage, onShow = () => {}, onHide = () => {}, isArchivedRoom, isChronosReport, childReportID) { + showContextMenu(type, event, selection, contextMenuAnchor, reportID, reportAction, draftMessage, onShow = () => {}, onHide = () => {}, isArchivedRoom, isChronosReport) { const nativeEvent = event.nativeEvent || {}; this.contextMenuAnchor = contextMenuAnchor; this.contextMenuTargetNode = nativeEvent.target; @@ -158,7 +157,6 @@ class PopoverReportActionContextMenu extends React.Component { reportActionDraftMessage: draftMessage, isArchivedRoom, isChronosReport, - childReportID, }); }); } @@ -264,7 +262,6 @@ class PopoverReportActionContextMenu extends React.Component { shouldSetModalVisibilityForDeleteConfirmation: true, isArchivedRoom: false, isChronosReport: false, - childReportID: '0', }); } @@ -311,7 +308,6 @@ class PopoverReportActionContextMenu extends React.Component { draftMessage={this.state.reportActionDraftMessage} isArchivedRoom={this.state.isArchivedRoom} isChronosReport={this.state.isChronosReport} - childReportID={this.state.childReportID} anchor={this.contextMenuTargetNode} contentRef={this.contentRef} /> diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index d9a069ccecd5..0090396e61cf 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -371,7 +371,6 @@ class ReportActionItem extends Component { isVisible={hovered && !this.props.draftMessage && !hasErrors} draftMessage={this.props.draftMessage} isChronosReport={ReportUtils.chatIncludesChronos(this.props.report)} - childReportActionID={this.props.action.childReportActionID} />
)} From 88e0ca523bbc75dc8f13569cb13a0e0849167cf9 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Thu, 11 May 2023 21:51:13 +0100 Subject: [PATCH 42/56] fix workspace icon bug --- src/libs/ReportUtils.js | 5 +++++ src/pages/home/HeaderView.js | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 225850248825..97559aad3267 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -752,6 +752,11 @@ function getIcons(report, personalDetails, defaultIcon = null) { const parentReport = lodashGet(allReports, [`${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`]); const parentReportAction = ReportActionsUtils.getParentReportAction(report); + if (!parentReport) { + result.source = Expensicons.ActiveRoomAvatar; + return [result]; + } + if (getChatType(parentReport)) { result.source = getWorkspaceAvatar(parentReport); result.type = CONST.ICON_TYPE_WORKSPACE; diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index 6250fbc81c34..bb4099235b3a 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -75,7 +75,7 @@ const HeaderView = (props) => { const isChatRoom = ReportUtils.isChatRoom(props.report); const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(props.report); const isTaskReport = ReportUtils.isTaskReport(props.report); - const reportHeaderData = isTaskReport && !_.isEmpty(props.parentReport) ? props.parentReport : props.report; + const reportHeaderData = isTaskReport && !_.isEmpty(props.parentReport) && !isThread ? props.parentReport : props.report; const title = ReportUtils.getReportName(reportHeaderData); const subtitle = ReportUtils.getChatRoomSubtitle(reportHeaderData); const isConcierge = participants.length === 1 && _.contains(participants, CONST.EMAIL.CONCIERGE); From d89ac1cfaed6ea90b66bf80fadfd8b7f2f056fee Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Thu, 11 May 2023 22:23:45 +0100 Subject: [PATCH 43/56] Missed one line to fix icon --- src/libs/ReportUtils.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 97559aad3267..68191c72f57e 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -457,9 +457,8 @@ function getChatRoomSubtitle(report) { } // If thread is not from a DM or group chat, the subtitle will follow the pattern 'Workspace Name • #roomName' - const parentReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`]; - const workspaceName = getPolicyName(parentReport); - const roomName = isChatRoom(parentReport) ? parentReport.displayName : ''; + const workspaceName = getPolicyName(report); + const roomName = isChatRoom(report) ? lodashGet(report, 'displayName') : ''; return roomName ? `${workspaceName} • ${roomName}` : `${workspaceName}`; } if (!isDefaultRoom(report) && !isUserCreatedPolicyRoom(report) && !isPolicyExpenseChat(report)) { From 9a815ca85c485400c88c99a5a8bbcb19fd5c63d0 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 11 May 2023 16:24:34 -0600 Subject: [PATCH 44/56] Add beta check to threads --- src/pages/home/report/ContextMenu/ContextMenuActions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index e641281f4f19..e97497a7ea02 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -110,7 +110,7 @@ export default [ icon: Expensicons.ChatBubble, successTextTranslateKey: '', successIcon: null, - shouldShow: (type, reportAction) => Environment.isDevelopment() && type === CONTEXT_MENU_TYPES.REPORT_ACTION && reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT, + shouldShow: (type, reportAction, betas) => Permissions.canUseThreads(betas) && type === CONTEXT_MENU_TYPES.REPORT_ACTION && reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT, onPress: (closePopover, {reportAction, reportID}) => { Report.navigateToAndOpenChildReport(lodashGet(reportAction, 'childReportID', '0'), reportAction, reportID); if (closePopover) { From 6effecb8f18f3eca3c63a3c11ec16c5a7db341d7 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 11 May 2023 16:50:56 -0600 Subject: [PATCH 45/56] Style --- src/pages/home/report/ContextMenu/ContextMenuActions.js | 3 ++- src/pages/signin/SignInPageLayout/Footer.js | 7 +++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index e97497a7ea02..8ae14d5c6e5d 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -110,7 +110,8 @@ export default [ icon: Expensicons.ChatBubble, successTextTranslateKey: '', successIcon: null, - shouldShow: (type, reportAction, betas) => Permissions.canUseThreads(betas) && type === CONTEXT_MENU_TYPES.REPORT_ACTION && reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT, + shouldShow: (type, reportAction, betas) => + Permissions.canUseThreads(betas) && type === CONTEXT_MENU_TYPES.REPORT_ACTION && reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT, onPress: (closePopover, {reportAction, reportID}) => { Report.navigateToAndOpenChildReport(lodashGet(reportAction, 'childReportID', '0'), reportAction, reportID); if (closePopover) { diff --git a/src/pages/signin/SignInPageLayout/Footer.js b/src/pages/signin/SignInPageLayout/Footer.js index cb8acb5d1e1f..b17e0faee990 100644 --- a/src/pages/signin/SignInPageLayout/Footer.js +++ b/src/pages/signin/SignInPageLayout/Footer.js @@ -25,8 +25,7 @@ const propTypes = { scrollPageToTop: PropTypes.func.isRequired, }; -const defaultProps = { -}; +const defaultProps = {}; const navigateHome = (scrollPageToTop) => { scrollPageToTop(); @@ -35,7 +34,7 @@ const navigateHome = (scrollPageToTop) => { Session.clearSignInData(); }; -const columns = ({scrollPageToTop}) => ([ +const columns = ({scrollPageToTop}) => [ { translationPath: 'footer.features', rows: [ @@ -148,7 +147,7 @@ const columns = ({scrollPageToTop}) => ([ }, ], }, -]); +]; const Footer = (props) => { const isVertical = props.isSmallScreenWidth; From 3a659c1417521b6104051993a49603604a478860 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 11 May 2023 18:24:56 -0600 Subject: [PATCH 46/56] Don't show thread button for the parent comment --- .../ContextMenu/BaseReportActionContextMenu.js | 13 +++++++++++-- .../home/report/ContextMenu/ContextMenuActions.js | 10 ++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js index 62b85f7f7d07..2ebba34e704b 100755 --- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js +++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js @@ -50,8 +50,17 @@ class BaseReportActionContextMenu extends React.Component { } render() { - const shouldShowFilter = (contextAction) => - contextAction.shouldShow(this.props.type, this.props.reportAction, this.props.isArchivedRoom, this.props.betas, this.props.anchor, this.props.isChronosReport); + const shouldShowFilter = (contextAction) => { + return contextAction.shouldShow( + this.props.type, + this.props.reportAction, + this.props.isArchivedRoom, + this.props.betas, + this.props.anchor, + this.props.isChronosReport, + this.props.reportID, + ); + }; return ( (this.props.isVisible || this.state.shouldKeepOpen) && ( diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 8ae14d5c6e5d..0b49a32155eb 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -110,8 +110,14 @@ export default [ icon: Expensicons.ChatBubble, successTextTranslateKey: '', successIcon: null, - shouldShow: (type, reportAction, betas) => - Permissions.canUseThreads(betas) && type === CONTEXT_MENU_TYPES.REPORT_ACTION && reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT, + shouldShow: (type, reportAction, isArchivedRoom, betas, anchor, isChronosReport, reportID) => { + return ( + Permissions.canUseThreads(betas) && + type === CONTEXT_MENU_TYPES.REPORT_ACTION && + reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT && + reportAction.childReportID.toString() !== reportID + ); + }, onPress: (closePopover, {reportAction, reportID}) => { Report.navigateToAndOpenChildReport(lodashGet(reportAction, 'childReportID', '0'), reportAction, reportID); if (closePopover) { From 81a3d59ca9b073b5fad8c913935201e8cb429ed2 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 11 May 2023 18:49:35 -0600 Subject: [PATCH 47/56] If the report is a task, pass the parent --- src/pages/home/HeaderView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index bb4099235b3a..79b386165b4b 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -75,7 +75,7 @@ const HeaderView = (props) => { const isChatRoom = ReportUtils.isChatRoom(props.report); const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(props.report); const isTaskReport = ReportUtils.isTaskReport(props.report); - const reportHeaderData = isTaskReport && !_.isEmpty(props.parentReport) && !isThread ? props.parentReport : props.report; + const reportHeaderData = isTaskReport && !_.isEmpty(props.parentReport) && (!isThread || ReportUtils.isTaskReport(props.report)) ? props.parentReport : props.report; const title = ReportUtils.getReportName(reportHeaderData); const subtitle = ReportUtils.getChatRoomSubtitle(reportHeaderData); const isConcierge = participants.length === 1 && _.contains(participants, CONST.EMAIL.CONCIERGE); From a3f17f2453557635fb4c5045a528d696d5d4427c Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 11 May 2023 19:05:49 -0600 Subject: [PATCH 48/56] Check for undefined because not all actions have a childReportID --- src/pages/home/report/ContextMenu/ContextMenuActions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 0b49a32155eb..f76de7dd727c 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -115,7 +115,7 @@ export default [ Permissions.canUseThreads(betas) && type === CONTEXT_MENU_TYPES.REPORT_ACTION && reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT && - reportAction.childReportID.toString() !== reportID + (_.isUndefined(reportAction.childReportID) || reportAction.childReportID.toString() !== reportID) ); }, onPress: (closePopover, {reportAction, reportID}) => { From 074e5b213f50c08bf9556c9537f9fd0dd4ee2810 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 11 May 2023 20:27:12 -0600 Subject: [PATCH 49/56] Style --- .../home/report/ContextMenu/BaseReportActionContextMenu.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js index 2ebba34e704b..8467cc574370 100755 --- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js +++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js @@ -50,8 +50,8 @@ class BaseReportActionContextMenu extends React.Component { } render() { - const shouldShowFilter = (contextAction) => { - return contextAction.shouldShow( + const shouldShowFilter = (contextAction) => + contextAction.shouldShow( this.props.type, this.props.reportAction, this.props.isArchivedRoom, @@ -60,7 +60,6 @@ class BaseReportActionContextMenu extends React.Component { this.props.isChronosReport, this.props.reportID, ); - }; return ( (this.props.isVisible || this.state.shouldKeepOpen) && ( From e59c0206b72f2b02df9562dac436a1cc34623d56 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Fri, 12 May 2023 11:09:25 +0100 Subject: [PATCH 50/56] Remove newlines from headerText --- src/libs/ReportUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 68191c72f57e..773385e82c99 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -965,7 +965,7 @@ function getReportName(report) { let formattedName; if (isThread(report)) { const parentReportAction = ReportActionsUtils.getParentReportAction(report); - const parentReportActionMessage = lodashGet(parentReportAction, ['message', 0, 'text']); + const parentReportActionMessage = lodashGet(parentReportAction, ['message', 0, 'text'], '').replace(/(\r\n|\n|\r)/gm, ' '); return parentReportActionMessage || Localize.translateLocal('parentReportAction.deletedMessage'); } if (isChatRoom(report) || isTaskReport(report)) { From ec3fe30d59015560357aa12a2c185215145ae847 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Fri, 12 May 2023 12:02:27 +0100 Subject: [PATCH 51/56] fix lint errors --- .../home/report/ContextMenu/ContextMenuActions.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index f76de7dd727c..9f95c0a8bf97 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -110,14 +110,11 @@ export default [ icon: Expensicons.ChatBubble, successTextTranslateKey: '', successIcon: null, - shouldShow: (type, reportAction, isArchivedRoom, betas, anchor, isChronosReport, reportID) => { - return ( - Permissions.canUseThreads(betas) && - type === CONTEXT_MENU_TYPES.REPORT_ACTION && - reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT && - (_.isUndefined(reportAction.childReportID) || reportAction.childReportID.toString() !== reportID) - ); - }, + shouldShow: (type, reportAction, isArchivedRoom, betas, anchor, isChronosReport, reportID) => + Permissions.canUseThreads(betas) && + type === CONTEXT_MENU_TYPES.REPORT_ACTION && + reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT && + (_.isUndefined(reportAction.childReportID) || reportAction.childReportID.toString() !== reportID), onPress: (closePopover, {reportAction, reportID}) => { Report.navigateToAndOpenChildReport(lodashGet(reportAction, 'childReportID', '0'), reportAction, reportID); if (closePopover) { From 0e5e7e2f98c9d0a10715a4c5db3e6fd7cd46954d Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Fri, 12 May 2023 12:26:13 +0100 Subject: [PATCH 52/56] Use sentence casing (slack convo) --- src/languages/en.js | 2 +- src/languages/es.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/languages/en.js b/src/languages/en.js index 90be7096b4c2..df045c0e96b4 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -1303,6 +1303,6 @@ export default { scrollToNewestMessages: 'Scroll to newest messages', }, parentReportAction: { - deletedMessage: '[Deleted Message]', + deletedMessage: '[Deleted message]', }, }; diff --git a/src/languages/es.js b/src/languages/es.js index eed368b0af33..fc11b7ddce2e 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -1768,6 +1768,6 @@ export default { scrollToNewestMessages: 'Desplázate a los mensajes más recientes', }, parentReportAction: { - deletedMessage: '[Mensaje Eliminado]', + deletedMessage: '[Mensaje eliminado]', }, }; From ddb9185b9c3cdbad0c06d156cffd104f80ecd103 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Fri, 12 May 2023 10:58:51 -0600 Subject: [PATCH 53/56] Show threads in lhn regardles of number of participants --- src/libs/ReportUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 68191c72f57e..c8370f007a5f 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1681,7 +1681,7 @@ function shouldReportBeInOptionList(report, reportIDFromRoute, isInGSDMode, curr // Exclude reports that have no data because there wouldn't be anything to show in the option item. // This can happen if data is currently loading from the server or a report is in various stages of being created. // This can also happen for anyone accessing a public room or archived room for which they don't have access to the underlying policy. - if (!report || !report.reportID || (_.isEmpty(report.participants) && !isPublicRoom(report) && !isArchivedRoom(report) && !isMoneyRequestReport(report))) { + if (!report || !report.reportID || (_.isEmpty(report.participants) && !isThread(report) && !isPublicRoom(report) && !isArchivedRoom(report) && !isMoneyRequestReport(report))) { return false; } From 47a8a40b020658f34246643d6906109b10d7f0a4 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Fri, 12 May 2023 11:16:23 -0600 Subject: [PATCH 54/56] Style updates and simplifications --- src/libs/ReportUtils.js | 12 +++--------- src/pages/home/HeaderView.js | 2 +- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 9ef2cdc4d7d0..4b5f4a30a2c0 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -434,10 +434,7 @@ function isPolicyExpenseChatAdmin(report, policies) { * @returns {Boolean} */ function isThread(report) { - if (report && report.parentReportID && report.parentReportActionID) { - return true; - } - return false; + return report && report.parentReportID && report.parentReportActionID; } /** @@ -447,10 +444,7 @@ function isThread(report) { * @returns {Boolean} */ function isThreadParent(reportAction) { - if (reportAction && reportAction.childReportID && reportAction.childReportID !== 0) { - return true; - } - return false; + return reportAction && reportAction.childReportID && reportAction.childReportID !== 0; } /** @@ -467,7 +461,7 @@ function getChatRoomSubtitle(report) { // If thread is not from a DM or group chat, the subtitle will follow the pattern 'Workspace Name • #roomName' const workspaceName = getPolicyName(report); const roomName = isChatRoom(report) ? lodashGet(report, 'displayName') : ''; - return roomName ? `${workspaceName} • ${roomName}` : `${workspaceName}`; + return [workspaceName, roomName].join(' • '); } if (!isDefaultRoom(report) && !isUserCreatedPolicyRoom(report) && !isPolicyExpenseChat(report)) { return ''; diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index 79b386165b4b..8ae4a56d4093 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -75,7 +75,7 @@ const HeaderView = (props) => { const isChatRoom = ReportUtils.isChatRoom(props.report); const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(props.report); const isTaskReport = ReportUtils.isTaskReport(props.report); - const reportHeaderData = isTaskReport && !_.isEmpty(props.parentReport) && (!isThread || ReportUtils.isTaskReport(props.report)) ? props.parentReport : props.report; + const reportHeaderData = isTaskReport && !_.isEmpty(props.parentReport) && (!isThread || isTaskReport) ? props.parentReport : props.report; const title = ReportUtils.getReportName(reportHeaderData); const subtitle = ReportUtils.getChatRoomSubtitle(reportHeaderData); const isConcierge = participants.length === 1 && _.contains(participants, CONST.EMAIL.CONCIERGE); From a473d8562bbc55abb4231372ee8bb81e824ad6d8 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Fri, 12 May 2023 18:28:22 +0100 Subject: [PATCH 55/56] Don't show threads in search for now --- src/libs/OptionsListUtils.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index d4a450f3740f..1843afc9158b 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -545,6 +545,7 @@ function getOptions( sortPersonalDetailsByAlphaAsc = true, forcePolicyNamePreview = false, includeOwnedWorkspaceChats = false, + includeThreads = false, }, ) { if (!isPersonalDetailsReady(personalDetails)) { @@ -584,6 +585,7 @@ function getOptions( return; } + const isThread = ReportUtils.isThread(report); const isChatRoom = ReportUtils.isChatRoom(report); const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(report); const logins = report.participants || []; @@ -592,6 +594,10 @@ function getOptions( return; } + if (isThread && !includeThreads) { + return; + } + // Save the report in the map if this is a single participant so we can associate the reportID with the // personal detail option later. Individuals should not be associated with single participant // policyExpenseChats or chatRooms since those are not people. From 702e6a676613030e738aed06feb19ec5bc04ea16 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Fri, 12 May 2023 11:55:53 -0600 Subject: [PATCH 56/56] Fix logic to always return bool --- src/libs/ReportUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 4b5f4a30a2c0..bf536690f364 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -434,7 +434,7 @@ function isPolicyExpenseChatAdmin(report, policies) { * @returns {Boolean} */ function isThread(report) { - return report && report.parentReportID && report.parentReportActionID; + return Boolean(report && report.parentReportID && report.parentReportActionID); } /**