diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 50c60eeea5a92..6ae60712b19c0 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -146,7 +146,7 @@ function getParticipantNames(personalDetailList) { } /** - * A very optimized method to remove unique items from an array. + * A very optimized method to remove duplicates from an array. * Taken from https://stackoverflow.com/a/9229821/9114791 * * @param {Array} items @@ -186,7 +186,11 @@ function getSearchText(report, reportName, personalDetailList, isChatRoomOrPolic if (!isChatRoomOrPolicyExpenseChat) { for (let i = 0; i < personalDetailList.length; i++) { const personalDetail = personalDetailList[i]; - searchTerms = searchTerms.concat([personalDetail.displayName, personalDetail.login.replace(/\./g, '')]); + + // The regex below is used to remove dots only from the local part of the user email (local-part@domain) + // so that we can match emails that have dots without explicitly writing the dots (e.g: fistlast@domain will match first.last@domain) + // More info https://github.com/Expensify/App/issues/8007 + searchTerms = searchTerms.concat([personalDetail.displayName, personalDetail.login, personalDetail.login.replace(/\.(?=[^\s@]*@)/g, '')]); } } if (report) { @@ -381,16 +385,13 @@ function createOption(logins, personalDetails, report, reportActions = {}, { * @returns {Boolean} */ function isSearchStringMatch(searchValue, searchText, participantNames = new Set(), isChatRoom = false) { - const searchWords = _.map( - searchValue - .replace(/\./g, '') - .replace(/,/g, ' ') - .split(' '), - word => word.trim(), - ); - return _.every(searchWords, (word) => { + const searchWords = _.compact(uniqFast([ + searchValue, + ..._.map(searchValue.replace(/,/g, ' ').split(' '), word => word.trim()), + ])); + const valueToSearch = searchText && searchText.replace(new RegExp(/ /g), ''); + return _.some(searchWords, (word) => { const matchRegex = new RegExp(Str.escapeForRegExp(word), 'i'); - const valueToSearch = searchText && searchText.replace(new RegExp(/ /g), ''); return matchRegex.test(valueToSearch) || (!isChatRoom && participantNames.has(word)); }); } diff --git a/tests/unit/OptionsListUtilsTest.js b/tests/unit/OptionsListUtilsTest.js index db6dffdc0f1ad..9e63d1f076441 100644 --- a/tests/unit/OptionsListUtilsTest.js +++ b/tests/unit/OptionsListUtilsTest.js @@ -514,11 +514,11 @@ describe('OptionsListUtils', () => { expect(results.personalDetails.length).toBe(0); expect(results.userToInvite).not.toBe(null); - // When we add a search term for which exist options for it excluding its period. + // When we add a search term with a period, with options for it that don't contain the period results = OptionsListUtils.getNewChatOptions(REPORTS, PERSONAL_DETAILS, [], 'peter.parker@expensify.com'); - // Then we will have an options at all and there should be a userToInvite too. - expect(results.recentReports.length).toBe(1); + // Then we should have no options at all but there should be a userToInvite + expect(results.recentReports.length).toBe(0); expect(results.userToInvite).not.toBe(null); // When we add a search term for which no options exist and the searchValue itself