diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index cbe712d4282a..eeae8d804a8f 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -23,12 +23,6 @@ Onyx.connect({ callback: val => currentUserLogin = val && val.email, }); -let priorityMode; -Onyx.connect({ - key: ONYXKEYS.NVP_PRIORITY_MODE, - callback: val => priorityMode = val, -}); - let loginList; Onyx.connect({ key: ONYXKEYS.LOGIN_LIST, @@ -106,6 +100,9 @@ function addSMSDomainIfPhoneNumber(login) { */ function getPersonalDetailsForLogins(logins, personalDetails) { const personalDetailsForLogins = {}; + if (!personalDetails) { + return personalDetailsForLogins; + } _.each(logins, (login) => { let personalDetail = personalDetails[login]; if (!personalDetail) { @@ -445,7 +442,6 @@ function getOptions(reports, personalDetails, { sortPersonalDetailsByAlphaAsc = true, forcePolicyNamePreview = false, }) { - const isInGSDMode = priorityMode === CONST.PRIORITY_MODE.GSD; let recentReportOptions = []; let personalDetailsOptions = []; const reportMapForLogins = {}; @@ -454,7 +450,7 @@ function getOptions(reports, personalDetails, { const filteredReports = _.filter(reports, report => ReportUtils.shouldReportBeInOptionList( report, Navigation.getReportIDFromRoute(), - isInGSDMode, + false, currentUserLogin, iouReports, betas, diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 841508e3b791..487e8bb5d6eb 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -916,12 +916,6 @@ function shouldReportBeInOptionList(report, reportIDFromRoute, isInGSDMode, curr return true; } - // Include unread reports when in GSD mode - // GSD mode is specifically for focusing the user on the most relevant chats, primarily, the unread ones - if (isInGSDMode) { - return isUnread(report); - } - // Include reports if they have a draft, are pinned, or have an outstanding IOU // These are always relevant to the user no matter what view mode the user prefers if (report.hasDraft || report.isPinned || hasOutstandingIOU(report, currentUserLogin, iouReports)) { @@ -941,6 +935,12 @@ function shouldReportBeInOptionList(report, reportIDFromRoute, isInGSDMode, curr return false; } + // Include unread reports when in GSD mode + // GSD mode is specifically for focusing the user on the most relevant chats, primarily, the unread ones + if (isInGSDMode) { + return isUnread(report); + } + // Include default rooms for free plan policies if (isDefaultRoom(report) && getPolicyType(report, policies) === CONST.POLICY.TYPE.FREE) { return true; diff --git a/tests/unit/LHNFilterTest.js b/tests/unit/LHNFilterTest.js index 0cf7fa020f41..d653c3a457d2 100644 --- a/tests/unit/LHNFilterTest.js +++ b/tests/unit/LHNFilterTest.js @@ -398,5 +398,242 @@ describe('Sidebar', () => { expect(sidebarLinks.queryAllByText(/One, Two/)).toHaveLength(0); }); }); + + it('always shows pinned and draft chats', () => { + // Given a draft report and a pinned report + const draftReport = { + ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com']), + hasDraft: true, + }; + const pinnedReport = { + ...LHNTestUtils.getFakeReport(['email3@test.com', 'email4@test.com']), + isPinned: true, + }; + const sidebarLinks = LHNTestUtils.getDefaultRenderedSidebarLinks(draftReport.reportID); + + return waitForPromisesToResolve() + + // When Onyx is updated to contain that data and the sidebar re-renders + .then(() => Onyx.multiSet({ + [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, + [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [`${ONYXKEYS.COLLECTION.REPORT}${draftReport.reportID}`]: draftReport, + [`${ONYXKEYS.COLLECTION.REPORT}${pinnedReport.reportID}`]: pinnedReport, + })) + + // Then both reports are visible + .then(() => { + const displayNames = sidebarLinks.queryAllByA11yLabel('Chat user display names'); + expect(displayNames).toHaveLength(2); + expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Three, Four'); + expect(lodashGet(displayNames, [1, 'props', 'children'])).toBe('One, Two'); + }); + }); + + it('archived rooms are displayed only when they have unread messages', () => { + // Given an archived chat report, an archived default policy room, and an archived user created policy room + const archivedReport = { + ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com']), + statusNum: CONST.REPORT.STATUS.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + }; + const archivedPolicyRoomReport = { + ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com']), + chatType: CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, + statusNum: CONST.REPORT.STATUS.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + }; + const archivedUserCreatedPolicyRoomReport = { + ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com']), + chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM, + statusNum: CONST.REPORT.STATUS.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + }; + const sidebarLinks = LHNTestUtils.getDefaultRenderedSidebarLinks(); + + return waitForPromisesToResolve() + + // When Onyx is updated to contain that data and the sidebar re-renders + .then(() => Onyx.multiSet({ + [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, + [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [`${ONYXKEYS.COLLECTION.REPORT}${archivedReport.reportID}`]: archivedReport, + [`${ONYXKEYS.COLLECTION.REPORT}${archivedPolicyRoomReport.reportID}`]: archivedPolicyRoomReport, + [`${ONYXKEYS.COLLECTION.REPORT}${archivedUserCreatedPolicyRoomReport.reportID}`]: archivedUserCreatedPolicyRoomReport, + })) + + // Then neither reports are visible + .then(() => { + const displayNames = sidebarLinks.queryAllByA11yLabel('Chat user display names'); + expect(displayNames).toHaveLength(0); + }) + + // When they have unread messages + .then(() => Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${archivedReport.reportID}`, { + lastReadSequenceNumber: LHNTestUtils.TEST_MAX_SEQUENCE_NUMBER - 1, + })) + .then(() => Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${archivedPolicyRoomReport.reportID}`, { + lastReadSequenceNumber: LHNTestUtils.TEST_MAX_SEQUENCE_NUMBER - 1, + })) + .then(() => Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${archivedUserCreatedPolicyRoomReport.reportID}`, { + lastReadSequenceNumber: LHNTestUtils.TEST_MAX_SEQUENCE_NUMBER - 1, + })) + + // Then they are all visible + .then(() => { + const displayNames = sidebarLinks.queryAllByA11yLabel('Chat user display names'); + expect(displayNames).toHaveLength(3); + }); + }); + + it('policy rooms are displayed only when they have unread messages', () => { + // Given a default policy room and user created policy room + const policyRoomReport = { + ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com']), + chatType: CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, + }; + const userCreatedPolicyRoomReport = { + ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com']), + chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM, + }; + const sidebarLinks = LHNTestUtils.getDefaultRenderedSidebarLinks(); + + return waitForPromisesToResolve() + + // When Onyx is updated to contain that data and the sidebar re-renders + .then(() => Onyx.multiSet({ + [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, + [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [`${ONYXKEYS.COLLECTION.REPORT}${policyRoomReport.reportID}`]: policyRoomReport, + [`${ONYXKEYS.COLLECTION.REPORT}${userCreatedPolicyRoomReport.reportID}`]: userCreatedPolicyRoomReport, + })) + + // Then neither reports are visible + .then(() => { + const displayNames = sidebarLinks.queryAllByA11yLabel('Chat user display names'); + expect(displayNames).toHaveLength(0); + }) + + // When they both have unread messages + .then(() => Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${policyRoomReport.reportID}`, { + lastReadSequenceNumber: LHNTestUtils.TEST_MAX_SEQUENCE_NUMBER - 1, + })) + .then(() => Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${userCreatedPolicyRoomReport.reportID}`, { + lastReadSequenceNumber: LHNTestUtils.TEST_MAX_SEQUENCE_NUMBER - 1, + })) + + // Then both rooms are visible + .then(() => { + const displayNames = sidebarLinks.queryAllByA11yLabel('Chat user display names'); + expect(displayNames).toHaveLength(2); + }); + }); + }); + + describe('all combinations of hasComments, isArchived, isUserCreatedPolicyRoom, hasAddWorkspaceError, isUnread, isPinned, hasDraft', () => { + // Given a report that is the active report and doesn't change + const report1 = LHNTestUtils.getFakeReport(['email3@test.com', 'email4@test.com']); + + // Given a free policy that doesn't change + const policy = { + name: 'Policy One', + policyID: '1', + type: CONST.POLICY.TYPE.FREE, + }; + + // Given the user is in all betas + const betas = [ + CONST.BETAS.DEFAULT_ROOMS, + CONST.BETAS.POLICY_ROOMS, + CONST.BETAS.POLICY_EXPENSE_CHAT, + ]; + + // Given there are 7 boolean variables tested in the filtering logic: + // 1. hasComments + // 2. isArchived + // 3. isUserCreatedPolicyRoom + // 4. hasAddWorkspaceError + // 5. isUnread + // 6. isPinned + // 7. hasDraft + // There is one setting not represented here, which is hasOutstandingIOU. In order to test that setting, there must be + // additional reports in Onyx, so it's being left out for now. It's identical to the logic for hasDraft and isPinned though. + + // Given these combinations of booleans which result in the report being filtered out (not shown). + const booleansWhichRemovesInactiveReport = [ + JSON.stringify([false, false, false, false, false, false, false]), + JSON.stringify([false, false, false, true, false, false, false]), + JSON.stringify([false, false, true, false, false, false, false]), + JSON.stringify([false, false, true, false, true, false, false]), + JSON.stringify([false, false, true, true, false, false, false]), + JSON.stringify([false, false, true, true, true, false, false]), + JSON.stringify([false, true, false, false, false, false, false]), + JSON.stringify([false, true, false, false, true, false, false]), + JSON.stringify([false, true, false, true, false, false, false]), + JSON.stringify([false, true, false, true, true, false, false]), + JSON.stringify([false, true, true, false, false, false, false]), + JSON.stringify([false, true, true, false, true, false, false]), + JSON.stringify([false, true, true, true, false, false, false]), + JSON.stringify([false, true, true, true, true, false, false]), + JSON.stringify([true, false, false, false, false, false, false]), + JSON.stringify([true, false, false, true, false, false, false]), + JSON.stringify([true, false, true, false, false, false, false]), + JSON.stringify([true, false, true, true, false, false, false]), + JSON.stringify([true, true, false, false, false, false, false]), + JSON.stringify([true, true, false, true, false, false, false]), + JSON.stringify([true, true, true, false, false, false, false]), + JSON.stringify([true, true, true, true, false, false, false]), + ]; + + // When every single combination of those booleans is tested + + // Taken from https://stackoverflow.com/a/39734979/9114791 to generate all possible boolean combinations + const AMOUNT_OF_VARIABLES = 7; + // eslint-disable-next-line no-bitwise + for (let i = 0; i < (1 << AMOUNT_OF_VARIABLES); i++) { + const boolArr = []; + for (let j = AMOUNT_OF_VARIABLES - 1; j >= 0; j--) { + // eslint-disable-next-line no-bitwise + boolArr.push(Boolean(i & (1 << j))); + } + + // To test a failing set of conditions, comment out the for loop above and then use a hardcoded array + // for the specific case that's failing. You can then debug the code to see why the test is not passing. + // const boolArr = [false, false, false, true, false, false, false]; + + it(`the booleans ${JSON.stringify(boolArr)}`, () => { + const report2 = { + ...LHNTestUtils.getAdvancedFakeReport(...boolArr), + policyID: policy.policyID, + }; + const sidebarLinks = LHNTestUtils.getDefaultRenderedSidebarLinks(report1.reportID); + + return waitForPromisesToResolve() + + // When Onyx is updated to contain that data and the sidebar re-renders + .then(() => Onyx.multiSet({ + [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, + [ONYXKEYS.BETAS]: betas, + [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, + [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, + [`${ONYXKEYS.COLLECTION.POLICY}${policy.policyID}`]: policy, + })) + + // Then depending on the outcome, either one or two reports are visible + .then(() => { + if (booleansWhichRemovesInactiveReport.indexOf(JSON.stringify(boolArr)) > -1) { + // Only one report visible + expect(sidebarLinks.queryAllByA11yHint('Navigates to a chat')).toHaveLength(1); + expect(sidebarLinks.queryAllByA11yLabel('Chat user display names')).toHaveLength(1); + const displayNames = sidebarLinks.queryAllByA11yLabel('Chat user display names'); + expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Three, Four'); + } else { + // Both reports visible + expect(sidebarLinks.queryAllByA11yHint('Navigates to a chat')).toHaveLength(2); + } + }); + }); + } }); });