diff --git a/src/components/Search/FilterDropdowns/UserSelectPopup.tsx b/src/components/Search/FilterDropdowns/UserSelectPopup.tsx index c0128495581f..740dfd057d06 100644 --- a/src/components/Search/FilterDropdowns/UserSelectPopup.tsx +++ b/src/components/Search/FilterDropdowns/UserSelectPopup.tsx @@ -105,10 +105,11 @@ function UserSelectPopup({value, closeOverlay, onChange, isSearchable}: UserSele { excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, includeCurrentUser: true, + personalDetails, }, countryCode, ); - }, [options.reports, options.personalDetails, allPolicies, draftComments, nvpDismissedProductTraining, loginList, countryCode]); + }, [options.reports, options.personalDetails, allPolicies, draftComments, nvpDismissedProductTraining, loginList, countryCode, personalDetails]); const filteredOptions = useMemo(() => { return filterAndOrderOptions(optionsList, cleanSearchTerm, countryCode, loginList, { diff --git a/src/components/Search/SearchFiltersParticipantsSelector.tsx b/src/components/Search/SearchFiltersParticipantsSelector.tsx index 27e829f323f7..ec54bffab4e9 100644 --- a/src/components/Search/SearchFiltersParticipantsSelector.tsx +++ b/src/components/Search/SearchFiltersParticipantsSelector.tsx @@ -74,10 +74,11 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate}: { excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, includeCurrentUser: true, + personalDetails, }, countryCode, ); - }, [areOptionsInitialized, options.reports, options.personalDetails, allPolicies, draftComments, nvpDismissedProductTraining, loginList, countryCode]); + }, [areOptionsInitialized, options.reports, options.personalDetails, allPolicies, draftComments, nvpDismissedProductTraining, loginList, countryCode, personalDetails]); const unselectedOptions = useMemo(() => { return filterSelectedOptions(defaultOptions, new Set(selectedOptions.map((option) => option.accountID))); diff --git a/src/hooks/useSearchSelector.base.ts b/src/hooks/useSearchSelector.base.ts index 41d37faf3e5f..311e9a8db48c 100644 --- a/src/hooks/useSearchSelector.base.ts +++ b/src/hooks/useSearchSelector.base.ts @@ -1,5 +1,6 @@ import {useCallback, useMemo, useState} from 'react'; import type {PermissionStatus} from 'react-native-permissions'; +import {usePersonalDetails} from '@components/OnyxListItemProvider'; import {useOptionsList} from '@components/OptionListContextProvider'; import type {GetOptionsConfig, Options, SearchOption} from '@libs/OptionsListUtils'; import {getEmptyOptions, getSearchOptions, getSearchValueForPhoneOrEmail, getValidOptions} from '@libs/OptionsListUtils'; @@ -165,6 +166,7 @@ function useSearchSelectorBase({ const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true}); const [draftComments] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT, {canBeMissing: true}); const [nvpDismissedProductTraining] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, {canBeMissing: true}); + const personalDetails = usePersonalDetails(); const onListEndReached = useDebounce( useCallback(() => { @@ -208,6 +210,7 @@ function useSearchSelectorBase({ maxRecentReportElements: maxRecentReportsToShow, searchString: computedSearchTerm, includeUserToInvite, + personalDetails, }); case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_GENERAL: return getValidOptions(optionsWithContacts, allPolicies, draftComments, nvpDismissedProductTraining, loginList, { @@ -218,6 +221,7 @@ function useSearchSelectorBase({ maxRecentReportElements: maxRecentReportsToShow, includeUserToInvite, excludeLogins, + personalDetails, }); case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_SHARE_LOG: return getValidOptions( @@ -238,6 +242,7 @@ function useSearchSelectorBase({ searchString: computedSearchTerm, maxElements: maxResults, includeUserToInvite, + personalDetails, }, countryCode, ); @@ -258,6 +263,7 @@ function useSearchSelectorBase({ searchString: computedSearchTerm, maxElements: maxResults, includeUserToInvite, + personalDetails, }); case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_ATTENDEES: return getValidOptions(optionsWithContacts, allPolicies, draftComments, nvpDismissedProductTraining, loginList, { @@ -274,6 +280,7 @@ function useSearchSelectorBase({ includeUserToInvite, includeCurrentUser, shouldAcceptName: true, + personalDetails, }); default: return getEmptyOptions(); @@ -296,6 +303,7 @@ function useSearchSelectorBase({ getValidOptionsConfig, selectedOptions, includeCurrentUser, + personalDetails, ]); const isOptionSelected = useMemo(() => { diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index 05a7ba16969c..82d691151e12 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -2014,6 +2014,7 @@ function prepareReportOptionsForDisplay(options: Array>, po showRBR = true, shouldShowGBR = false, shouldUnreadBeBold = false, + personalDetails, } = config; const validOptions: Array> = []; @@ -2084,7 +2085,7 @@ function prepareReportOptionsForDisplay(options: Array>, po if (report?.policyID) { const policy = policiesCollection?.[`${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`]; const submitToAccountID = getSubmitToAccountID(policy, report); - const submitsToAccountDetails = allPersonalDetails?.[submitToAccountID]; + const submitsToAccountDetails = (personalDetails ?? allPersonalDetails)?.[submitToAccountID]; const subtitle = submitsToAccountDetails?.displayName ?? submitsToAccountDetails?.login; if (subtitle) { @@ -2163,6 +2164,7 @@ function getValidOptions( includeUserToInvite = false, maxRecentReportElements = undefined, shouldAcceptName = false, + personalDetails, ...config }: GetOptionsConfig = {}, countryCode: number = CONST.DEFAULT_COUNTRY_CODE, @@ -2245,6 +2247,7 @@ function getValidOptions( shouldSeparateSelfDMChat, shouldSeparateWorkspaceChat, shouldShowGBR, + personalDetails, }).at(0); } @@ -2258,6 +2261,7 @@ function getValidOptions( shouldSeparateSelfDMChat, shouldSeparateWorkspaceChat, shouldShowGBR, + personalDetails, }); workspaceChats = prepareReportOptionsForDisplay(workspaceChats, policiesCollection, { @@ -2267,6 +2271,7 @@ function getValidOptions( shouldSeparateSelfDMChat, shouldSeparateWorkspaceChat, shouldShowGBR, + personalDetails, }); } else if (recentAttendees && recentAttendees?.length > 0) { recentAttendees.filter((attendee) => { @@ -2382,6 +2387,7 @@ type SearchOptionsConfig = { shouldShowGBR?: boolean; shouldUnreadBeBold?: boolean; loginList: OnyxEntry; + personalDetails?: OnyxEntry; }; /** diff --git a/src/libs/OptionsListUtils/types.ts b/src/libs/OptionsListUtils/types.ts index fb2b73e3f30e..a42669e1dde2 100644 --- a/src/libs/OptionsListUtils/types.ts +++ b/src/libs/OptionsListUtils/types.ts @@ -2,7 +2,7 @@ import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import type {OptionData} from '@libs/ReportUtils'; import type {AvatarSource} from '@libs/UserAvatarUtils'; import type {IOUAction} from '@src/CONST'; -import type {Beta, Login, PersonalDetails, Report, ReportActions, TransactionViolation} from '@src/types/onyx'; +import type {Beta, Login, PersonalDetails, PersonalDetailsList, Report, ReportActions, TransactionViolation} from '@src/types/onyx'; import type {Icon, PendingAction} from '@src/types/onyx/OnyxCommon'; /** @@ -157,6 +157,7 @@ type GetValidReportsConfig = { preferredPolicyID?: string; shouldUnreadBeBold?: boolean; shouldAlwaysIncludeDM?: boolean; + personalDetails?: OnyxEntry; } & GetValidOptionsSharedConfig; type IsValidReportsConfig = Pick< diff --git a/src/pages/NewChatPage.tsx b/src/pages/NewChatPage.tsx index 346b5a892bc4..44d5739a3b82 100755 --- a/src/pages/NewChatPage.tsx +++ b/src/pages/NewChatPage.tsx @@ -68,6 +68,7 @@ function useOptions() { const [didScreenTransitionEnd, setDidScreenTransitionEnd] = useState(false); const {contacts} = useContactImport(); const [draftComments] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT, {canBeMissing: true}); + const allPersonalDetails = usePersonalDetails(); const { options: listOptions, @@ -104,6 +105,7 @@ function useOptions() { betas: betas ?? [], includeSelfDM: true, shouldAlwaysIncludeDM: true, + personalDetails: allPersonalDetails, }, countryCode, ); diff --git a/src/pages/iou/request/MoneyRequestAccountantSelector.tsx b/src/pages/iou/request/MoneyRequestAccountantSelector.tsx index 5d7eec2f3f1a..82e79fe54200 100644 --- a/src/pages/iou/request/MoneyRequestAccountantSelector.tsx +++ b/src/pages/iou/request/MoneyRequestAccountantSelector.tsx @@ -90,6 +90,7 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType betas, excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, action, + personalDetails, }, countryCode, ); @@ -112,6 +113,7 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType betas, action, countryCode, + personalDetails, ]); const chatOptions = useMemo(() => { diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index 32fe446d089b..9bcf58a432fc 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -1140,6 +1140,32 @@ describe('OptionsListUtils', () => { expect(results.recentReports.at(0)?.isBold).toBe(true); expect(results.recentReports.at(0)?.isUnread).toBe(true); }); + + it('should use personalDetails parameter when passed to getValidOptions', () => { + // Given a personalDetails object to pass explicitly + const customPersonalDetails = { + 2: { + accountID: 2, + displayName: 'Custom Iron Man', + login: 'tonystark@expensify.com', + }, + 3: { + accountID: 3, + displayName: 'Custom Spider-Man', + login: 'peterparker@expensify.com', + }, + }; + + // When we call getValidOptions with personalDetails parameter + const results = getValidOptions({reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, {}, {}, nvpDismissedProductTraining, loginList, { + personalDetails: customPersonalDetails, + }); + + // Then the function should complete without errors and return valid results + // The personalDetails param is used internally by prepareReportOptionsForDisplay for workspace chats + expect(results.recentReports.length).toBeGreaterThan(0); + expect(results.personalDetails.length).toBeGreaterThan(0); + }); }); describe('getValidOptions() for chat room', () => {