diff --git a/src/components/Reactions/ReactionTooltipContent.tsx b/src/components/Reactions/ReactionTooltipContent.tsx index 399372a01912..31980478843b 100644 --- a/src/components/Reactions/ReactionTooltipContent.tsx +++ b/src/components/Reactions/ReactionTooltipContent.tsx @@ -2,9 +2,11 @@ import React from 'react'; import {View} from 'react-native'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; import useThemeStyles from '@hooks/useThemeStyles'; import {getLocalizedEmojiName} from '@libs/EmojiUtils'; -import {getPersonalDetailsByIDs} from '@libs/PersonalDetailsUtils'; +import ONYXKEYS from '@src/ONYXKEYS'; +import {personalDetailsWithCustomNameSelector} from '@src/selectors/PersonalDetails'; type ReactionTooltipContentProps = { /** @@ -31,13 +33,20 @@ type ReactionTooltipContentProps = { function ReactionTooltipContent({accountIDs, emojiCodes, emojiName, currentUserAccountID}: ReactionTooltipContentProps) { const styles = useThemeStyles(); const {translate, preferredLocale} = useLocalize(); - const users = getPersonalDetailsByIDs({accountIDs, currentUserAccountID, shouldChangeUserDisplayName: true}); + const [users] = useOnyx( + ONYXKEYS.PERSONAL_DETAILS_LIST, + { + selector: personalDetailsWithCustomNameSelector({accountIDs, shouldChangeUserDisplayName: true, currentUserAccountID, translate}), + }, + [accountIDs, currentUserAccountID, translate], + ); const localizedEmojiName = getLocalizedEmojiName(emojiName, preferredLocale); - const namesString = users - .map((user) => user?.displayName) - .filter((name) => name) - .join(', '); + const namesString = + users + ?.map((user) => user?.displayName) + .filter((name) => name) + .join(', ') ?? ''; return ( diff --git a/src/libs/PersonalDetailsUtils.ts b/src/libs/PersonalDetailsUtils.ts index 81ed9e4a5909..153f237c9a02 100644 --- a/src/libs/PersonalDetailsUtils.ts +++ b/src/libs/PersonalDetailsUtils.ts @@ -1,7 +1,7 @@ import {Str} from 'expensify-common'; import type {OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; -import type {LocaleContextProps} from '@components/LocaleContextProvider'; +import type {LocaleContextProps, LocalizedTranslate} from '@components/LocaleContextProvider'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {OnyxInputOrEntry, PersonalDetails, PersonalDetailsList, PrivatePersonalDetails} from '@src/types/onyx'; @@ -19,15 +19,15 @@ type FirstAndLastName = { lastName: string; }; -let personalDetails: Array = []; +let deprecatedPersonalDetails: Array = []; let allPersonalDetails: OnyxEntry = {}; let emailToPersonalDetailsCache: Record = {}; Onyx.connect({ key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (val) => { - personalDetails = Object.values(val ?? {}); + deprecatedPersonalDetails = Object.values(val ?? {}); allPersonalDetails = val; - emailToPersonalDetailsCache = personalDetails.reduce((acc: Record, detail) => { + emailToPersonalDetailsCache = deprecatedPersonalDetails.reduce((acc: Record, detail) => { if (detail?.login) { acc[detail.login.toLowerCase()] = detail; } @@ -136,6 +136,43 @@ function getPersonalDetailsByIDs({ return result; } +function newGetPersonalDetailsByIDs(params: { + accountIDs: number[]; + personalDetails: OnyxEntry; + shouldChangeUserDisplayName: true; + currentUserAccountID: number | undefined; + translate: LocalizedTranslate; +}): PersonalDetails[]; +function newGetPersonalDetailsByIDs(params: {accountIDs: number[]; personalDetails: OnyxEntry; shouldChangeUserDisplayName?: false}): PersonalDetails[]; +function newGetPersonalDetailsByIDs({ + accountIDs, + personalDetails, + currentUserAccountID, + shouldChangeUserDisplayName = false, + translate, +}: { + accountIDs: number[]; + personalDetails: OnyxEntry; + currentUserAccountID?: number; + shouldChangeUserDisplayName?: boolean; + translate?: LocalizedTranslate; +}): PersonalDetails[] { + const result: PersonalDetails[] = []; + for (const accountID of accountIDs) { + const detail = personalDetails?.[accountID]; + if (!detail) { + continue; + } + + if (shouldChangeUserDisplayName && currentUserAccountID === detail.accountID && translate) { + result.push({...detail, displayName: translate('common.you')}); + } else { + result.push(detail); + } + } + return result; +} + function getPersonalDetailByEmail(email: string | undefined): PersonalDetails | undefined { if (!email) { return undefined; @@ -458,6 +495,7 @@ function areTravelPersonalDetailsMissing(privatePersonalDetails: OnyxEntry isOffline || !participant.isPendingDelete); @@ -183,7 +186,7 @@ function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { title: translate('workspace.people.removeMembersTitle', {count: selectedMembers.length}), prompt: translate('workspace.people.removeMembersPrompt', { count: selectedMembers.length, - memberName: formatPhoneNumber(getPersonalDetailsByIDs({accountIDs: selectedMembers, currentUserAccountID}).at(0)?.displayName ?? ''), + memberName: formatPhoneNumber(firstSelectedMemberDetails?.displayName ?? ''), }), confirmText: translate('common.remove'), cancelText: translate('common.cancel'), diff --git a/src/pages/RoomMembersPage.tsx b/src/pages/RoomMembersPage.tsx index de79462ed581..d290a42a01ba 100644 --- a/src/pages/RoomMembersPage.tsx +++ b/src/pages/RoomMembersPage.tsx @@ -14,8 +14,6 @@ import TableListItem from '@components/SelectionList/ListItem/TableListItem'; import type {ListItem} from '@components/SelectionList/types'; import SelectionListWithModal from '@components/SelectionListWithModal'; import Text from '@components/Text'; -import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails'; -import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; import useConfirmModal from '@hooks/useConfirmModal'; import useFilteredSelection from '@hooks/useFilteredSelection'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; @@ -36,7 +34,7 @@ import type {PlatformStackRouteProp, PlatformStackScreenProps} from '@libs/Navig import type {RoomMembersNavigatorParamList} from '@libs/Navigation/types'; import {isPersonalDetailsReady, isSearchStringMatchUserDetails} from '@libs/OptionsListUtils'; import Parser from '@libs/Parser'; -import {getDisplayNameOrDefault, getPersonalDetailsByIDs} from '@libs/PersonalDetailsUtils'; +import {getDisplayNameOrDefault} from '@libs/PersonalDetailsUtils'; import {isPolicyAdmin, isPolicyEmployee as isPolicyEmployeeUtils} from '@libs/PolicyUtils'; import {getReportAction} from '@libs/ReportActionsUtils'; import {getReportName} from '@libs/ReportNameUtils'; @@ -55,12 +53,13 @@ import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; +import {personalDetailsSelector} from '@src/selectors/PersonalDetails'; import type {PersonalDetails} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type {WithReportOrNotFoundProps} from './inbox/report/withReportOrNotFound'; import withReportOrNotFound from './inbox/report/withReportOrNotFound'; -type RoomMembersPageProps = WithReportOrNotFoundProps & WithCurrentUserPersonalDetailsProps & PlatformStackScreenProps; +type RoomMembersPageProps = WithReportOrNotFoundProps & PlatformStackScreenProps; function RoomMembersPage({report, policy}: RoomMembersPageProps) { const route = useRoute>(); @@ -71,7 +70,6 @@ function RoomMembersPage({report, policy}: RoomMembersPageProps) { const reportAttributes = useReportAttributes(); const [session] = useOnyx(ONYXKEYS.SESSION); const [reportMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${report?.reportID}`); - const currentUserAccountID = Number(session?.accountID); const {formatPhoneNumber, translate, localeCompare} = useLocalize(); const {showConfirmModal} = useConfirmModal(); const [userSearchPhrase] = useOnyx(ONYXKEYS.ROOM_MEMBERS_USER_SEARCH_PHRASE); @@ -105,6 +103,8 @@ function RoomMembersPage({report, policy}: RoomMembersPageProps) { ); const [selectedMembers, setSelectedMembers] = useFilteredSelection(personalDetailsParticipants, shouldIncludeMember); + const firstSelectedMember = selectedMembers?.at(0); + const [firstSelectedMemberDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {selector: personalDetailsSelector(firstSelectedMember)}); const isFocusedScreen = useIsFocused(); const {isOffline} = useNetwork(); @@ -163,7 +163,7 @@ function RoomMembersPage({report, policy}: RoomMembersPageProps) { title: translate('workspace.people.removeMembersTitle', {count: selectedMembers.length}), prompt: translate('roomMembersPage.removeMembersPrompt', { count: selectedMembers.length, - memberName: formatPhoneNumber(getPersonalDetailsByIDs({accountIDs: selectedMembers, currentUserAccountID}).at(0)?.displayName ?? ''), + memberName: formatPhoneNumber(firstSelectedMemberDetails?.displayName ?? ''), }), confirmText: translate('common.remove'), cancelText: translate('common.cancel'), @@ -173,7 +173,7 @@ function RoomMembersPage({report, policy}: RoomMembersPageProps) { return; } removeUsers(); - }, [showConfirmModal, translate, selectedMembers, formatPhoneNumber, currentUserAccountID, removeUsers]); + }, [showConfirmModal, translate, selectedMembers.length, formatPhoneNumber, firstSelectedMemberDetails?.displayName, removeUsers]); /** * Add user from the selectedMembers list @@ -481,4 +481,4 @@ function RoomMembersPage({report, policy}: RoomMembersPageProps) { ); } -export default withReportOrNotFound()(withCurrentUserPersonalDetails(RoomMembersPage)); +export default withReportOrNotFound()(RoomMembersPage); diff --git a/src/pages/domain/Members/DomainAddMemberPage.tsx b/src/pages/domain/Members/DomainAddMemberPage.tsx index 30e68c2c194a..8a2b2ec6351e 100644 --- a/src/pages/domain/Members/DomainAddMemberPage.tsx +++ b/src/pages/domain/Members/DomainAddMemberPage.tsx @@ -13,7 +13,6 @@ import useThemeStyles from '@hooks/useThemeStyles'; import {addErrorMessage} from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; -import {getPersonalDetailsByIDs} from '@libs/PersonalDetailsUtils'; import {isValidEmail} from '@libs/ValidationUtils'; import type {SettingsNavigatorParamList} from '@navigation/types'; import DomainNotFoundPageWrapper from '@pages/domain/DomainNotFoundPageWrapper'; @@ -23,6 +22,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import {defaultSecurityGroupIDSelector, domainNameSelector, memberAccountIDsSelector} from '@src/selectors/Domain'; +import {personalDetailsWithCustomNameSelector} from '@src/selectors/PersonalDetails'; import INPUT_IDS from '@src/types/form/AddDomainMemberForm'; import type {Errors} from '@src/types/onyx/OnyxCommon'; import getEmptyArray from '@src/types/utils/getEmptyArray'; @@ -53,7 +53,7 @@ function DomainAddMemberPage({route}: DomainAddMemberProps) { const [memberIDs = getEmptyArray()] = useOnyx(`${ONYXKEYS.COLLECTION.DOMAIN}${domainAccountID}`, { selector: memberAccountIDsSelector, }); - const personalDetails = getPersonalDetailsByIDs({accountIDs: memberIDs}); + const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {selector: personalDetailsWithCustomNameSelector({accountIDs: memberIDs})}, [memberIDs]); const [domainName] = useOnyx(`${ONYXKEYS.COLLECTION.DOMAIN}${domainAccountID}`, {selector: domainNameSelector}); const [defaultSecurityGroupID] = useOnyx(`${ONYXKEYS.COLLECTION.DOMAIN}${domainAccountID}`, {selector: defaultSecurityGroupIDSelector}); @@ -80,7 +80,7 @@ function DomainAddMemberPage({route}: DomainAddMemberProps) { addErrorMessage(errors, 'email', translate('common.error.characterLimitExceedCounter', fullEmail.length, CONST.LOGIN_CHARACTER_LIMIT)); } - const isUserAlreadyAMember = !!values.email && personalDetails.some(({login}) => login?.toLowerCase() === fullEmail.toLowerCase()); + const isUserAlreadyAMember = !!values.email && personalDetails?.some(({login}) => login?.toLowerCase() === fullEmail.toLowerCase()); const isEmailInvalid = !!domainName && !!values.email && !isValidEmail(fullEmail); if (isEmailInvalid) { diff --git a/src/pages/inbox/report/ReactionList/PopoverReactionList.tsx b/src/pages/inbox/report/ReactionList/PopoverReactionList.tsx index ff364f697142..edc158343121 100644 --- a/src/pages/inbox/report/ReactionList/PopoverReactionList.tsx +++ b/src/pages/inbox/report/ReactionList/PopoverReactionList.tsx @@ -2,11 +2,14 @@ import React, {useEffect} from 'react'; import type {RefObject} from 'react'; import PopoverWithMeasuredContent from '@components/PopoverWithMeasuredContent'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; +import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import {getEmojiReactionDetails} from '@libs/EmojiUtils'; -import {getPersonalDetailsByIDs} from '@libs/PersonalDetailsUtils'; import type {ReactionListAnchor} from '@pages/inbox/ReportScreenContext'; import ONYXKEYS from '@src/ONYXKEYS'; +import {personalDetailsWithCustomNameSelector} from '@src/selectors/PersonalDetails'; +import type {PersonalDetails} from '@src/types/onyx'; +import getEmptyArray from '@src/types/utils/getEmptyArray'; import BaseReactionList from './BaseReactionList'; type PopoverReactionListProps = { @@ -19,6 +22,7 @@ type PopoverReactionListProps = { }; function PopoverReactionList({isVisible, emojiName, reportActionID, anchorPosition, anchorRef, onClose}: PopoverReactionListProps) { + const {translate} = useLocalize(); const {accountID} = useCurrentUserPersonalDetails(); const [emojiReactions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_REACTIONS}${reportActionID}`); @@ -26,7 +30,14 @@ function PopoverReactionList({isVisible, emojiName, reportActionID, anchorPositi const selectedReaction = emojiReactions?.[emojiName]; const isReady = !!selectedReaction; const {emojiCodes = [], reactionCount = 0, hasUserReacted = false, userAccountIDs = []} = selectedReaction ? getEmojiReactionDetails(emojiName, selectedReaction, accountID) : {}; - const users = isReady ? getPersonalDetailsByIDs({accountIDs: userAccountIDs, currentUserAccountID: accountID, shouldChangeUserDisplayName: true}) : []; + + const [users = getEmptyArray()] = useOnyx( + ONYXKEYS.PERSONAL_DETAILS_LIST, + { + selector: isReady ? personalDetailsWithCustomNameSelector({accountIDs: userAccountIDs, currentUserAccountID: accountID, shouldChangeUserDisplayName: true, translate}) : () => [], + }, + [userAccountIDs, accountID, translate], + ); // Hide the list when all reactions are removed useEffect(() => { diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index f4289fe4cb83..5806b6f1b8b7 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -64,7 +64,7 @@ import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import {isPersonalDetailsReady, sortAlphabetically} from '@libs/OptionsListUtils'; -import {getDisplayNameOrDefault, getPersonalDetailsByIDs} from '@libs/PersonalDetailsUtils'; +import {getDisplayNameOrDefault, newGetPersonalDetailsByIDs} from '@libs/PersonalDetailsUtils'; import { canEditWorkspaceSettings, getConnectionExporters, @@ -168,7 +168,6 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers const [invitedEmailsToAccountIDsDraft] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_INVITE_MEMBERS_DRAFT}${route.params.policyID.toString()}`); const isMobileSelectionModeEnabled = useMobileSelectionMode(); const [session] = useOnyx(ONYXKEYS.SESSION); - const currentUserAccountID = Number(session?.accountID); const selectionListRef = useRef>(null); const isFocused = useIsFocused(); const policyID = route.params.policyID; @@ -214,9 +213,9 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers const firstSelectedEmployeeAccountID = policyMemberEmailsToAccountIDs[selectedEmployees[0]]; return translate('workspace.people.removeMembersPrompt', { count: selectedEmployees.length, - memberName: formatPhoneNumber(getPersonalDetailsByIDs({accountIDs: [firstSelectedEmployeeAccountID], currentUserAccountID}).at(0)?.displayName ?? ''), + memberName: formatPhoneNumber(newGetPersonalDetailsByIDs({accountIDs: [firstSelectedEmployeeAccountID], personalDetails}).at(0)?.displayName ?? ''), }); - }, [selectedEmployees, policyMemberEmailsToAccountIDs, translate, policy, formatPhoneNumber, currentUserAccountID]); + }, [selectedEmployees, policyMemberEmailsToAccountIDs, translate, policy, formatPhoneNumber, personalDetails]); /** * Get members for the current workspace */ diff --git a/src/pages/workspace/WorkspacesListRow.tsx b/src/pages/workspace/WorkspacesListRow.tsx index 21f5cc9a92cc..a60fc1559dbc 100644 --- a/src/pages/workspace/WorkspacesListRow.tsx +++ b/src/pages/workspace/WorkspacesListRow.tsx @@ -14,23 +14,24 @@ import Text from '@components/Text'; import TextWithTooltip from '@components/TextWithTooltip'; import ThreeDotsMenu from '@components/ThreeDotsMenu'; import Tooltip from '@components/Tooltip'; -import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails'; -import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; import WorkspacesListRowDisplayName from '@components/WorkspacesListRowDisplayName'; import useAnimatedHighlightStyle from '@hooks/useAnimatedHighlightStyle'; import {useMemoizedLazyExpensifyIcons, useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import {getDisplayNameOrDefault, getPersonalDetailsByIDs} from '@libs/PersonalDetailsUtils'; +import {getDisplayNameOrDefault} from '@libs/PersonalDetailsUtils'; import {getUserFriendlyWorkspaceType} from '@libs/PolicyUtils'; import type {AvatarSource} from '@libs/UserAvatarUtils'; import variables from '@styles/variables'; import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import {personalDetailsSelector} from '@src/selectors/PersonalDetails'; import type IconAsset from '@src/types/utils/IconAsset'; -type WorkspacesListRowProps = WithCurrentUserPersonalDetailsProps & { +type WorkspacesListRowProps = { /** Name of the workspace */ title: string; @@ -116,7 +117,6 @@ function WorkspacesListRow({ fallbackWorkspaceIcon, ownerAccountID, workspaceType, - currentUserPersonalDetails, layoutWidth = CONST.LAYOUT_WIDTH.NONE, rowStyles, style, @@ -141,6 +141,8 @@ function WorkspacesListRow({ const icons = useMemoizedLazyExpensifyIcons(['ArrowRight', 'Hourglass']); const illustrations = useMemoizedLazyIllustrations(['Mailbox', 'ShieldYellow']); + const [ownerDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {selector: personalDetailsSelector(ownerAccountID)}); + const workspaceTypeIcon = useCallback( (type: WorkspacesListRowProps['workspaceType']): IconAsset => { switch (type) { @@ -155,7 +157,6 @@ function WorkspacesListRow({ [illustrations.Mailbox, illustrations.ShieldYellow], ); - const ownerDetails = ownerAccountID && getPersonalDetailsByIDs({accountIDs: [ownerAccountID], currentUserAccountID: currentUserPersonalDetails.accountID}).at(0); const threeDotsMenuRef = useRef<{hidePopoverMenu: () => void; isPopupMenuVisible: boolean}>(null); const animatedHighlightStyle = useAnimatedHighlightStyle({ borderRadius: variables.componentBorderRadius, @@ -369,4 +370,4 @@ function WorkspacesListRow({ ); } -export default withCurrentUserPersonalDetails(WorkspacesListRow); +export default WorkspacesListRow; diff --git a/src/selectors/PersonalDetails.ts b/src/selectors/PersonalDetails.ts index 4d1713da063e..ff560e7e19db 100644 --- a/src/selectors/PersonalDetails.ts +++ b/src/selectors/PersonalDetails.ts @@ -1,8 +1,46 @@ import type {OnyxEntry} from 'react-native-onyx'; +import type {LocalizedTranslate} from '@components/LocaleContextProvider'; +import {newGetPersonalDetailsByIDs} from '@libs/PersonalDetailsUtils'; import CONST from '@src/CONST'; -import type {PersonalDetailsList, Report} from '@src/types/onyx'; +import type {PersonalDetails, PersonalDetailsList, Report} from '@src/types/onyx'; -const personalDetailsSelector = (accountID: number) => (personalDetailsList: OnyxEntry) => personalDetailsList?.[accountID]; +const personalDetailsSelector = (accountID: number | undefined) => (personalDetailsList: OnyxEntry) => (accountID ? personalDetailsList?.[accountID] : undefined); + +function personalDetailsWithCustomNameSelector(params: { + accountIDs: number[]; + currentUserAccountID?: number; + shouldChangeUserDisplayName: true; + translate: LocalizedTranslate; +}): (personalDetails: OnyxEntry) => PersonalDetails[]; +function personalDetailsWithCustomNameSelector(params: {accountIDs: number[]; shouldChangeUserDisplayName?: false}): (personalDetails: OnyxEntry) => PersonalDetails[]; +function personalDetailsWithCustomNameSelector({ + accountIDs, + currentUserAccountID, + shouldChangeUserDisplayName, + translate, +}: { + accountIDs: number[]; + currentUserAccountID?: number; + shouldChangeUserDisplayName?: boolean; + translate?: LocalizedTranslate; +}) { + return (personalDetails: OnyxEntry): PersonalDetails[] => { + if (shouldChangeUserDisplayName && translate) { + return newGetPersonalDetailsByIDs({ + accountIDs, + personalDetails, + currentUserAccountID, + shouldChangeUserDisplayName: true, + translate, + }); + } + return newGetPersonalDetailsByIDs({ + accountIDs, + personalDetails, + shouldChangeUserDisplayName: false, + }); + }; +} const personalDetailsLoginSelector = (accountID: number) => (personalDetailsList: OnyxEntry) => personalDetailsList?.[accountID]?.login; @@ -17,4 +55,4 @@ const accountIDToLoginSelector = (reportsToArchive: Report[]) => (personalDetail return map; }; -export {personalDetailsSelector, personalDetailsLoginSelector, accountIDToLoginSelector}; +export {personalDetailsSelector, personalDetailsWithCustomNameSelector, personalDetailsLoginSelector, accountIDToLoginSelector}; diff --git a/tests/unit/PersonalDetailsSelectorTest.ts b/tests/unit/PersonalDetailsSelectorTest.ts index 8fd4f55c2c2b..18e7d9d3fb26 100644 --- a/tests/unit/PersonalDetailsSelectorTest.ts +++ b/tests/unit/PersonalDetailsSelectorTest.ts @@ -1,5 +1,7 @@ -import {personalDetailsLoginSelector, personalDetailsSelector} from '@selectors/PersonalDetails'; +import {personalDetailsLoginSelector, personalDetailsSelector, personalDetailsWithCustomNameSelector} from '@selectors/PersonalDetails'; +import {newGetPersonalDetailsByIDs} from '@libs/PersonalDetailsUtils'; import type {PersonalDetailsList} from '@src/types/onyx'; +import {translateLocal} from '../utils/TestHelper'; describe('PersonalDetailsSelector', () => { const accountID = 123; @@ -44,4 +46,38 @@ describe('PersonalDetailsSelector', () => { expect(result).toBeUndefined(); }); }); + + describe('personalDetailsWithCustomNameSelector', () => { + it('should match the result from newGetPersonalDetailsByIDs when shouldChangeUserDisplayName is false', () => { + const accountIDs = [accountID]; + const result = personalDetailsWithCustomNameSelector({accountIDs})(personalDetailsList); + + const expected = newGetPersonalDetailsByIDs({ + accountIDs, + personalDetails: personalDetailsList, + }); + + expect(result).toEqual(expected); + }); + + it('should match the result from newGetPersonalDetailsByIDs when shouldChangeUserDisplayName is true', () => { + const accountIDs = [accountID]; + const result = personalDetailsWithCustomNameSelector({ + accountIDs, + currentUserAccountID: accountID, + shouldChangeUserDisplayName: true, + translate: translateLocal, + })(personalDetailsList); + + const expected = newGetPersonalDetailsByIDs({ + accountIDs, + personalDetails: personalDetailsList, + shouldChangeUserDisplayName: true, + currentUserAccountID: accountID, + translate: translateLocal, + }); + + expect(result).toEqual(expected); + }); + }); }); diff --git a/tests/unit/libs/PersonalDetailsUtilsTest.ts b/tests/unit/libs/PersonalDetailsUtilsTest.ts index 126ccac1d07a..d74bee310214 100644 --- a/tests/unit/libs/PersonalDetailsUtilsTest.ts +++ b/tests/unit/libs/PersonalDetailsUtilsTest.ts @@ -8,10 +8,11 @@ import { getEffectiveDisplayName, getPersonalDetailByEmail, getPersonalDetailsOnyxDataForOptimisticUsers, + newGetPersonalDetailsByIDs, } from '@libs/PersonalDetailsUtils'; import ONYXKEYS from '@src/ONYXKEYS'; import type {PersonalDetails, PersonalDetailsList, PrivatePersonalDetails} from '@src/types/onyx'; -import {formatPhoneNumber} from '../../utils/TestHelper'; +import {formatPhoneNumber, translateLocal} from '../../utils/TestHelper'; import waitForBatchedUpdates from '../../utils/waitForBatchedUpdates'; type PersonalDetailsForDisplayName = Pick & { @@ -702,4 +703,62 @@ describe('PersonalDetailsUtils', () => { expect(result[1]).toEqual({accountID: 1, login: 'second@example.com', displayName: 'Second'}); }); }); + + describe('newGetPersonalDetailsByIDs', () => { + const accountID1 = 1; + const accountID2 = 2; + const personalDetails: PersonalDetailsList = { + [accountID1]: { + accountID: accountID1, + login: 'user1@example.com', + displayName: 'User One', + }, + [accountID2]: { + accountID: accountID2, + login: 'user2@example.com', + displayName: 'User Two', + }, + }; + + it('should return an empty array if accountIDs is empty', () => { + const result = newGetPersonalDetailsByIDs({ + accountIDs: [], + personalDetails, + }); + expect(result).toEqual([]); + }); + + it('should return personal details for the given accountIDs', () => { + const result = newGetPersonalDetailsByIDs({ + accountIDs: [accountID1, accountID2], + personalDetails, + }); + expect(result).toEqual([personalDetails[accountID1], personalDetails[accountID2]]); + }); + + it('should filter out accountIDs that do not have corresponding personal details', () => { + const result = newGetPersonalDetailsByIDs({ + accountIDs: [accountID1, 999], + personalDetails, + }); + expect(result).toEqual([personalDetails[accountID1]]); + }); + + it("should replace the current user's displayName with 'You' if shouldChangeUserDisplayName is true", () => { + const result = newGetPersonalDetailsByIDs({ + accountIDs: [accountID1, accountID2], + personalDetails, + shouldChangeUserDisplayName: true, + currentUserAccountID: accountID1, + translate: translateLocal, + }); + expect(result).toEqual([ + { + ...personalDetails[accountID1], + displayName: translateLocal('common.you'), + }, + personalDetails[accountID2], + ]); + }); + }); });