Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🍒 Cherry pick PR #11631 to staging 🍒 #11642

Merged
merged 2 commits into from
Oct 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
versionCode 1001021200
versionName "1.2.12-0"
versionCode 1001021201
versionName "1.2.12-1"
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()

if (isNewArchitectureEnabled()) {
Expand Down
2 changes: 1 addition & 1 deletion ios/NewExpensify/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>1.2.12.0</string>
<string>1.2.12.1</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSApplicationQueriesSchemes</key>
Expand Down
2 changes: 1 addition & 1 deletion ios/NewExpensifyTests/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.2.12.0</string>
<string>1.2.12.1</string>
</dict>
</plist>
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
"version": "1.2.12-0",
"version": "1.2.12-1",
"author": "Expensify, Inc.",
"homepage": "https://new.expensify.com",
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
Expand Down
12 changes: 4 additions & 8 deletions src/libs/OptionsListUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 = {};
Expand All @@ -454,7 +450,7 @@ function getOptions(reports, personalDetails, {
const filteredReports = _.filter(reports, report => ReportUtils.shouldReportBeInOptionList(
report,
Navigation.getReportIDFromRoute(),
isInGSDMode,
false,
currentUserLogin,
iouReports,
betas,
Expand Down
12 changes: 6 additions & 6 deletions src/libs/ReportUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand All @@ -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;
Expand Down
237 changes: 237 additions & 0 deletions tests/unit/LHNFilterTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
});
});
}
});
});