diff --git a/src/components/LHNOptionsList/OptionRowLHNData.tsx b/src/components/LHNOptionsList/OptionRowLHNData.tsx index 27f1009824dd..249b598f5bc9 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.tsx +++ b/src/components/LHNOptionsList/OptionRowLHNData.tsx @@ -1,3 +1,4 @@ +import {accountIDSelector} from '@selectors/Session'; import {deepEqual} from 'fast-equals'; import React, {useMemo, useRef} from 'react'; import useCurrentReportID from '@hooks/useCurrentReportID'; @@ -50,6 +51,7 @@ function OptionRowLHNData({ const [movedFromReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getMovedReportID(lastAction, CONST.REPORT.MOVE_TYPE.FROM)}`, {canBeMissing: true}); const [movedToReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getMovedReportID(lastAction, CONST.REPORT.MOVE_TYPE.TO)}`, {canBeMissing: true}); + const [currentUserAccountID] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true, selector: accountIDSelector}); // Check the report errors equality to avoid re-rendering when there are no changes const prevReportErrors = usePrevious(reportAttributes?.reportErrors); const areReportErrorsEqual = useMemo(() => deepEqual(prevReportErrors, reportAttributes?.reportErrors), [prevReportErrors, reportAttributes?.reportErrors]); @@ -76,6 +78,7 @@ function OptionRowLHNData({ lastActionReport, movedFromReport, movedToReport, + currentUserAccountID, }); // eslint-disable-next-line react-compiler/react-compiler if (deepEqual(item, optionItemRef.current)) { @@ -114,6 +117,7 @@ function OptionRowLHNData({ isReportArchived, movedFromReport, movedToReport, + currentUserAccountID, ]); return ( diff --git a/src/components/Search/FilterDropdowns/UserSelectPopup.tsx b/src/components/Search/FilterDropdowns/UserSelectPopup.tsx index 9f1ce5560040..7d3d5810516d 100644 --- a/src/components/Search/FilterDropdowns/UserSelectPopup.tsx +++ b/src/components/Search/FilterDropdowns/UserSelectPopup.tsx @@ -109,12 +109,19 @@ function UserSelectPopup({value, closeOverlay, onChange, isSearchable}: UserSele }, [options.reports, options.personalDetails, draftComments, nvpDismissedProductTraining, loginList, countryCode]); const filteredOptions = useMemo(() => { - return filterAndOrderOptions(optionsList, cleanSearchTerm, countryCode, loginList, { - excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, - maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW, - canInviteUser: false, - }); - }, [optionsList, cleanSearchTerm, countryCode, loginList]); + return filterAndOrderOptions( + optionsList, + cleanSearchTerm, + countryCode, + loginList, + { + excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, + maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW, + canInviteUser: false, + }, + accountID, + ); + }, [optionsList, cleanSearchTerm, countryCode, loginList, accountID]); const listData = useMemo(() => { const personalDetailList = filteredOptions.personalDetails.map((participant) => ({ diff --git a/src/components/Search/SearchAutocompleteList.tsx b/src/components/Search/SearchAutocompleteList.tsx index 9bf74be30480..92d80dfb1b90 100644 --- a/src/components/Search/SearchAutocompleteList.tsx +++ b/src/components/Search/SearchAutocompleteList.tsx @@ -192,6 +192,8 @@ function SearchAutocompleteList({ const [recentSearches] = useOnyx(ONYXKEYS.RECENT_SEARCHES, {canBeMissing: true}); const [countryCode] = useOnyx(ONYXKEYS.COUNTRY_CODE, {canBeMissing: false}); const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); + const [currentUserLogin] = useOnyx(ONYXKEYS.SESSION, {selector: emailSelector, canBeMissing: false}); + const [currentUserAccountID = -1] = useOnyx(ONYXKEYS.SESSION, {selector: accountIDSelector, canBeMissing: false}); const expensifyIcons = useMemoizedLazyExpensifyIcons(['History', 'MagnifyingGlass']); const {options, areOptionsInitialized} = useOptionsList(); @@ -215,8 +217,10 @@ function SearchAutocompleteList({ shouldShowGBR: false, shouldUnreadBeBold: true, loginList, + currentUserAccountID, + currentUserEmail: currentUserLogin, }); - }, [areOptionsInitialized, options, draftComments, nvpDismissedProductTraining, betas, autocompleteQueryValue, countryCode, loginList]); + }, [areOptionsInitialized, options, draftComments, nvpDismissedProductTraining, betas, autocompleteQueryValue, countryCode, loginList, currentUserAccountID, currentUserLogin]); const [isInitialRender, setIsInitialRender] = useState(true); const parsedQuery = useMemo(() => parseForAutocomplete(autocompleteQueryValue), [autocompleteQueryValue]); @@ -290,8 +294,6 @@ function SearchAutocompleteList({ }, [allRecentCategories]); const [policies = getEmptyObject>>()] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: false}); - const [currentUserLogin] = useOnyx(ONYXKEYS.SESSION, {selector: emailSelector, canBeMissing: false}); - const [currentUserAccountID = -1] = useOnyx(ONYXKEYS.SESSION, {selector: accountIDSelector, canBeMissing: false}); const taxRates = useMemo(() => getAllTaxRates(policies), [policies]); @@ -425,6 +427,8 @@ function SearchAutocompleteList({ countryCode, loginList, shouldShowGBR: true, + currentUserAccountID, + currentUserEmail: currentUserLogin, }).personalDetails.filter((participant) => participant.text && !alreadyAutocompletedKeys.has(participant.text.toLowerCase())); return participants.map((participant) => ({ @@ -456,6 +460,8 @@ function SearchAutocompleteList({ countryCode, loginList, shouldShowGBR: true, + currentUserAccountID, + currentUserEmail: currentUserLogin, }).recentReports.filter((chat) => { if (!chat.text) { return false; diff --git a/src/components/Search/SearchFiltersChatsSelector.tsx b/src/components/Search/SearchFiltersChatsSelector.tsx index 2d8f438aeb86..c7035dfe2128 100644 --- a/src/components/Search/SearchFiltersChatsSelector.tsx +++ b/src/components/Search/SearchFiltersChatsSelector.tsx @@ -1,4 +1,5 @@ import reportsSelector from '@selectors/Attributes'; +import {accountIDSelector, emailSelector} from '@selectors/Session'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {usePersonalDetails} from '@components/OnyxListItemProvider'; import {useOptionsList} from '@components/OptionListContextProvider'; @@ -51,6 +52,8 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const [countryCode = CONST.DEFAULT_COUNTRY_CODE] = useOnyx(ONYXKEYS.COUNTRY_CODE, {canBeMissing: false}); const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); + const [currentUserAccountID] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true, selector: accountIDSelector}); + const [currentUserEmail] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true, selector: emailSelector}); const [isSearchingForReports] = useOnyx(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, {initWithStoredValues: false, canBeMissing: true}); const [reportAttributesDerived] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {canBeMissing: true, selector: reportsSelector}); @@ -74,15 +77,33 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen if (!areOptionsInitialized || !isScreenTransitionEnd) { return defaultListOptions; } - return getSearchOptions({options, draftComments, nvpDismissedProductTraining, betas: undefined, isUsedInChatFinder: false, countryCode, loginList}); - }, [areOptionsInitialized, isScreenTransitionEnd, options, draftComments, nvpDismissedProductTraining, countryCode, loginList]); + return getSearchOptions({ + options, + draftComments, + nvpDismissedProductTraining, + betas: undefined, + isUsedInChatFinder: false, + countryCode, + loginList, + currentUserAccountID, + currentUserEmail, + }); + }, [areOptionsInitialized, isScreenTransitionEnd, options, draftComments, nvpDismissedProductTraining, countryCode, loginList, currentUserAccountID, currentUserEmail]); const chatOptions = useMemo(() => { - return filterAndOrderOptions(defaultOptions, cleanSearchTerm, countryCode, loginList, { - selectedOptions, - excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, - }); - }, [defaultOptions, cleanSearchTerm, countryCode, loginList, selectedOptions]); + return filterAndOrderOptions( + defaultOptions, + cleanSearchTerm, + countryCode, + loginList, + { + selectedOptions, + excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, + currentUserEmail, + }, + currentUserAccountID, + ); + }, [defaultOptions, cleanSearchTerm, countryCode, loginList, selectedOptions, currentUserAccountID, currentUserEmail]); const {sections, headerMessage} = useMemo(() => { const newSections: Section[] = []; @@ -99,6 +120,7 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen false, undefined, reportAttributesDerived, + currentUserAccountID, ); newSections.push(formattedResults.section); @@ -131,6 +153,7 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen selectedOptions, selectedReportIDs, translate, + currentUserAccountID, ]); useEffect(() => { diff --git a/src/components/Search/SearchFiltersParticipantsSelector.tsx b/src/components/Search/SearchFiltersParticipantsSelector.tsx index aa20315d8a50..5dcf8b52f92a 100644 --- a/src/components/Search/SearchFiltersParticipantsSelector.tsx +++ b/src/components/Search/SearchFiltersParticipantsSelector.tsx @@ -1,4 +1,5 @@ import reportsSelector from '@selectors/Attributes'; +import {accountIDSelector, emailSelector} from '@selectors/Session'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {usePersonalDetails} from '@components/OnyxListItemProvider'; import {useOptionsList} from '@components/OptionListContextProvider'; @@ -51,6 +52,8 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate}: const [reportAttributesDerived] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {canBeMissing: true, selector: reportsSelector}); const [countryCode = CONST.DEFAULT_COUNTRY_CODE] = useOnyx(ONYXKEYS.COUNTRY_CODE, {canBeMissing: false}); const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); + const [currentUserAccountID] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true, selector: accountIDSelector}); + const [currentUserEmail] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true, selector: emailSelector}); const [selectedOptions, setSelectedOptions] = useState([]); const [searchTerm, setSearchTerm] = useState(''); const cleanSearchTerm = useMemo(() => searchTerm.trim().toLowerCase(), [searchTerm]); @@ -72,22 +75,32 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate}: { excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, includeCurrentUser: true, + currentUserAccountID, + currentUserEmail, }, countryCode, ); - }, [areOptionsInitialized, options.reports, options.personalDetails, draftComments, nvpDismissedProductTraining, loginList, countryCode]); + }, [areOptionsInitialized, options.reports, options.personalDetails, draftComments, nvpDismissedProductTraining, loginList, countryCode, currentUserAccountID, currentUserEmail]); const unselectedOptions = useMemo(() => { return filterSelectedOptions(defaultOptions, new Set(selectedOptions.map((option) => option.accountID))); }, [defaultOptions, selectedOptions]); const chatOptions = useMemo(() => { - const filteredOptions = filterAndOrderOptions(unselectedOptions, cleanSearchTerm, countryCode, loginList, { - selectedOptions, - excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, - maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW, - canInviteUser: false, - }); + const filteredOptions = filterAndOrderOptions( + unselectedOptions, + cleanSearchTerm, + countryCode, + loginList, + { + selectedOptions, + excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, + maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW, + canInviteUser: false, + currentUserEmail, + }, + currentUserAccountID, + ); const {currentUserOption} = unselectedOptions; @@ -97,7 +110,7 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate}: } return filteredOptions; - }, [unselectedOptions, cleanSearchTerm, countryCode, loginList, selectedOptions]); + }, [unselectedOptions, cleanSearchTerm, countryCode, loginList, selectedOptions, currentUserAccountID, currentUserEmail]); const {sections, headerMessage} = useMemo(() => { const newSections: Section[] = []; @@ -114,6 +127,7 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate}: true, undefined, reportAttributesDerived, + currentUserAccountID, ); const selectedCurrentUser = formattedResults.section.data.find((option) => option.accountID === chatOptions.currentUserOption?.accountID); @@ -162,7 +176,7 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate}: sections: newSections, headerMessage: message, }; - }, [areOptionsInitialized, cleanSearchTerm, selectedOptions, chatOptions, personalDetails, reportAttributesDerived, translate, formatPhoneNumber]); + }, [areOptionsInitialized, cleanSearchTerm, selectedOptions, chatOptions, personalDetails, reportAttributesDerived, translate, formatPhoneNumber, currentUserAccountID]); const resetChanges = useCallback(() => { setSelectedOptions([]); diff --git a/src/hooks/useContactImport.ts b/src/hooks/useContactImport.ts index 1893e0d1272a..58a95bef15f6 100644 --- a/src/hooks/useContactImport.ts +++ b/src/hooks/useContactImport.ts @@ -1,3 +1,4 @@ +import {emailSelector} from '@selectors/Session'; import {useCallback, useState} from 'react'; import {RESULTS} from 'react-native-permissions'; import type {PermissionStatus} from 'react-native-permissions'; @@ -33,14 +34,15 @@ function useContactImport(): UseContactImportResult { const {localeCompare} = useLocalize(); const [countryCode = CONST.DEFAULT_COUNTRY_CODE] = useOnyx(ONYXKEYS.COUNTRY_CODE, {canBeMissing: false}); const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); + const [currentUserEmail] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true, selector: emailSelector}); const importAndSaveContacts = useCallback(() => { contactImport().then(({contactList, permissionStatus}: ContactImportResult) => { setContactPermissionState(permissionStatus); - const usersFromContact = getContacts(contactList, localeCompare, countryCode, loginList); + const usersFromContact = getContacts(contactList, localeCompare, countryCode, loginList, currentUserEmail); setContacts(usersFromContact); }); - }, [localeCompare, countryCode, loginList]); + }, [localeCompare, countryCode, loginList, currentUserEmail]); useContactPermissions({ importAndSaveContacts, diff --git a/src/hooks/useSearchSelector.base.ts b/src/hooks/useSearchSelector.base.ts index 7196fa0a9ea5..c0a4e43e64b9 100644 --- a/src/hooks/useSearchSelector.base.ts +++ b/src/hooks/useSearchSelector.base.ts @@ -1,3 +1,4 @@ +import {accountIDSelector, emailSelector} from '@selectors/Session'; import {useCallback, useMemo, useState} from 'react'; import type {PermissionStatus} from 'react-native-permissions'; import {useOptionsList} from '@components/OptionListContextProvider'; @@ -164,6 +165,8 @@ function useSearchSelectorBase({ const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); const [draftComments] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT, {canBeMissing: true}); const [nvpDismissedProductTraining] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, {canBeMissing: true}); + const [currentUserAccountID] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true, selector: accountIDSelector}); + const [currentUserEmail] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true, selector: emailSelector}); const onListEndReached = useDebounce( useCallback(() => { @@ -195,6 +198,8 @@ function useSearchSelectorBase({ includeUserToInvite, countryCode, loginList, + currentUserAccountID, + currentUserEmail, }); case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_MEMBER_INVITE: return getValidOptions(optionsWithContacts, draftComments, nvpDismissedProductTraining, loginList, { @@ -207,6 +212,8 @@ function useSearchSelectorBase({ maxRecentReportElements: maxRecentReportsToShow, searchString: computedSearchTerm, includeUserToInvite, + currentUserAccountID, + currentUserEmail, }); case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_GENERAL: return getValidOptions(optionsWithContacts, draftComments, nvpDismissedProductTraining, loginList, { @@ -217,6 +224,8 @@ function useSearchSelectorBase({ maxRecentReportElements: maxRecentReportsToShow, includeUserToInvite, excludeLogins, + currentUserAccountID, + currentUserEmail, }); case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_SHARE_LOG: return getValidOptions( @@ -236,6 +245,8 @@ function useSearchSelectorBase({ searchString: computedSearchTerm, maxElements: maxResults, includeUserToInvite, + currentUserAccountID, + currentUserEmail, }, countryCode, ); @@ -256,6 +267,8 @@ function useSearchSelectorBase({ searchString: computedSearchTerm, maxElements: maxResults, includeUserToInvite, + currentUserAccountID, + currentUserEmail, }); case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_ATTENDEES: return getValidOptions(optionsWithContacts, draftComments, nvpDismissedProductTraining, loginList, { @@ -271,6 +284,8 @@ function useSearchSelectorBase({ searchString: computedSearchTerm, includeUserToInvite, includeCurrentUser, + currentUserAccountID, + currentUserEmail, }); default: return getEmptyOptions(); @@ -293,6 +308,8 @@ function useSearchSelectorBase({ getValidOptionsConfig, selectedOptions, includeCurrentUser, + currentUserAccountID, + currentUserEmail, ]); const isOptionSelected = useMemo(() => { diff --git a/src/libs/ContactUtils.ts b/src/libs/ContactUtils.ts index dc562f996524..99949a63ce67 100644 --- a/src/libs/ContactUtils.ts +++ b/src/libs/ContactUtils.ts @@ -34,6 +34,7 @@ const getContacts = ( localeCompare: LocaleContextProps['localeCompare'], countryCode: number, loginList: OnyxEntry, + currentUserEmail?: string, ): Array> => { return deviceContacts .map((contact) => { @@ -55,6 +56,7 @@ const getContacts = ( avatar: avatarSource, countryCode, loginList, + currentUserEmail, }); }) .filter((contact): contact is SearchOption => contact !== null); diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index f675cf270cdc..86a74b783edd 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -188,15 +188,6 @@ import type { * be configured to display different results based on the options passed to the private getOptions() method. Public * methods should be named for the views they build options for and then exported for use in a component. */ -let currentUserLogin: string | undefined; -let currentUserAccountID: number | undefined; -Onyx.connect({ - key: ONYXKEYS.SESSION, - callback: (value) => { - currentUserLogin = value?.email; - currentUserAccountID = value?.accountID; - }, -}); let allPersonalDetails: OnyxEntry; Onyx.connect({ @@ -410,7 +401,7 @@ function uniqFast(items: string[]): string[] { /** * Get the last actor display name from last actor details. */ -function getLastActorDisplayName(lastActorDetails: Partial | null) { +function getLastActorDisplayName(lastActorDetails: Partial | null, currentUserAccountID: number | undefined) { if (!lastActorDetails) { return ''; } @@ -429,7 +420,12 @@ function getLastActorDisplayName(lastActorDetails: Partial | nu /** * Should show the last actor display name from last actor details. */ -function shouldShowLastActorDisplayName(report: OnyxEntry, lastActorDetails: Partial | null, lastAction: OnyxEntry) { +function shouldShowLastActorDisplayName( + report: OnyxEntry, + lastActorDetails: Partial | null, + lastAction: OnyxEntry, + currentUserAccountID: number | undefined, +) { const reportID = report?.reportID; const lastReportAction = reportID ? lastVisibleReportActions[reportID] : lastAction; @@ -445,7 +441,7 @@ function shouldShowLastActorDisplayName(report: OnyxEntry, lastActorDeta return false; } - const lastActorDisplayName = getLastActorDisplayName(lastActorDetails); + const lastActorDisplayName = getLastActorDisplayName(lastActorDetails, currentUserAccountID); if (!lastActorDisplayName) { return false; @@ -562,7 +558,7 @@ function hasHiddenDisplayNames(accountIDs: number[]) { return getPersonalDetailsByIDs({accountIDs, currentUserAccountID: 0}).some((personalDetail) => !getDisplayNameOrDefault(personalDetail, undefined, false)); } -function getLastActorDisplayNameFromLastVisibleActions(report: OnyxEntry, lastActorDetails: Partial | null): string { +function getLastActorDisplayNameFromLastVisibleActions(report: OnyxEntry, lastActorDetails: Partial | null, currentUserAccountID: number | undefined): string { const reportID = report?.reportID; const lastReportAction = reportID ? lastVisibleReportActions[reportID] : undefined; @@ -579,11 +575,11 @@ function getLastActorDisplayNameFromLastVisibleActions(report: OnyxEntry } if (actorDetails) { - return getLastActorDisplayName(actorDetails); + return getLastActorDisplayName(actorDetails, currentUserAccountID); } } - return getLastActorDisplayName(lastActorDetails); + return getLastActorDisplayName(lastActorDetails, currentUserAccountID); } /** @@ -1078,7 +1074,7 @@ function getPolicyExpenseReportOption(participant: Participant | SearchOptionDat * Note: We can't migrate this off of using logins because this is used to check if you're trying to start a chat with * yourself or a different user, and people won't be starting new chats via accountID usually. */ -function isCurrentUser(userDetails: PersonalDetails, loginList: OnyxEntry): boolean { +function isCurrentUser(userDetails: PersonalDetails, loginList: OnyxEntry, currentUserEmail: string | undefined): boolean { if (!userDetails) { return false; } @@ -1086,7 +1082,7 @@ function isCurrentUser(userDetails: PersonalDetails, loginList: OnyxEntry // If user login is a mobile number, append sms domain if not appended already. const userDetailsLogin = addSMSDomainIfPhoneNumber(userDetails.login ?? ''); - if (currentUserLogin?.toLowerCase() === userDetailsLogin.toLowerCase()) { + if (currentUserEmail?.toLowerCase() === userDetailsLogin.toLowerCase()) { return true; } @@ -1648,13 +1644,14 @@ function getUserToInviteOption({ shouldAcceptName = false, countryCode = CONST.DEFAULT_COUNTRY_CODE, loginList = {}, + currentUserEmail, }: GetUserToInviteConfig): SearchOptionData | null { if (!searchValue) { return null; } const parsedPhoneNumber = parsePhoneNumber(appendCountryCode(Str.removeSMSDomain(searchValue), countryCode)); - const isCurrentUserLogin = isCurrentUser({login: searchValue} as PersonalDetails, loginList); + const isCurrentUserLogin = isCurrentUser({login: searchValue} as PersonalDetails, loginList, currentUserEmail); const isInSelectedOption = selectedOptions.some((option) => 'login' in option && option.login === searchValue); const isValidEmail = Str.isValidEmail(searchValue) && !Str.isDomainEmail(searchValue) && !Str.endsWith(searchValue, CONST.SMS.DOMAIN); const isValidPhoneNumber = parsedPhoneNumber.possible && Str.isValidE164Phone(getPhoneNumberWithoutSpecialChars(parsedPhoneNumber.number?.input ?? '')); @@ -1707,6 +1704,7 @@ function getUserToInviteContactOption({ avatar = '', countryCode = CONST.DEFAULT_COUNTRY_CODE, loginList = {}, + currentUserEmail, }: GetUserToInviteConfig): SearchOption | null { // If email is provided, use it as the primary identifier // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing @@ -1727,7 +1725,7 @@ function getUserToInviteContactOption({ const login = email ? effectiveSearchValue : (sanitizedPhoneLogin ?? searchValue); const normalizedLoginToExclude = addSMSDomainIfPhoneNumber(login).toLowerCase(); - const isCurrentUserLogin = isCurrentUser({login} as PersonalDetails, loginList); + const isCurrentUserLogin = isCurrentUser({login} as PersonalDetails, loginList, currentUserEmail); const isInSelectedOption = selectedOptions.some((option) => 'login' in option && option.login === login); const isInOptionToExclude = optionsToExclude.findIndex((optionToExclude) => 'login' in optionToExclude && optionToExclude.login === normalizedLoginToExclude) !== -1; @@ -1817,6 +1815,7 @@ function isValidReport(option: SearchOption, config: IsValidReportsConfi excludeNonAdminWorkspaces, isRestrictedToPreferredPolicy, preferredPolicyID, + currentUserAccountID, } = config; const topmostReportId = Navigation.getTopmostReportId(); @@ -2121,7 +2120,7 @@ function getValidOptions( loginsToExclude[option.login] = true; } } - const {includeP2P = true, shouldBoldTitleByDefault = true, includeDomainEmail = false, shouldShowGBR = false, ...getValidReportsConfig} = config; + const {includeP2P = true, shouldBoldTitleByDefault = true, includeDomainEmail = false, shouldShowGBR = false, currentUserAccountID, currentUserEmail, ...getValidReportsConfig} = config; // Get valid recent reports: let recentReportOptions: Array> = []; @@ -2162,6 +2161,7 @@ function getValidOptions( includeP2P, includeDomainEmail, loginsToExclude, + currentUserAccountID, }, draftComment, ); @@ -2226,10 +2226,10 @@ function getValidOptions( if (includeP2P) { let personalDetailLoginsToExclude = loginsToExclude; - if (currentUserLogin) { + if (currentUserEmail) { personalDetailLoginsToExclude = { ...loginsToExclude, - [currentUserLogin]: !config.includeCurrentUser, + [currentUserEmail]: !config.includeCurrentUser, }; } @@ -2261,7 +2261,7 @@ function getValidOptions( if (!personalDetail) { continue; } - if (!!currentUserLogin && personalDetail?.login === currentUserLogin) { + if (!!currentUserEmail && personalDetail?.login === currentUserEmail) { currentUserRef.current = personalDetail; } personalDetail.isBold = shouldBoldTitleByDefault; @@ -2284,6 +2284,7 @@ function getValidOptions( countryCode, { excludeLogins: loginsToExclude, + currentUserEmail, }, ); } @@ -2314,6 +2315,8 @@ type SearchOptionsConfig = { shouldShowGBR?: boolean; shouldUnreadBeBold?: boolean; loginList: OnyxEntry; + currentUserAccountID?: number; + currentUserEmail?: string; }; /** @@ -2335,6 +2338,8 @@ function getSearchOptions({ shouldShowGBR = false, shouldUnreadBeBold = false, loginList, + currentUserAccountID, + currentUserEmail, }: SearchOptionsConfig): Options { Timing.start(CONST.TIMING.LOAD_SEARCH_OPTIONS); Performance.markStart(CONST.TIMING.LOAD_SEARCH_OPTIONS); @@ -2364,6 +2369,8 @@ function getSearchOptions({ includeUserToInvite, shouldShowGBR, shouldUnreadBeBold, + currentUserAccountID, + currentUserEmail, }, countryCode, ); @@ -2398,17 +2405,23 @@ function getIOUConfirmationOptionsFromPayeePersonalDetail(personalDetail: OnyxEn }; } -function getFilteredRecentAttendees(personalDetails: OnyxEntry, attendees: Attendee[], recentAttendees: Attendee[]): Option[] { - const recentAttendeeHasCurrentUser = recentAttendees.find((attendee) => attendee.email === currentUserLogin || attendee.login === currentUserLogin); - if (!recentAttendeeHasCurrentUser && currentUserLogin) { - const details = getPersonalDetailByEmail(currentUserLogin); +function getFilteredRecentAttendees( + personalDetails: OnyxEntry, + attendees: Attendee[], + recentAttendees: Attendee[], + currentUserEmail: string | undefined, + currentUserAccountID: number | undefined, +): Option[] { + const recentAttendeeHasCurrentUser = recentAttendees.find((attendee) => attendee.email === currentUserEmail || attendee.login === currentUserEmail); + if (!recentAttendeeHasCurrentUser && currentUserEmail) { + const details = getPersonalDetailByEmail(currentUserEmail); recentAttendees.push({ - email: currentUserLogin, - login: currentUserLogin, - displayName: details?.displayName ?? currentUserLogin, + email: currentUserEmail, + login: currentUserEmail, + displayName: details?.displayName ?? currentUserEmail, accountID: currentUserAccountID, - text: details?.displayName ?? currentUserLogin, - searchText: details?.displayName ?? currentUserLogin, + text: details?.displayName ?? currentUserEmail, + searchText: details?.displayName ?? currentUserEmail, avatarUrl: details?.avatarThumbnail ?? '', }); } @@ -2463,6 +2476,8 @@ function getMemberInviteOptions( excludeLogins: Record = {}, includeSelectedOptions = false, countryCode: number = CONST.DEFAULT_COUNTRY_CODE, + currentUserAccountID?: number, + currentUserEmail?: string, ): Options { return getValidOptions( {personalDetails, reports: []}, @@ -2477,6 +2492,8 @@ function getMemberInviteOptions( includeRecentReports: false, searchString: '', maxElements: undefined, + currentUserAccountID, + currentUserEmail, }, countryCode, ); @@ -2546,6 +2563,7 @@ function formatSectionsFromSearchTerm( shouldGetOptionDetails = false, filteredWorkspaceChats: SearchOptionData[] = [], reportAttributesDerived?: ReportAttributesDerivedValue['reports'], + currentUserAccountID?: number, ): SectionForSearchTerm { // We show the selected participants at the top of the list when there is no search term or maximum number of participants has already been selected // However, if there is a search term we remove the selected participants from the top of the list unless they are part of the search results @@ -2570,7 +2588,7 @@ function formatSectionsFromSearchTerm( // This will add them to the list of options, deduping them if they already exist in the other lists const selectedParticipantsWithoutDetails = selectedOptions.filter((participant) => { const accountID = participant.accountID ?? null; - const isPartOfSearchTerm = getPersonalDetailSearchTerms(participant).join(' ').toLowerCase().includes(cleanSearchTerm); + const isPartOfSearchTerm = getPersonalDetailSearchTerms(participant, currentUserAccountID).join(' ').toLowerCase().includes(cleanSearchTerm); const isReportInRecentReports = filteredRecentReports.some((report) => report.accountID === accountID) || filteredWorkspaceChats.some((report) => report.accountID === accountID); const isReportInPersonalDetails = filteredPersonalDetails.some((personalDetail) => personalDetail.accountID === accountID); @@ -2604,8 +2622,8 @@ function getFirstKeyForList(data?: Option[] | null) { return firstNonEmptyDataObj?.keyForList ? firstNonEmptyDataObj?.keyForList : ''; } -function getPersonalDetailSearchTerms(item: Partial) { - if (item.accountID === currentUserAccountID) { +function getPersonalDetailSearchTerms(item: Partial, currentUserAccountID?: number) { + if (currentUserAccountID !== undefined && item.accountID === currentUserAccountID) { return getCurrentUserSearchTerms(item); } return [item.participantsList?.[0]?.displayName ?? item.displayName ?? '', item.login ?? '', item.login?.replace(CONST.EMAIL_SEARCH_REGEX, '') ?? '']; @@ -2682,11 +2700,11 @@ function filterWorkspaceChats(reports: SearchOptionData[], searchTerms: string[] return filteredReports; } -function filterPersonalDetails(personalDetails: SearchOptionData[], searchTerms: string[]): SearchOptionData[] { +function filterPersonalDetails(personalDetails: SearchOptionData[], searchTerms: string[], currentUserAccountID?: number): SearchOptionData[] { return searchTerms.reduceRight( (items, term) => filterArrayByMatch(items, term, (item) => { - const values = getPersonalDetailSearchTerms(item); + const values = getPersonalDetailSearchTerms(item, currentUserAccountID); return uniqFast(values); }), personalDetails, @@ -2770,7 +2788,14 @@ function filterSelfDMChat(report: SearchOptionData, searchTerms: string[]): Sear return isMatch ? report : undefined; } -function filterOptions(options: Options, searchInputValue: string, countryCode: number, loginList: OnyxEntry, config?: FilterUserToInviteConfig): Options { +function filterOptions( + options: Options, + searchInputValue: string, + countryCode: number, + loginList: OnyxEntry, + config?: FilterUserToInviteConfig, + currentUserAccountID?: number, +): Options { const trimmedSearchInput = searchInputValue.trim(); // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing @@ -2779,7 +2804,7 @@ function filterOptions(options: Options, searchInputValue: string, countryCode: const searchTerms = searchValue ? searchValue.split(' ') : []; const recentReports = filterReports(options.recentReports, searchTerms); - const personalDetails = filterPersonalDetails(options.personalDetails, searchTerms); + const personalDetails = filterPersonalDetails(options.personalDetails, searchTerms, currentUserAccountID); const currentUserOption = filterCurrentUserOption(options.currentUserOption, searchTerms); const userToInvite = filterUserToInvite( { @@ -2844,10 +2869,17 @@ function combineOrderingOfReportsAndPersonalDetails( * Filters and orders the options based on the search input value. * Note that personal details that are part of the recent reports will always be shown as part of the recent reports (ie. DMs). */ -function filterAndOrderOptions(options: Options, searchInputValue: string, countryCode: number, loginList: OnyxEntry, config: FilterAndOrderConfig = {}): Options { +function filterAndOrderOptions( + options: Options, + searchInputValue: string, + countryCode: number, + loginList: OnyxEntry, + config: FilterAndOrderConfig = {}, + currentUserAccountID?: number, +): Options { let filterResult = options; if (searchInputValue.trim().length > 0) { - filterResult = filterOptions(options, searchInputValue, countryCode, loginList, config); + filterResult = filterOptions(options, searchInputValue, countryCode, loginList, config, currentUserAccountID); } const orderedOptions = combineOrderingOfReportsAndPersonalDetails(filterResult, searchInputValue, config); @@ -2902,7 +2934,7 @@ function shouldUseBoldText(report: SearchOptionData): boolean { return report.isUnread === true && notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.MUTE && !isHiddenForCurrentUser(notificationPreference); } -function getManagerMcTestParticipant(): Participant | undefined { +function getManagerMcTestParticipant(currentUserAccountID: number | undefined): Participant | undefined { const managerMcTestPersonalDetails = Object.values(allPersonalDetails ?? {}).find((personalDetails) => personalDetails?.login === CONST.EMAIL.MANAGER_MCTEST); const managerMcTestReport = managerMcTestPersonalDetails?.accountID && currentUserAccountID ? getChatByParticipants([managerMcTestPersonalDetails?.accountID, currentUserAccountID]) : undefined; diff --git a/src/libs/OptionsListUtils/types.ts b/src/libs/OptionsListUtils/types.ts index 814cc47f115e..c4f4df5741d5 100644 --- a/src/libs/OptionsListUtils/types.ts +++ b/src/libs/OptionsListUtils/types.ts @@ -176,7 +176,9 @@ type IsValidReportsConfig = Pick< | 'excludeNonAdminWorkspaces' | 'isRestrictedToPreferredPolicy' | 'preferredPolicyID' ->; +> & { + currentUserAccountID?: number; +}; type GetOptionsConfig = { excludeLogins?: Record; @@ -190,6 +192,8 @@ type GetOptionsConfig = { maxElements?: number; maxRecentReportElements?: number; includeUserToInvite?: boolean; + currentUserAccountID?: number; + currentUserEmail?: string; } & GetValidReportsConfig; type GetUserToInviteConfig = { @@ -205,6 +209,7 @@ type GetUserToInviteConfig = { optionsToExclude?: GetOptionsConfig['selectedOptions']; countryCode?: number; loginList: OnyxEntry; + currentUserEmail?: string; } & Pick; type MemberForList = { @@ -242,7 +247,7 @@ type PreviewConfig = { isSelected?: boolean; }; -type FilterUserToInviteConfig = Pick & { +type FilterUserToInviteConfig = Pick & { canInviteUser?: boolean; excludeLogins?: Record; }; diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index 694842b3ad35..b9947623e5e1 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -648,6 +648,7 @@ function getOptionData({ lastActionReport, movedFromReport, movedToReport, + currentUserAccountID, }: { report: OnyxEntry; oneTransactionThreadReport: OnyxEntry; @@ -666,6 +667,7 @@ function getOptionData({ lastActionReport: OnyxEntry | undefined; movedFromReport?: OnyxEntry; movedToReport?: OnyxEntry; + currentUserAccountID: number | undefined; }): OptionData | undefined { // When a user signs out, Onyx is cleared. Due to the lazy rendering with a virtual list, it's possible for // this method to be called after the Onyx data has been cleared out. In that case, it's fine to do @@ -792,7 +794,7 @@ function getOptionData({ : null; } - const lastActorDisplayName = getLastActorDisplayName(lastActorDetails); + const lastActorDisplayName = getLastActorDisplayName(lastActorDetails, currentUserAccountID); let lastMessageTextFromReport = lastMessageTextFromReportProp; if (!lastMessageTextFromReport) { lastMessageTextFromReport = getLastMessageTextForReport({report, lastActorDetails, movedFromReport, movedToReport, policy, isReportArchived}); @@ -827,7 +829,7 @@ function getOptionData({ accountID: lastAction.actorAccountID, }; } - actorDisplayName = actorDetails ? getLastActorDisplayName(actorDetails) : undefined; + actorDisplayName = actorDetails ? getLastActorDisplayName(actorDetails, currentUserAccountID) : undefined; const lastActionOriginalMessage = lastAction?.actionName ? getOriginalMessage(lastAction) : null; const targetAccountIDs = lastActionOriginalMessage?.targetAccountIDs ?? []; const targetAccountIDsLength = targetAccountIDs.length !== 0 ? targetAccountIDs.length : (report.lastMessageHtml?.match(/]*><\/mention-user>/g)?.length ?? 0); @@ -930,7 +932,8 @@ function getOptionData({ } else if (isCardIssuedAction(lastAction)) { result.alternateText = getCardIssuedMessage({reportAction: lastAction, expensifyCard: card, translate}); } else if (lastAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW && lastActorDisplayName && lastMessageTextFromReport) { - const displayName = (lastMessageTextFromReport.length > 0 && getLastActorDisplayNameFromLastVisibleActions(report, lastActorDetails)) || lastActorDisplayName; + const displayName = + (lastMessageTextFromReport.length > 0 && getLastActorDisplayNameFromLastVisibleActions(report, lastActorDetails, currentUserAccountID)) || lastActorDisplayName; result.alternateText = formatReportLastMessageText(`${displayName}: ${lastMessageText}`); } else if (lastAction && isOldDotReportAction(lastAction)) { result.alternateText = getMessageOfOldDotReportAction(lastAction); @@ -994,8 +997,9 @@ function getOptionData({ translate('report.noActivityYet'), ); } - if (shouldShowLastActorDisplayName(report, lastActorDetails, lastAction) && !isReportArchived) { - const displayName = (lastMessageTextFromReport.length > 0 && getLastActorDisplayNameFromLastVisibleActions(report, lastActorDetails)) || lastActorDisplayName; + if (shouldShowLastActorDisplayName(report, lastActorDetails, lastAction, currentUserAccountID) && !isReportArchived) { + const displayName = + (lastMessageTextFromReport.length > 0 && getLastActorDisplayNameFromLastVisibleActions(report, lastActorDetails, currentUserAccountID)) || lastActorDisplayName; result.alternateText = `${displayName}: ${formatReportLastMessageText(lastMessageText)}`; } else { result.alternateText = formatReportLastMessageText(lastMessageText); diff --git a/src/libs/actions/IOU/index.ts b/src/libs/actions/IOU/index.ts index be6dba9b0b3f..741881f6a09a 100644 --- a/src/libs/actions/IOU/index.ts +++ b/src/libs/actions/IOU/index.ts @@ -1823,7 +1823,7 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR if (isMoneyRequestToManagerMcTest) { const date = new Date(); const isTestReceipt = transaction.receipt?.isTestReceipt ?? false; - const managerMcTestParticipant = getManagerMcTestParticipant() ?? {}; + const managerMcTestParticipant = getManagerMcTestParticipant(userAccountID) ?? {}; const optimisticIOUReportAction = buildOptimisticIOUReportAction({ type: isScanRequest && !isTestReceipt ? CONST.IOU.REPORT_ACTION_TYPE.CREATE : CONST.IOU.REPORT_ACTION_TYPE.PAY, amount: iou.report?.total ?? 0, diff --git a/src/pages/NewChatPage.tsx b/src/pages/NewChatPage.tsx index 52e05cf17f1d..7fff069d8461 100755 --- a/src/pages/NewChatPage.tsx +++ b/src/pages/NewChatPage.tsx @@ -1,5 +1,6 @@ import {useFocusEffect} from '@react-navigation/native'; import reportsSelector from '@selectors/Attributes'; +import {accountIDSelector} from '@selectors/Session'; import isEmpty from 'lodash/isEmpty'; import reject from 'lodash/reject'; import type {Ref} from 'react'; @@ -62,6 +63,7 @@ function useOptions() { const [newGroupDraft] = useOnyx(ONYXKEYS.NEW_GROUP_CHAT_DRAFT, {canBeMissing: true}); const [countryCode = CONST.DEFAULT_COUNTRY_CODE] = useOnyx(ONYXKEYS.COUNTRY_CODE, {canBeMissing: false}); const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); + const [currentUserAccountID] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true, selector: accountIDSelector}); const personalData = useCurrentUserPersonalDetails(); const focusTimeoutRef = useRef(null); const [didScreenTransitionEnd, setDidScreenTransitionEnd] = useState(false); @@ -100,6 +102,8 @@ function useOptions() { { betas: betas ?? [], includeSelfDM: true, + currentUserAccountID, + currentUserEmail: personalData.login, }, countryCode, ); @@ -108,10 +112,18 @@ function useOptions() { const areOptionsInitialized = !isLoading; - const options = filterAndOrderOptions(unselectedOptions, debouncedSearchTerm, countryCode, loginList, { - selectedOptions, - maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW, - }); + const options = filterAndOrderOptions( + unselectedOptions, + debouncedSearchTerm, + countryCode, + loginList, + { + selectedOptions, + maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW, + currentUserEmail: personalData.login, + }, + currentUserAccountID, + ); const cleanSearchTerm = debouncedSearchTerm.trim().toLowerCase(); @@ -120,7 +132,7 @@ function useOptions() { !!options.userToInvite, debouncedSearchTerm.trim(), countryCode, - selectedOptions.some((participant) => getPersonalDetailSearchTerms(participant).join(' ').toLowerCase?.().includes(cleanSearchTerm)), + selectedOptions.some((participant) => getPersonalDetailSearchTerms(participant, currentUserAccountID).join(' ').toLowerCase?.().includes(cleanSearchTerm)), ); useFocusEffect( @@ -154,6 +166,7 @@ function useOptions() { getUserToInviteOption({ searchValue: participant?.login, loginList, + currentUserEmail: personalData.login, }); if (participantOption) { result.push({ @@ -227,6 +240,7 @@ function NewChatPage({ref}: NewChatPageProps) { const {top} = useSafeAreaInsets(); const [isSearchingForReports] = useOnyx(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, {initWithStoredValues: false, canBeMissing: true}); const [reportAttributesDerived] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {canBeMissing: true, selector: reportsSelector}); + const [currentUserAccountID] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true, selector: accountIDSelector}); const selectionListRef = useRef(null); const {singleExecution} = useSingleExecution(); @@ -263,6 +277,7 @@ function NewChatPage({ref}: NewChatPageProps) { undefined, undefined, reportAttributesDerived, + currentUserAccountID, ); sectionsList.push(formatResults.section); @@ -300,7 +315,7 @@ function NewChatPage({ref}: NewChatPageProps) { } return [sectionsList, firstKey]; - }, [debouncedSearchTerm, selectedOptions, recentReports, personalDetails, reportAttributesDerived, translate, userToInvite]); + }, [debouncedSearchTerm, selectedOptions, recentReports, personalDetails, reportAttributesDerived, translate, userToInvite, currentUserAccountID]); /** * Removes a selected option from list if already selected. If not already selected add this option to the list. diff --git a/src/pages/RoomInvitePage.tsx b/src/pages/RoomInvitePage.tsx index 570a97741823..398cabd8d852 100644 --- a/src/pages/RoomInvitePage.tsx +++ b/src/pages/RoomInvitePage.tsx @@ -1,3 +1,4 @@ +import {accountIDSelector} from '@selectors/Session'; import {Str} from 'expensify-common'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; import type {SectionListData} from 'react-native'; @@ -62,6 +63,7 @@ function RoomInvitePage({ const [userSearchPhrase] = useOnyx(ONYXKEYS.ROOM_MEMBERS_USER_SEARCH_PHRASE, {canBeMissing: true}); const [countryCode = CONST.DEFAULT_COUNTRY_CODE] = useOnyx(ONYXKEYS.COUNTRY_CODE, {canBeMissing: false}); const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); + const [currentUserAccountID] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true, selector: accountIDSelector}); const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState(userSearchPhrase ?? ''); const [selectedOptions, setSelectedOptions] = useState([]); const [isSearchingForReports] = useOnyx(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, {initWithStoredValues: false, canBeMissing: true}); @@ -92,7 +94,17 @@ function RoomInvitePage({ return {recentReports: [], personalDetails: [], userToInvite: null, currentUserOption: null}; } - const inviteOptions = getMemberInviteOptions(options.personalDetails, nvpDismissedProductTraining, loginList, betas ?? [], excludedUsers); + const inviteOptions = getMemberInviteOptions( + options.personalDetails, + nvpDismissedProductTraining, + loginList, + betas ?? [], + excludedUsers, + false, + CONST.DEFAULT_COUNTRY_CODE, + currentUserAccountID, + currentUserPersonalDetails.login, + ); // Update selectedOptions with the latest personalDetails information const detailsMap: Record = {}; for (const detail of inviteOptions.personalDetails) { @@ -113,16 +125,33 @@ function RoomInvitePage({ recentReports: [], currentUserOption: null, }; - }, [areOptionsInitialized, betas, excludedUsers, loginList, nvpDismissedProductTraining, options.personalDetails, selectedOptions]); + }, [ + areOptionsInitialized, + betas, + excludedUsers, + loginList, + nvpDismissedProductTraining, + options.personalDetails, + selectedOptions, + currentUserAccountID, + currentUserPersonalDetails.login, + ]); const inviteOptions = useMemo(() => { if (debouncedSearchTerm.trim() === '') { return defaultOptions; } - const filteredOptions = filterAndOrderOptions(defaultOptions, debouncedSearchTerm, countryCode, loginList, {excludeLogins: excludedUsers}); + const filteredOptions = filterAndOrderOptions( + defaultOptions, + debouncedSearchTerm, + countryCode, + loginList, + {excludeLogins: excludedUsers, currentUserEmail: currentUserPersonalDetails.login}, + currentUserAccountID, + ); return filteredOptions; - }, [debouncedSearchTerm, defaultOptions, countryCode, loginList, excludedUsers]); + }, [debouncedSearchTerm, defaultOptions, countryCode, loginList, excludedUsers, currentUserAccountID, currentUserPersonalDetails.login]); const sections = useMemo(() => { const sectionsArr: Sections = []; diff --git a/src/pages/Share/ShareTab.tsx b/src/pages/Share/ShareTab.tsx index 99eab562ba82..a5d694159828 100644 --- a/src/pages/Share/ShareTab.tsx +++ b/src/pages/Share/ShareTab.tsx @@ -1,3 +1,4 @@ +import {accountIDSelector, emailSelector} from '@selectors/Session'; import type {Ref} from 'react'; import React, {useEffect, useImperativeHandle, useMemo, useRef} from 'react'; import {View} from 'react-native'; @@ -50,6 +51,8 @@ function ShareTab({ref}: ShareTabProps) { const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); const [draftComments] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT, {canBeMissing: true}); const [nvpDismissedProductTraining] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, {canBeMissing: true}); + const [currentUserAccountID] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true, selector: accountIDSelector}); + const [currentUserEmail] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true, selector: emailSelector}); useImperativeHandle(ref, () => ({ focus: selectionListRef.current?.focusTextInput, @@ -78,8 +81,10 @@ function ShareTab({ref}: ShareTabProps) { includeUserToInvite: true, countryCode, loginList, + currentUserAccountID, + currentUserEmail, }); - }, [areOptionsInitialized, options, draftComments, nvpDismissedProductTraining, betas, textInputValue, countryCode, loginList]); + }, [areOptionsInitialized, options, draftComments, nvpDismissedProductTraining, betas, textInputValue, countryCode, loginList, currentUserAccountID, currentUserEmail]); const recentReportsOptions = useMemo(() => { if (textInputValue.trim() === '') { diff --git a/src/pages/iou/request/MoneyRequestAccountantSelector.tsx b/src/pages/iou/request/MoneyRequestAccountantSelector.tsx index cbcbe5739374..c9f2484c0fe1 100644 --- a/src/pages/iou/request/MoneyRequestAccountantSelector.tsx +++ b/src/pages/iou/request/MoneyRequestAccountantSelector.tsx @@ -1,4 +1,5 @@ import reportsSelector from '@selectors/Attributes'; +import {accountIDSelector, emailSelector} from '@selectors/Session'; import lodashPick from 'lodash/pick'; import React, {memo, useCallback, useEffect, useMemo} from 'react'; import type {GestureResponderEvent} from 'react-native'; @@ -66,6 +67,8 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType const [draftComments] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT, {canBeMissing: true}); const [nvpDismissedProductTraining] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, {canBeMissing: true}); const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); + const [currentUserEmail] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true, selector: emailSelector}); + const [currentUserAccountID] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true, selector: accountIDSelector}); useEffect(() => { searchInServer(debouncedSearchTerm.trim()); @@ -110,12 +113,20 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType headerMessage: '', }; } - const newOptions = filterAndOrderOptions(defaultOptions, debouncedSearchTerm, countryCode, loginList, { - excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, - maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW, - }); + const newOptions = filterAndOrderOptions( + defaultOptions, + debouncedSearchTerm, + countryCode, + loginList, + { + excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, + maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW, + currentUserEmail, + }, + currentUserAccountID, + ); return newOptions; - }, [areOptionsInitialized, defaultOptions, debouncedSearchTerm, countryCode, loginList]); + }, [areOptionsInitialized, defaultOptions, debouncedSearchTerm, countryCode, loginList, currentUserAccountID, currentUserEmail]); /** * Returns the sections needed for the OptionsSelector @@ -138,6 +149,7 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType true, undefined, reportAttributesDerived, + currentUserAccountID, ); newSections.push(formatResults.section); @@ -158,6 +170,7 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType !isCurrentUser( {...chatOptions.userToInvite, accountID: chatOptions.userToInvite?.accountID ?? CONST.DEFAULT_NUMBER_ID, status: chatOptions.userToInvite?.status ?? undefined}, loginList, + currentUserEmail, ) ) { newSections.push({ @@ -191,6 +204,8 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType translate, loginList, countryCode, + currentUserAccountID, + currentUserEmail, ]); const selectAccountant = useCallback( diff --git a/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx b/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx index 36c8b99b1f8a..4db23b778960 100644 --- a/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx +++ b/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx @@ -1,4 +1,5 @@ import reportsSelector from '@selectors/Attributes'; +import {accountIDSelector, emailSelector} from '@selectors/Session'; import {deepEqual} from 'fast-equals'; import React, {memo, useCallback, useEffect, useMemo} from 'react'; import type {GestureResponderEvent} from 'react-native'; @@ -69,10 +70,15 @@ function MoneyRequestAttendeeSelector({attendees = [], onFinish, onAttendeesAdde const [reportAttributesDerived] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {canBeMissing: true, selector: reportsSelector}); const offlineMessage: string = isOffline ? `${translate('common.youAppearToBeOffline')} ${translate('search.resultsAreLimited')}` : ''; const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); + const [currentUserEmail] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true, selector: emailSelector}); + const [currentUserAccountID] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true, selector: accountIDSelector}); const isPaidGroupPolicy = useMemo(() => isPaidGroupPolicyFn(policy), [policy]); - const recentAttendeeLists = useMemo(() => getFilteredRecentAttendees(personalDetails, attendees, recentAttendees ?? []), [personalDetails, attendees, recentAttendees]); + const recentAttendeeLists = useMemo( + () => getFilteredRecentAttendees(personalDetails, attendees, recentAttendees ?? [], currentUserEmail, currentUserAccountID), + [personalDetails, attendees, recentAttendees, currentUserEmail, currentUserAccountID], + ); const initialSelectedOptions = useMemo( () => attendees.map((attendee) => ({ @@ -217,6 +223,7 @@ function MoneyRequestAttendeeSelector({attendees = [], onFinish, onAttendeesAdde true, undefined, reportAttributesDerived, + currentUserAccountID, ); newSections.push({ @@ -247,6 +254,7 @@ function MoneyRequestAttendeeSelector({attendees = [], onFinish, onAttendeesAdde status: orderedAvailableOptions.userToInvite?.status ?? undefined, }, loginList, + currentUserEmail, ) ) { newSections.push({ @@ -264,7 +272,7 @@ function MoneyRequestAttendeeSelector({attendees = [], onFinish, onAttendeesAdde !!orderedAvailableOptions?.userToInvite, cleanSearchTerm, countryCode, - attendees.some((attendee) => getPersonalDetailSearchTerms(attendee).join(' ').toLowerCase().includes(cleanSearchTerm)), + attendees.some((attendee) => getPersonalDetailSearchTerms(attendee, currentUserAccountID).join(' ').toLowerCase().includes(cleanSearchTerm)), ); return [newSections, headerMessage]; @@ -281,6 +289,8 @@ function MoneyRequestAttendeeSelector({attendees = [], onFinish, onAttendeesAdde loginList, countryCode, translate, + currentUserAccountID, + currentUserEmail, ]); const optionLength = useMemo(() => { diff --git a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx index 3e3d2cc472e4..4290a7f9eb31 100644 --- a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx +++ b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx @@ -1,5 +1,5 @@ import reportsSelector from '@selectors/Attributes'; -import {emailSelector} from '@selectors/Session'; +import {accountIDSelector, emailSelector} from '@selectors/Session'; import {transactionDraftValuesSelector} from '@selectors/TransactionDraft'; import {deepEqual} from 'fast-equals'; import lodashPick from 'lodash/pick'; @@ -118,6 +118,7 @@ function MoneyRequestParticipantsSelector({ const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`]; const [isSearchingForReports] = useOnyx(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, {canBeMissing: true, initWithStoredValues: false}); const [currentUserLogin] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true, selector: emailSelector}); + const [currentUserAccountID] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true, selector: accountIDSelector}); const [reportAttributesDerived] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {canBeMissing: true, selector: reportsSelector}); const [countryCode = CONST.DEFAULT_COUNTRY_CODE] = useOnyx(ONYXKEYS.COUNTRY_CODE, {canBeMissing: false}); const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); @@ -250,7 +251,7 @@ function MoneyRequestParticipantsSelector({ !!availableOptions?.userToInvite, debouncedSearchTerm.trim(), countryCode, - participants.some((participant) => getPersonalDetailSearchTerms(participant).join(' ').toLowerCase().includes(cleanSearchTerm)), + participants.some((participant) => getPersonalDetailSearchTerms(participant, currentUserAccountID).join(' ').toLowerCase().includes(cleanSearchTerm)), ), // eslint-disable-next-line react-compiler/react-compiler // eslint-disable-next-line react-hooks/exhaustive-deps @@ -264,6 +265,7 @@ function MoneyRequestParticipantsSelector({ debouncedSearchTerm, participants, countryCode, + currentUserAccountID, ], ); @@ -292,6 +294,7 @@ function MoneyRequestParticipantsSelector({ true, undefined, reportAttributesDerived, + currentUserAccountID, ); newSections.push(formatResults.section); @@ -332,6 +335,7 @@ function MoneyRequestParticipantsSelector({ status: availableOptions.userToInvite?.status ?? undefined, }, loginList, + currentUserLogin, ) && !isPerDiemRequest ) { @@ -369,6 +373,8 @@ function MoneyRequestParticipantsSelector({ isPerDiemRequest, showImportContacts, inputHelperText, + currentUserAccountID, + currentUserLogin, ]); /** diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx index 633f348a7d2d..1b1e3f4da692 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx @@ -392,7 +392,7 @@ function IOURequestStepScan({ } if (isTestTransaction) { - const managerMcTestParticipant = getManagerMcTestParticipant() ?? {}; + const managerMcTestParticipant = getManagerMcTestParticipant(currentUserPersonalDetails.accountID) ?? {}; let reportIDParam = managerMcTestParticipant.reportID; if (!managerMcTestParticipant.reportID && report?.reportID) { reportIDParam = generateReportID(); diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.tsx index e1f6414fda1e..4dd78b107b7c 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.tsx @@ -448,7 +448,7 @@ function IOURequestStepScan({ } if (isTestTransaction) { - const managerMcTestParticipant = getManagerMcTestParticipant() ?? {}; + const managerMcTestParticipant = getManagerMcTestParticipant(currentUserPersonalDetails.accountID) ?? {}; let reportIDParam = managerMcTestParticipant.reportID; if (!managerMcTestParticipant.reportID && report?.reportID) { reportIDParam = generateReportID(); diff --git a/src/pages/tasks/TaskAssigneeSelectorModal.tsx b/src/pages/tasks/TaskAssigneeSelectorModal.tsx index 0bc735cd1dc7..602812c2e106 100644 --- a/src/pages/tasks/TaskAssigneeSelectorModal.tsx +++ b/src/pages/tasks/TaskAssigneeSelectorModal.tsx @@ -1,5 +1,6 @@ /* eslint-disable es/no-optional-chaining */ import {useRoute} from '@react-navigation/native'; +import {emailSelector} from '@selectors/Session'; import React, {useCallback, useEffect, useMemo} from 'react'; import {InteractionManager, View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; @@ -46,6 +47,7 @@ function TaskAssigneeSelectorModal() { const [countryCode = CONST.DEFAULT_COUNTRY_CODE] = useOnyx(ONYXKEYS.COUNTRY_CODE, {canBeMissing: false}); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); + const [currentUserEmail] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true, selector: emailSelector}); const {searchTerm, debouncedSearchTerm, setSearchTerm, availableOptions, areOptionsInitialized} = useSearchSelector({ selectionMode: CONST.SEARCH_SELECTOR.SELECTION_MODE_SINGLE, @@ -170,7 +172,7 @@ function TaskAssigneeSelectorModal() { assigneePersonalDetails, report.reportID, undefined, // passing null as report because for editing task the report will be task details report page not the actual report where task was created - isCurrentUser({...option, accountID: option?.accountID ?? CONST.DEFAULT_NUMBER_ID, login: option?.login ?? ''}, loginList), + isCurrentUser({...option, accountID: option?.accountID ?? CONST.DEFAULT_NUMBER_ID, login: option?.login ?? ''}, loginList, currentUserEmail), ); // Pass through the selected assignee editTaskAssignee( @@ -196,7 +198,7 @@ function TaskAssigneeSelectorModal() { assigneePersonalDetails, task?.shareDestination ?? '', undefined, // passing null as report is null in this condition - isCurrentUser({...option, accountID: option?.accountID ?? CONST.DEFAULT_NUMBER_ID, login: option?.login ?? undefined}, loginList), + isCurrentUser({...option, accountID: option?.accountID ?? CONST.DEFAULT_NUMBER_ID, login: option?.login ?? undefined}, loginList, currentUserEmail), ); // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => { @@ -204,7 +206,7 @@ function TaskAssigneeSelectorModal() { }); } }, - [allPersonalDetails, report, currentUserPersonalDetails.accountID, loginList, parentReport, hasOutstandingChildTask, task?.shareDestination, backTo], + [allPersonalDetails, report, currentUserPersonalDetails.accountID, loginList, currentUserEmail, parentReport, hasOutstandingChildTask, task?.shareDestination, backTo], ); const handleBackButtonPress = useCallback(() => Navigation.goBack(!route.params?.reportID ? ROUTES.NEW_TASK.getRoute(backTo) : backTo), [route.params, backTo]); diff --git a/tests/perf-test/OptionsListUtils.perf-test.ts b/tests/perf-test/OptionsListUtils.perf-test.ts index 8b23f320a2aa..29573a4d22dd 100644 --- a/tests/perf-test/OptionsListUtils.perf-test.ts +++ b/tests/perf-test/OptionsListUtils.perf-test.ts @@ -26,6 +26,9 @@ const PERSONAL_DETAILS_COUNT = 1000; const SELECTED_OPTIONS_COUNT = 1000; const RECENT_REPORTS_COUNT = 100; +const MOCK_CURRENT_USER_ACCOUNT_ID = 1; +const MOCK_CURRENT_USER_EMAIL = 'testuser@example.com'; + const reports = createCollection( (item) => `${ONYXKEYS.COLLECTION.REPORT}${item.reportID}`, (index) => ({ @@ -112,22 +115,40 @@ describe('OptionsListUtils', () => { /* Testing getSearchOptions */ test('[OptionsListUtils] getSearchOptions', async () => { await waitForBatchedUpdates(); - await measureFunction(() => getSearchOptions({options, betas: mockedBetas, draftComments: {}, nvpDismissedProductTraining, loginList})); + await measureFunction(() => + getSearchOptions({ + options, + betas: mockedBetas, + draftComments: {}, + nvpDismissedProductTraining, + loginList, + currentUserAccountID: MOCK_CURRENT_USER_ACCOUNT_ID, + currentUserEmail: MOCK_CURRENT_USER_EMAIL, + }), + ); }); /* Testing getFilteredOptions */ test('[OptionsListUtils] getFilteredOptions with search value', async () => { await waitForBatchedUpdates(); - const formattedOptions = getValidOptions({reports: options.reports, personalDetails: options.personalDetails}, {}, nvpDismissedProductTraining, loginList, ValidOptionsConfig); + const formattedOptions = getValidOptions({reports: options.reports, personalDetails: options.personalDetails}, {}, nvpDismissedProductTraining, loginList, { + ...ValidOptionsConfig, + currentUserAccountID: MOCK_CURRENT_USER_ACCOUNT_ID, + currentUserEmail: MOCK_CURRENT_USER_EMAIL, + }); await measureFunction(() => { - filterAndOrderOptions(formattedOptions, SEARCH_VALUE, COUNTRY_CODE, loginList); + filterAndOrderOptions(formattedOptions, SEARCH_VALUE, COUNTRY_CODE, loginList, {currentUserEmail: MOCK_CURRENT_USER_EMAIL}, MOCK_CURRENT_USER_ACCOUNT_ID); }); }); test('[OptionsListUtils] getFilteredOptions with empty search value', async () => { await waitForBatchedUpdates(); - const formattedOptions = getValidOptions({reports: options.reports, personalDetails: options.personalDetails}, {}, nvpDismissedProductTraining, loginList, ValidOptionsConfig); + const formattedOptions = getValidOptions({reports: options.reports, personalDetails: options.personalDetails}, {}, nvpDismissedProductTraining, loginList, { + ...ValidOptionsConfig, + currentUserAccountID: MOCK_CURRENT_USER_ACCOUNT_ID, + currentUserEmail: MOCK_CURRENT_USER_EMAIL, + }); await measureFunction(() => { - filterAndOrderOptions(formattedOptions, '', COUNTRY_CODE, loginList); + filterAndOrderOptions(formattedOptions, '', COUNTRY_CODE, loginList, {currentUserEmail: MOCK_CURRENT_USER_EMAIL}, MOCK_CURRENT_USER_ACCOUNT_ID); }); }); @@ -148,6 +169,8 @@ describe('OptionsListUtils', () => { includeSelfDM: true, searchString: '', includeUserToInvite: false, + currentUserAccountID: MOCK_CURRENT_USER_ACCOUNT_ID, + currentUserEmail: MOCK_CURRENT_USER_EMAIL, }), ); }); @@ -155,7 +178,19 @@ describe('OptionsListUtils', () => { /* Testing getMemberInviteOptions */ test('[OptionsListUtils] getMemberInviteOptions', async () => { await waitForBatchedUpdates(); - await measureFunction(() => getMemberInviteOptions(options.personalDetails, nvpDismissedProductTraining, loginList, mockedBetas)); + await measureFunction(() => + getMemberInviteOptions( + options.personalDetails, + nvpDismissedProductTraining, + loginList, + mockedBetas, + {}, + false, + COUNTRY_CODE, + MOCK_CURRENT_USER_ACCOUNT_ID, + MOCK_CURRENT_USER_EMAIL, + ), + ); }); test('[OptionsListUtils] worst case scenario with a search term that matches a subset of selectedOptions, filteredRecentReports, and filteredPersonalDetails', async () => { @@ -202,6 +237,9 @@ describe('OptionsListUtils', () => { Object.values(filteredPersonalDetails), mockedPersonalDetails, true, + undefined, + undefined, + MOCK_CURRENT_USER_ACCOUNT_ID, ), ); }); @@ -212,6 +250,8 @@ describe('OptionsListUtils', () => { const mockedPersonalDetails = getMockedPersonalDetails(PERSONAL_DETAILS_COUNT); await waitForBatchedUpdates(); - await measureFunction(() => formatSectionsFromSearchTerm('', Object.values(selectedOptions), [], [], mockedPersonalDetails, true)); + await measureFunction(() => + formatSectionsFromSearchTerm('', Object.values(selectedOptions), [], [], mockedPersonalDetails, true, undefined, undefined, MOCK_CURRENT_USER_ACCOUNT_ID), + ); }); }); diff --git a/tests/perf-test/SidebarUtils.perf-test.ts b/tests/perf-test/SidebarUtils.perf-test.ts index 9c1db3ad522c..ab45ab1c4642 100644 --- a/tests/perf-test/SidebarUtils.perf-test.ts +++ b/tests/perf-test/SidebarUtils.perf-test.ts @@ -90,6 +90,7 @@ describe('SidebarUtils', () => { localeCompare, lastActionReport: undefined, isReportArchived: undefined, + currentUserAccountID: 1, }), ); }); diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index e4dfa68ebdf3..4c1329921b05 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -640,7 +640,15 @@ describe('OptionsListUtils', () => { it('should return all options when no search value is provided', () => { // Given a set of options // When we call getSearchOptions with all betas - const results = getSearchOptions({options: OPTIONS, draftComments: {}, nvpDismissedProductTraining, loginList, betas: [CONST.BETAS.ALL]}); + const results = getSearchOptions({ + options: OPTIONS, + draftComments: {}, + nvpDismissedProductTraining, + loginList, + betas: [CONST.BETAS.ALL], + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // Then all personal details (including those that have reports) should be returned expect(results.personalDetails.length).toBe(10); @@ -665,6 +673,8 @@ describe('OptionsListUtils', () => { includeRecentReports: true, includeCurrentUser: true, loginList, + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', }); // Then the current user should be included in personalDetails @@ -692,6 +702,8 @@ describe('OptionsListUtils', () => { includeUserToInvite: false, includeRecentReports: true, loginList, + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', }); // Then the current user should not be included in personalDetails @@ -715,6 +727,7 @@ describe('OptionsListUtils', () => { {}, nvpDismissedProductTraining, loginList, + {currentUserAccountID: 2, currentUserEmail: 'tonystark@expensify.com'}, ); // When we call orderOptions() results = orderOptions(results); @@ -751,6 +764,7 @@ describe('OptionsListUtils', () => { {}, nvpDismissedProductTraining, loginList, + {currentUserAccountID: 2, currentUserEmail: 'tonystark@expensify.com'}, ); // When we call orderOptions() results = orderOptions(results); @@ -778,7 +792,10 @@ describe('OptionsListUtils', () => { it('should return empty options when no reports or personal details are provided', () => { // Given empty arrays of reports and personalDetails // When we call getValidOptions() - const results = getValidOptions({reports: [], personalDetails: []}, {}, nvpDismissedProductTraining, loginList); + const results = getValidOptions({reports: [], personalDetails: []}, {}, nvpDismissedProductTraining, loginList, { + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // Then the result should be empty expect(results.personalDetails).toEqual([]); @@ -792,7 +809,10 @@ describe('OptionsListUtils', () => { it('should include Concierge by default in results', () => { // Given a set of reports and personalDetails that includes Concierge // When we call getValidOptions() - const results = getValidOptions({reports: OPTIONS_WITH_CONCIERGE.reports, personalDetails: OPTIONS_WITH_CONCIERGE.personalDetails}, {}, nvpDismissedProductTraining, loginList); + const results = getValidOptions({reports: OPTIONS_WITH_CONCIERGE.reports, personalDetails: OPTIONS_WITH_CONCIERGE.personalDetails}, {}, nvpDismissedProductTraining, loginList, { + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // Then the result should include all personalDetails except the currently logged in user expect(results.personalDetails.length).toBe(Object.values(OPTIONS_WITH_CONCIERGE.personalDetails).length - 1); @@ -813,6 +833,8 @@ describe('OptionsListUtils', () => { loginList, { excludeLogins: {[CONST.EMAIL.CONCIERGE]: true}, + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', }, ); @@ -827,6 +849,8 @@ describe('OptionsListUtils', () => { // When we call getValidOptions() const results = getValidOptions({reports: OPTIONS_WITH_CHRONOS.reports, personalDetails: OPTIONS_WITH_CHRONOS.personalDetails}, {}, nvpDismissedProductTraining, loginList, { excludeLogins: {[CONST.EMAIL.CHRONOS]: true}, + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', }); // Then the result should include all personalDetails except the currently logged in user and Chronos @@ -848,6 +872,8 @@ describe('OptionsListUtils', () => { loginList, { excludeLogins: {[CONST.EMAIL.RECEIPTS]: true}, + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', }, ); @@ -874,6 +900,8 @@ describe('OptionsListUtils', () => { includeP2P: true, canShowManagerMcTest: true, betas: [CONST.BETAS.NEWDOT_MANAGER_MCTEST], + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', }, ); @@ -895,6 +923,8 @@ describe('OptionsListUtils', () => { includeP2P: true, canShowManagerMcTest: false, betas: [CONST.BETAS.NEWDOT_MANAGER_MCTEST], + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', }, ); @@ -921,7 +951,7 @@ describe('OptionsListUtils', () => { {}, nvpDismissedProductTraining, loginList, - {includeP2P: true, canShowManagerMcTest: true, betas: [CONST.BETAS.NEWDOT_MANAGER_MCTEST]}, + {includeP2P: true, canShowManagerMcTest: true, betas: [CONST.BETAS.NEWDOT_MANAGER_MCTEST], currentUserAccountID: 2, currentUserEmail: 'tonystark@expensify.com'}, ); // Then the result should include all personalDetails except the currently logged in user and Manager McTest @@ -1133,7 +1163,10 @@ describe('OptionsListUtils', () => { it('should exclude users with recent reports from personalDetails', () => { // Given a set of reports and personalDetails // When we call getValidOptions with no search value - const results = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList); + const results = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList, { + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); const reportLogins = new Set(results.recentReports.map((reportOption) => reportOption.login)); const personalDetailsOverlapWithReports = results.personalDetails.every((personalDetailOption) => reportLogins.has(personalDetailOption.login)); @@ -1158,7 +1191,10 @@ describe('OptionsListUtils', () => { it('should include Concierge in the results by default', () => { // Given a set of report and personalDetails that include Concierge // When we call getValidOptions() - const results = getValidOptions({reports: OPTIONS_WITH_CONCIERGE.reports, personalDetails: OPTIONS_WITH_CONCIERGE.personalDetails}, {}, nvpDismissedProductTraining, loginList); + const results = getValidOptions({reports: OPTIONS_WITH_CONCIERGE.reports, personalDetails: OPTIONS_WITH_CONCIERGE.personalDetails}, {}, nvpDismissedProductTraining, loginList, { + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // Then the result should include all personalDetails except the currently logged in user expect(results.personalDetails.length).toBe(Object.values(OPTIONS_WITH_CONCIERGE.personalDetails).length - 1); @@ -1179,6 +1215,8 @@ describe('OptionsListUtils', () => { loginList, { excludeLogins: {[CONST.EMAIL.CONCIERGE]: true}, + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', }, ); @@ -1194,6 +1232,8 @@ describe('OptionsListUtils', () => { // When we call getValidOptions() with excludeLogins param const results = getValidOptions({reports: OPTIONS_WITH_CHRONOS.reports, personalDetails: OPTIONS_WITH_CHRONOS.personalDetails}, {}, nvpDismissedProductTraining, loginList, { excludeLogins: {[CONST.EMAIL.CHRONOS]: true}, + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', }); // Then the result should include all personalDetails except the currently logged in user and Chronos @@ -1216,6 +1256,8 @@ describe('OptionsListUtils', () => { loginList, { excludeLogins: {[CONST.EMAIL.RECEIPTS]: true}, + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', }, ); @@ -1241,7 +1283,10 @@ describe('OptionsListUtils', () => { it('should show all reports when maxRecentReportElements is not specified', () => { // Given a set of reports and personalDetails // When we call getValidOptions without maxRecentReportElements - const resultsWithoutLimit = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList); + const resultsWithoutLimit = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList, { + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); const resultsWithLimit = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList, { maxRecentReportElements: 2, }); @@ -1253,9 +1298,14 @@ describe('OptionsListUtils', () => { it('should not affect personalDetails count when maxRecentReportElements is specified', () => { // Given a set of reports and personalDetails // When we call getValidOptions with and without maxRecentReportElements - const resultsWithoutLimit = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList); + const resultsWithoutLimit = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList, { + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); const resultsWithLimit = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList, { maxRecentReportElements: 2, + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', }); // Then personalDetails should remain the same regardless of maxRecentReportElements @@ -1348,7 +1398,7 @@ describe('OptionsListUtils', () => { it('should sort personal details alphabetically', () => { // Given a set of personalDetails // When we call getMemberInviteOptions - const results = getMemberInviteOptions(OPTIONS.personalDetails, nvpDismissedProductTraining, loginList, []); + const results = getMemberInviteOptions(OPTIONS.personalDetails, nvpDismissedProductTraining, loginList, [], {}, false, COUNTRY_CODE, 2, 'tonystark@expensify.com'); // Then personal details should be sorted alphabetically expect(results.personalDetails.at(0)?.text).toBe('Black Panther'); @@ -1362,9 +1412,9 @@ describe('OptionsListUtils', () => { it('should return correct display name', () => { renderLocaleContextProvider(); // Given two different personal details - // When we call getLastActorDisplayName - const result1 = getLastActorDisplayName(PERSONAL_DETAILS['2']); - const result2 = getLastActorDisplayName(PERSONAL_DETAILS['3']); + // When we call getLastActorDisplayName with currentUserAccountID = 2 + const result1 = getLastActorDisplayName(PERSONAL_DETAILS['2'], 2); + const result2 = getLastActorDisplayName(PERSONAL_DETAILS['3'], 2); // We should expect the display names to be the same as the personal details expect(result1).toBe('You'); @@ -1378,7 +1428,7 @@ describe('OptionsListUtils', () => { const report = REPORTS['1']; const lastActorDetails = PERSONAL_DETAILS['3']; - const result = shouldShowLastActorDisplayName(report, lastActorDetails, undefined); + const result = shouldShowLastActorDisplayName(report, lastActorDetails, undefined, 2); expect(result).toBe(false); }); @@ -1387,7 +1437,7 @@ describe('OptionsListUtils', () => { const report = REPORTS['1']; const lastAction = createRandomReportAction(1); - const result = shouldShowLastActorDisplayName(report, null, lastAction); + const result = shouldShowLastActorDisplayName(report, null, lastAction, 2); expect(result).toBe(false); }); @@ -1398,7 +1448,7 @@ describe('OptionsListUtils', () => { const lastAction = createRandomReportAction(1); // When we call shouldShowLastActorDisplayName with a self DM report - const result = shouldShowLastActorDisplayName(report, lastActorDetails, lastAction); + const result = shouldShowLastActorDisplayName(report, lastActorDetails, lastAction, 2); expect(result).toBe(false); }); @@ -1411,7 +1461,7 @@ describe('OptionsListUtils', () => { const lastActorDetails = PERSONAL_DETAILS['3']; const lastAction = createRandomReportAction(1); - const result = shouldShowLastActorDisplayName(report, lastActorDetails, lastAction); + const result = shouldShowLastActorDisplayName(report, lastActorDetails, lastAction, 2); expect(result).toBe(false); }); @@ -1424,7 +1474,7 @@ describe('OptionsListUtils', () => { actionName: CONST.REPORT.ACTIONS.TYPE.IOU, }; - const result = shouldShowLastActorDisplayName(report, lastActorDetails, lastAction); + const result = shouldShowLastActorDisplayName(report, lastActorDetails, lastAction, 2); expect(result).toBe(false); }); @@ -1443,7 +1493,7 @@ describe('OptionsListUtils', () => { actionName: CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW, }; - const result = shouldShowLastActorDisplayName(report, lastActorDetails, lastAction); + const result = shouldShowLastActorDisplayName(report, lastActorDetails, lastAction, 2); expect(result).toBe(false); }); @@ -1459,7 +1509,7 @@ describe('OptionsListUtils', () => { }; const lastAction = createRandomReportAction(1); - const result = shouldShowLastActorDisplayName(report, lastActorDetails, lastAction); + const result = shouldShowLastActorDisplayName(report, lastActorDetails, lastAction, 2); expect(result).toBe(false); }); @@ -1474,7 +1524,7 @@ describe('OptionsListUtils', () => { }; // When we call shouldShowLastActorDisplayName with all valid conditions - const result = shouldShowLastActorDisplayName(report, lastActorDetails, lastAction); + const result = shouldShowLastActorDisplayName(report, lastActorDetails, lastAction, 2); expect(result).toBe(true); }); @@ -1488,7 +1538,7 @@ describe('OptionsListUtils', () => { actionName: CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT, }; - const result = shouldShowLastActorDisplayName(report, lastActorDetails, lastAction); + const result = shouldShowLastActorDisplayName(report, lastActorDetails, lastAction, 2); expect(result).toBe(true); }); @@ -1503,7 +1553,7 @@ describe('OptionsListUtils', () => { }; // When we call shouldShowLastActorDisplayName with the current user as last actor - const result = shouldShowLastActorDisplayName(report, lastActorDetails, lastAction); + const result = shouldShowLastActorDisplayName(report, lastActorDetails, lastAction, 2); expect(result).toBe(true); }); }); @@ -1532,9 +1582,17 @@ describe('OptionsListUtils', () => { it('should return all options when search is empty', () => { // Given a set of options // When we call getSearchOptions with all betas - const options = getSearchOptions({options: OPTIONS, draftComments: {}, nvpDismissedProductTraining, loginList, betas: [CONST.BETAS.ALL]}); + const options = getSearchOptions({ + options: OPTIONS, + draftComments: {}, + nvpDismissedProductTraining, + loginList, + betas: [CONST.BETAS.ALL], + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we pass the returned options to filterAndOrderOptions with an empty search value - const filteredOptions = filterAndOrderOptions(options, '', COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, '', COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then all options should be returned expect(filteredOptions.recentReports.length + filteredOptions.personalDetails.length).toBe(14); @@ -1544,9 +1602,17 @@ describe('OptionsListUtils', () => { const searchText = 'man'; // Given a set of options // When we call getSearchOptions with all betas - const options = getSearchOptions({options: OPTIONS, draftComments: {}, nvpDismissedProductTraining, loginList, betas: [CONST.BETAS.ALL]}); + const options = getSearchOptions({ + options: OPTIONS, + draftComments: {}, + nvpDismissedProductTraining, + loginList, + betas: [CONST.BETAS.ALL], + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we pass the returned options to filterAndOrderOptions with a search value and sortByReportTypeInSearch param - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, {sortByReportTypeInSearch: true}); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, {sortByReportTypeInSearch: true, currentUserEmail: 'tonystark@expensify.com'}, 2); // Then we expect all options to be part of the recentReports list and reports should be first: expect(filteredOptions.personalDetails.length).toBe(0); @@ -1563,9 +1629,17 @@ describe('OptionsListUtils', () => { const searchText = 'mistersinister@marauders.com'; // Given a set of options // When we call getSearchOptions with all betas - const options = getSearchOptions({options: OPTIONS, draftComments: {}, nvpDismissedProductTraining, loginList, betas: [CONST.BETAS.ALL]}); + const options = getSearchOptions({ + options: OPTIONS, + draftComments: {}, + nvpDismissedProductTraining, + loginList, + betas: [CONST.BETAS.ALL], + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we pass the returned options to filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then only one report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -1577,9 +1651,17 @@ describe('OptionsListUtils', () => { const searchText = 'Archived'; // Given a set of options // When we call getSearchOptions with all betas - const options = getSearchOptions({options: OPTIONS, draftComments: {}, nvpDismissedProductTraining, loginList, betas: [CONST.BETAS.ALL]}); + const options = getSearchOptions({ + options: OPTIONS, + draftComments: {}, + nvpDismissedProductTraining, + loginList, + betas: [CONST.BETAS.ALL], + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we pass the returned options to filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then only one report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -1593,9 +1675,17 @@ describe('OptionsListUtils', () => { // Given a set of options created from PERSONAL_DETAILS_WITH_PERIODS const OPTIONS_WITH_PERIODS = createOptionList(PERSONAL_DETAILS_WITH_PERIODS, REPORTS); // When we call getSearchOptions with all betas - const options = getSearchOptions({options: OPTIONS_WITH_PERIODS, draftComments: {}, nvpDismissedProductTraining, loginList, betas: [CONST.BETAS.ALL]}); + const options = getSearchOptions({ + options: OPTIONS_WITH_PERIODS, + draftComments: {}, + nvpDismissedProductTraining, + loginList, + betas: [CONST.BETAS.ALL], + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we pass the returned options to filterAndOrderOptions with a search value and sortByReportTypeInSearch param - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, {sortByReportTypeInSearch: true}); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, {sortByReportTypeInSearch: true, currentUserEmail: 'tonystark@expensify.com'}, 2); // Then only one report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -1607,9 +1697,17 @@ describe('OptionsListUtils', () => { const searchText = 'avengers'; // Given a set of options with workspace rooms // When we call getSearchOptions with all betas - const options = getSearchOptions({options: OPTIONS_WITH_WORKSPACE_ROOM, draftComments: {}, nvpDismissedProductTraining, loginList, betas: [CONST.BETAS.ALL]}); + const options = getSearchOptions({ + options: OPTIONS_WITH_WORKSPACE_ROOM, + draftComments: {}, + nvpDismissedProductTraining, + loginList, + betas: [CONST.BETAS.ALL], + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we pass the returned options to filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then only one report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -1620,9 +1718,17 @@ describe('OptionsListUtils', () => { it('should put exact match by login on the top of the list', () => { const searchText = 'reedrichards@expensify.com'; // Given a set of options with all betas - const options = getSearchOptions({options: OPTIONS, draftComments: {}, nvpDismissedProductTraining, loginList, betas: [CONST.BETAS.ALL]}); + const options = getSearchOptions({ + options: OPTIONS, + draftComments: {}, + nvpDismissedProductTraining, + loginList, + betas: [CONST.BETAS.ALL], + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we pass the returned options to filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then only one report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -1635,9 +1741,17 @@ describe('OptionsListUtils', () => { // Given a set of options with chat rooms const OPTIONS_WITH_CHAT_ROOMS = createOptionList(PERSONAL_DETAILS, REPORTS_WITH_CHAT_ROOM); // When we call getSearchOptions with all betas - const options = getSearchOptions({options: OPTIONS_WITH_CHAT_ROOMS, draftComments: {}, nvpDismissedProductTraining, loginList, betas: [CONST.BETAS.ALL]}); + const options = getSearchOptions({ + options: OPTIONS_WITH_CHAT_ROOMS, + draftComments: {}, + nvpDismissedProductTraining, + loginList, + betas: [CONST.BETAS.ALL], + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we pass the returned options to filterAndOrderOptions with a search value - const filterOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList); + const filterOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then only two reports should be returned expect(filterOptions.recentReports.length).toBe(2); @@ -1649,9 +1763,16 @@ describe('OptionsListUtils', () => { renderLocaleContextProvider(); const searchText = 'fantastic'; // Given a set of options - const options = getSearchOptions({options: OPTIONS, draftComments: {}, nvpDismissedProductTraining, loginList}); + const options = getSearchOptions({ + options: OPTIONS, + draftComments: {}, + nvpDismissedProductTraining, + loginList, + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we call filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then only three reports should be returned expect(filteredOptions.recentReports.length).toBe(3); @@ -1664,9 +1785,16 @@ describe('OptionsListUtils', () => { it('should return the user to invite when the search value is a valid, non-existent email', () => { const searchText = 'test@email.com'; // Given a set of options - const options = getSearchOptions({options: OPTIONS, draftComments: {}, loginList, nvpDismissedProductTraining}); + const options = getSearchOptions({ + options: OPTIONS, + draftComments: {}, + loginList, + nvpDismissedProductTraining, + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we call filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then the user to invite should be returned expect(filteredOptions.userToInvite?.login).toBe(searchText); @@ -1679,7 +1807,14 @@ describe('OptionsListUtils', () => { excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, }); // When we call filterAndOrderOptions with a search value and excluded logins list - const filterOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, {excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT}); + const filterOptions = filterAndOrderOptions( + options, + searchText, + COUNTRY_CODE, + loginList, + {excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, currentUserEmail: 'tonystark@expensify.com'}, + 2, + ); // Then no personal details should be returned expect(filterOptions.recentReports.length).toBe(0); @@ -1688,9 +1823,23 @@ describe('OptionsListUtils', () => { it('should return the user to invite when the search value is a valid, non-existent email and the user is not excluded', () => { const searchText = 'test@email.com'; // Given a set of options - const options = getSearchOptions({options: OPTIONS, draftComments: {}, loginList, nvpDismissedProductTraining}); + const options = getSearchOptions({ + options: OPTIONS, + draftComments: {}, + loginList, + nvpDismissedProductTraining, + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we call filterAndOrderOptions with a search value and excludeLogins - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, {excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT}); + const filteredOptions = filterAndOrderOptions( + options, + searchText, + COUNTRY_CODE, + loginList, + {excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, currentUserEmail: 'tonystark@expensify.com'}, + 2, + ); // Then the user to invite should be returned expect(filteredOptions.userToInvite?.login).toBe(searchText); @@ -1699,16 +1848,23 @@ describe('OptionsListUtils', () => { it('should return limited amount of recent reports if the limit is set', () => { const searchText = ''; // Given a set of options - const options = getSearchOptions({options: OPTIONS, draftComments: {}, loginList, nvpDismissedProductTraining}); + const options = getSearchOptions({ + options: OPTIONS, + draftComments: {}, + loginList, + nvpDismissedProductTraining, + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we call filterAndOrderOptions with a search value and maxRecentReportsToShow set to 2 - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, {maxRecentReportsToShow: 2}); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, {maxRecentReportsToShow: 2, currentUserEmail: 'tonystark@expensify.com'}, 2); // Then only two reports should be returned expect(filteredOptions.recentReports.length).toBe(2); // Note: in the past maxRecentReportsToShow: 0 would return all recent reports, this has changed, and is expected to return none now // When we call filterAndOrderOptions with a search value and maxRecentReportsToShow set to 0 - const limitToZeroOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, {maxRecentReportsToShow: 0}); + const limitToZeroOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, {maxRecentReportsToShow: 0, currentUserEmail: 'tonystark@expensify.com'}, 2); // Then no reports should be returned expect(limitToZeroOptions.recentReports.length).toBe(0); @@ -1717,9 +1873,17 @@ describe('OptionsListUtils', () => { it('should not return any user to invite if email exists on the personal details list', () => { const searchText = 'natasharomanoff@expensify.com'; // Given a set of options with all betas - const options = getSearchOptions({options: OPTIONS, draftComments: {}, nvpDismissedProductTraining, loginList, betas: [CONST.BETAS.ALL]}); + const options = getSearchOptions({ + options: OPTIONS, + draftComments: {}, + nvpDismissedProductTraining, + loginList, + betas: [CONST.BETAS.ALL], + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we call filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then there should be one matching result expect(filteredOptions.personalDetails.length).toBe(1); @@ -1729,9 +1893,9 @@ describe('OptionsListUtils', () => { it('should not return any options if search value does not match any personal details (getMemberInviteOptions)', () => { // Given a set of options - const options = getMemberInviteOptions(OPTIONS.personalDetails, nvpDismissedProductTraining, loginList, []); + const options = getMemberInviteOptions(OPTIONS.personalDetails, nvpDismissedProductTraining, loginList, [], {}, false, COUNTRY_CODE, 2, 'tonystark@expensify.com'); // When we call filterAndOrderOptions with a search value that does not match any personal details - const filteredOptions = filterAndOrderOptions(options, 'magneto', COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, 'magneto', COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then no personal details should be returned expect(filteredOptions.personalDetails.length).toBe(0); @@ -1739,9 +1903,9 @@ describe('OptionsListUtils', () => { it('should return one personal detail if search value matches an email (getMemberInviteOptions)', () => { // Given a set of options - const options = getMemberInviteOptions(OPTIONS.personalDetails, nvpDismissedProductTraining, loginList, []); + const options = getMemberInviteOptions(OPTIONS.personalDetails, nvpDismissedProductTraining, loginList, [], {}, false, COUNTRY_CODE, 2, 'tonystark@expensify.com'); // When we call filterAndOrderOptions with a search value that matches an email - const filteredOptions = filterAndOrderOptions(options, 'peterparker@expensify.com', COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, 'peterparker@expensify.com', COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then one personal detail should be returned expect(filteredOptions.personalDetails.length).toBe(1); @@ -1774,7 +1938,7 @@ describe('OptionsListUtils', () => { includeUserToInvite: false, }); // When we pass the returned options to filterAndOrderOptions with a search value that does not match the group chat name - const filteredOptions = filterAndOrderOptions(options, 'mutants', COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, 'mutants', COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then no recent reports should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -1807,7 +1971,7 @@ describe('OptionsListUtils', () => { includeUserToInvite: false, }); // When we pass the returned options to filterAndOrderOptions with a search value that matches the group chat name - const filteredOptions = filterAndOrderOptions(options, 'Avengers Room', COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, 'Avengers Room', COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then one recent report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -1840,7 +2004,7 @@ describe('OptionsListUtils', () => { includeUserToInvite: false, }); // When we pass the returned options to filterAndOrderOptions with a search value that does not match the group chat name - const filteredOptions = filterAndOrderOptions(options, 'Mutants Lair', COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, 'Mutants Lair', COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then no recent reports should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -1848,9 +2012,12 @@ describe('OptionsListUtils', () => { it('should show the option from personal details when searching for personal detail with no existing report', () => { // Given a set of options - const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList); + const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList, { + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we call filterAndOrderOptions with a search value that matches a personal detail with no existing report - const filteredOptions = filterAndOrderOptions(options, 'hulk', COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, 'hulk', COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then no recent reports should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -1862,9 +2029,12 @@ describe('OptionsListUtils', () => { it('should not return any options or user to invite if there are no search results and the string does not match a potential email or phone', () => { // Given a set of options - const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList); + const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList, { + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports - const filteredOptions = filterAndOrderOptions(options, 'marc@expensify', COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, 'marc@expensify', COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -1875,9 +2045,12 @@ describe('OptionsListUtils', () => { it('should not return any options but should return an user to invite if no matching options exist and the search value is a potential email', () => { // Given a set of options - const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList); + const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList, { + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports - const filteredOptions = filterAndOrderOptions(options, 'marc@expensify.com', COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, 'marc@expensify.com', COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -1888,9 +2061,12 @@ describe('OptionsListUtils', () => { it('should return user to invite when search term has a period with options for it that do not contain the period', () => { // Given a set of options - const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList); + const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList, { + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite - const filteredOptions = filterAndOrderOptions(options, 'peter.parker@expensify.com', COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, 'peter.parker@expensify.com', COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then no recent reports should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -1900,9 +2076,12 @@ describe('OptionsListUtils', () => { it('should return user which has displayName with accent mark when search value without accent mark', () => { // Given a set of options - const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList); + const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList, { + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we call filterAndOrderOptions with a search value without accent mark - const filteredOptions = filterAndOrderOptions(options, 'Timothee', COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, 'Timothee', COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then one personalDetails with accent mark should be returned expect(filteredOptions.personalDetails.length).toBe(1); @@ -1910,9 +2089,12 @@ describe('OptionsListUtils', () => { it('should not return options but should return an user to invite if no matching options exist and the search value is a potential phone number', () => { // Given a set of options - const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList); + const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList, { + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite - const filteredOptions = filterAndOrderOptions(options, '5005550006', COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, '5005550006', COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -1925,9 +2107,12 @@ describe('OptionsListUtils', () => { it('should not return options but should return an user to invite if no matching options exist and the search value is a potential phone number with country code added', () => { // Given a set of options - const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList); + const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList, { + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite - const filteredOptions = filterAndOrderOptions(options, '+15005550006', COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, '+15005550006', COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -1940,9 +2125,12 @@ describe('OptionsListUtils', () => { it('should not return options but should return an user to invite if no matching options exist and the search value is a potential phone number with special characters added', () => { // Given a set of options - const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList); + const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList, { + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite - const filteredOptions = filterAndOrderOptions(options, '+1 (800)324-3233', COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, '+1 (800)324-3233', COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -1955,9 +2143,12 @@ describe('OptionsListUtils', () => { it('should not return any options or user to invite if contact number contains alphabet characters', () => { // Given a set of options - const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList); + const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList, { + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports - const filteredOptions = filterAndOrderOptions(options, '998243aaaa', COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, '998243aaaa', COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -1968,9 +2159,12 @@ describe('OptionsListUtils', () => { it('should not return any options if search value does not match any personal details', () => { // Given a set of options - const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList); + const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList, { + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we call filterAndOrderOptions with a search value that does not match any personal details - const filteredOptions = filterAndOrderOptions(options, 'magneto', COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, 'magneto', COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then no personal details should be returned expect(filteredOptions.personalDetails.length).toBe(0); @@ -1978,9 +2172,19 @@ describe('OptionsListUtils', () => { it('should return one recent report and no personal details if a search value provides an email', () => { // Given a set of options - const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList); + const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList, { + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we call filterAndOrderOptions with a search value that matches an email - const filteredOptions = filterAndOrderOptions(options, 'peterparker@expensify.com', COUNTRY_CODE, loginList, {sortByReportTypeInSearch: true}); + const filteredOptions = filterAndOrderOptions( + options, + 'peterparker@expensify.com', + COUNTRY_CODE, + loginList, + {sortByReportTypeInSearch: true, currentUserEmail: 'tonystark@expensify.com'}, + 2, + ); // Then one recent report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -1992,9 +2196,12 @@ describe('OptionsListUtils', () => { it('should return all matching reports and personal details', () => { // Given a set of options - const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList); + const options = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, nvpDismissedProductTraining, loginList, { + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we call filterAndOrderOptions with a search value that matches both reports and personal details and maxRecentReportsToShow param - const filteredOptions = filterAndOrderOptions(options, '.com', COUNTRY_CODE, loginList, {maxRecentReportsToShow: 5}); + const filteredOptions = filterAndOrderOptions(options, '.com', COUNTRY_CODE, loginList, {maxRecentReportsToShow: 5, currentUserEmail: 'tonystark@expensify.com'}, 2); // Then there should be 4 matching personal details expect(filteredOptions.personalDetails.length).toBe(5); @@ -2009,9 +2216,16 @@ describe('OptionsListUtils', () => { it('should return matching option when searching (getSearchOptions)', () => { // Given a set of options - const options = getSearchOptions({options: OPTIONS, draftComments: {}, nvpDismissedProductTraining, loginList}); + const options = getSearchOptions({ + options: OPTIONS, + draftComments: {}, + nvpDismissedProductTraining, + loginList, + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we call filterAndOrderOptions with a search value that matches a personal detail - const filteredOptions = filterAndOrderOptions(options, 'spider', COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, 'spider', COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then one personal detail should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -2021,9 +2235,16 @@ describe('OptionsListUtils', () => { it('should return latest lastVisibleActionCreated item on top when search value matches multiple items (getSearchOptions)', () => { // Given a set of options - const options = getSearchOptions({options: OPTIONS, draftComments: {}, nvpDismissedProductTraining, loginList}); + const options = getSearchOptions({ + options: OPTIONS, + draftComments: {}, + nvpDismissedProductTraining, + loginList, + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we call filterAndOrderOptions with a search value that matches multiple items - const filteredOptions = filterAndOrderOptions(options, 'fantastic', COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, 'fantastic', COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then only three reports should be returned expect(filteredOptions.recentReports.length).toBe(3); @@ -2038,9 +2259,23 @@ describe('OptionsListUtils', () => { // Given a set of options with periods const OPTIONS_WITH_PERIODS = createOptionList(PERSONAL_DETAILS_WITH_PERIODS, REPORTS); // When we call getSearchOptions - const results = getSearchOptions({options: OPTIONS_WITH_PERIODS, draftComments: {}, nvpDismissedProductTraining, loginList}); + const results = getSearchOptions({ + options: OPTIONS_WITH_PERIODS, + draftComments: {}, + nvpDismissedProductTraining, + loginList, + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we pass the returned options to filterAndOrderOptions with a search value - const filteredResults = filterAndOrderOptions(results, 'barry.allen@expensify.com', COUNTRY_CODE, loginList, {sortByReportTypeInSearch: true}); + const filteredResults = filterAndOrderOptions( + results, + 'barry.allen@expensify.com', + COUNTRY_CODE, + loginList, + {sortByReportTypeInSearch: true, currentUserEmail: 'tonystark@expensify.com'}, + 2, + ); // Then only one report should be returned expect(filteredResults.recentReports.length).toBe(1); @@ -2056,9 +2291,17 @@ describe('OptionsListUtils', () => { OPTIONS.personalDetails = OPTIONS.personalDetails.flatMap((obj) => [obj, {...obj}]); // Given a set of options - const options = getSearchOptions({options: OPTIONS, draftComments: {}, nvpDismissedProductTraining, loginList, betas: [CONST.BETAS.ALL]}); + const options = getSearchOptions({ + options: OPTIONS, + draftComments: {}, + nvpDismissedProductTraining, + loginList, + betas: [CONST.BETAS.ALL], + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we call filterAndOrderOptions with a an empty search value - const filteredOptions = filterAndOrderOptions(options, '', COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, '', COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); const matchingEntries = filteredOptions.personalDetails.filter((detail) => detail.login === login); // Then there should be 2 unique login entries @@ -2072,9 +2315,17 @@ describe('OptionsListUtils', () => { const OPTIONS_WITH_SELF_DM = createOptionList(PERSONAL_DETAILS, REPORTS_WITH_SELF_DM); // Given a set of options with self dm and all betas - const options = getSearchOptions({options: OPTIONS_WITH_SELF_DM, draftComments: {}, nvpDismissedProductTraining, loginList, betas: [CONST.BETAS.ALL]}); + const options = getSearchOptions({ + options: OPTIONS_WITH_SELF_DM, + draftComments: {}, + nvpDismissedProductTraining, + loginList, + betas: [CONST.BETAS.ALL], + currentUserAccountID: 2, + currentUserEmail: 'tonystark@expensify.com', + }); // When we call filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchTerm, COUNTRY_CODE, loginList); + const filteredOptions = filterAndOrderOptions(options, searchTerm, COUNTRY_CODE, loginList, {currentUserEmail: 'tonystark@expensify.com'}, 2); // Then the self dm should be on top. expect(filteredOptions.recentReports.at(0)?.isSelfDM).toBe(true); diff --git a/tests/unit/SidebarUtilsTest.ts b/tests/unit/SidebarUtilsTest.ts index a417d1dc3451..7a15f0eea3fc 100644 --- a/tests/unit/SidebarUtilsTest.ts +++ b/tests/unit/SidebarUtilsTest.ts @@ -356,6 +356,7 @@ describe('SidebarUtils', () => { lastAction: undefined, lastActionReport: undefined, isReportArchived: undefined, + currentUserAccountID: 12345, }); const optionDataUnpinned = SidebarUtils.getOptionData({ report: MOCK_REPORT_UNPINNED, @@ -371,6 +372,7 @@ describe('SidebarUtils', () => { lastAction: undefined, lastActionReport: undefined, isReportArchived: undefined, + currentUserAccountID: 12345, }); expect(optionDataPinned?.isPinned).toBe(true); @@ -1172,6 +1174,7 @@ describe('SidebarUtils', () => { lastAction, lastActionReport: undefined, isReportArchived: undefined, + currentUserAccountID: 12345, }); // Then the alternate text should be equal to the message of the last action prepended with the last actor display name. @@ -1233,6 +1236,7 @@ describe('SidebarUtils', () => { lastAction, lastActionReport: undefined, isReportArchived: undefined, + currentUserAccountID: 12345, }); // Then the alternate text should be equal to the message of the last action prepended with the last actor display name. @@ -1297,6 +1301,7 @@ describe('SidebarUtils', () => { lastAction, lastActionReport: undefined, isReportArchived: undefined, + currentUserAccountID: 12345, }); // Then the alternate text should show @Hidden. @@ -1346,6 +1351,7 @@ describe('SidebarUtils', () => { localeCompare, lastActionReport: undefined, isReportArchived: undefined, + currentUserAccountID: 12345, }); expect(optionData?.alternateText).toBe(`test message`); @@ -1386,6 +1392,7 @@ describe('SidebarUtils', () => { localeCompare, isReportArchived: true, lastActionReport: undefined, + currentUserAccountID: 12345, }); expect(optionData?.alternateText).toBe(`test message`); @@ -1423,6 +1430,7 @@ describe('SidebarUtils', () => { localeCompare, lastActionReport: undefined, isReportArchived: undefined, + currentUserAccountID: 12345, }); expect(optionData?.alternateText).toBe(`test message`); @@ -1549,6 +1557,7 @@ describe('SidebarUtils', () => { localeCompare, lastActionReport: undefined, isReportArchived: undefined, + currentUserAccountID: 12345, }); expect(optionData?.alternateText).toBe(formatReportLastMessageText(iouReport.reportName)); @@ -1591,6 +1600,7 @@ describe('SidebarUtils', () => { localeCompare, lastActionReport: undefined, isReportArchived: undefined, + currentUserAccountID: 12345, }); expect(optionData?.alternateText).toBe(`${policy.name} ${CONST.DOT_SEPARATOR} test message`); @@ -1662,6 +1672,7 @@ describe('SidebarUtils', () => { lastAction, lastActionReport: undefined, isReportArchived: undefined, + currentUserAccountID: 12345, }); // Then the alternate text should be equal to the message of the last action prepended with the last actor display name. @@ -1722,6 +1733,7 @@ describe('SidebarUtils', () => { lastAction, lastActionReport: undefined, isReportArchived: undefined, + currentUserAccountID: 2, }); expect(result?.alternateText).toBe(`You: moved this report to the Three's Workspace workspace`); @@ -1794,6 +1806,7 @@ describe('SidebarUtils', () => { lastAction, lastActionReport: undefined, isReportArchived: undefined, + currentUserAccountID: undefined, }); expect(result?.alternateText).toBe(`You: ${getReportActionMessageText(lastAction)}`); @@ -1912,6 +1925,7 @@ describe('SidebarUtils', () => { lastAction, lastActionReport: undefined, isReportArchived: undefined, + currentUserAccountID: 12345, }); expect(result?.alternateText).toContain(`${getReportActionMessageText(lastAction)}`); @@ -1997,6 +2011,7 @@ describe('SidebarUtils', () => { lastAction, lastActionReport: undefined, isReportArchived: undefined, + currentUserAccountID: 12345, }); expect(result?.alternateText).toBe(`One: submitted`); @@ -2094,10 +2109,11 @@ describe('SidebarUtils', () => { localeCompare, lastActionReport: undefined, isReportArchived: undefined, + currentUserAccountID: managerID, }); const reportPreviewMessage = getReportPreviewMessage(iouReport, iouAction, true, true, null, true, lastReportPreviewAction); - expect(result?.alternateText).toBe(`${getLastActorDisplayName({accountID: managerID})}: ${reportPreviewMessage}`); + expect(result?.alternateText).toBe(`${getLastActorDisplayName({accountID: managerID}, managerID)}: ${reportPreviewMessage}`); }); it("shouldn't add current user prefix if the current user isn't the report's manager for report preview action in a DM chat", async () => { @@ -2192,6 +2208,7 @@ describe('SidebarUtils', () => { localeCompare, lastActionReport: undefined, isReportArchived: undefined, + currentUserAccountID: managerID, }); const reportPreviewMessage = getReportPreviewMessage(iouReport, iouAction, true, true, null, true, lastReportPreviewAction);