diff --git a/lib/shared/search-utils.js b/lib/shared/search-utils.js --- a/lib/shared/search-utils.js +++ b/lib/shared/search-utils.js @@ -18,23 +18,38 @@ import { threadPermissions } from '../types/thread-permission-types.js'; import { type ThreadType, threadTypes } from '../types/thread-types-enum.js'; import { type ThreadInfo } from '../types/thread-types.js'; -import type { AccountUserInfo, UserListItem } from '../types/user-types.js'; +import type { + AccountUserInfo, + UserListItem, + GlobalAccountUserInfo, +} from '../types/user-types.js'; import { useServerCall, useDispatchActionPromise, } from '../utils/action-utils.js'; +import { values } from '../utils/objects.js'; const notFriendNotice = 'not friend'; -function getPotentialMemberItems( - text: string, - userInfos: { +[id: string]: AccountUserInfo }, - searchIndex: SearchIndex, - excludeUserIDs: $ReadOnlyArray, - inputParentThreadInfo: ?ThreadInfo, - inputCommunityThreadInfo: ?ThreadInfo, - threadType: ?ThreadType, -): UserListItem[] { +function getPotentialMemberItems({ + text, + userInfos, + searchIndex, + excludeUserIDs, + includeServerSearchUsers, + inputParentThreadInfo, + inputCommunityThreadInfo, + threadType, +}: { + +text: string, + +userInfos: { +[id: string]: AccountUserInfo }, + +searchIndex: SearchIndex, + +excludeUserIDs: $ReadOnlyArray, + +includeServerSearchUsers?: $ReadOnlyArray, + +inputParentThreadInfo?: ?ThreadInfo, + +inputCommunityThreadInfo?: ?ThreadInfo, + +threadType?: ?ThreadType, +}): UserListItem[] { const communityThreadInfo = inputCommunityThreadInfo && inputCommunityThreadInfo.id !== genesis.id ? inputCommunityThreadInfo @@ -55,10 +70,18 @@ containingThreadInfo = communityThreadInfo; } - let results = []; - const appendUserInfo = (userInfo: AccountUserInfo) => { + const results: { + [id: string]: { + ...AccountUserInfo | GlobalAccountUserInfo, + isMemberOfParentThread: boolean, + isMemberOfContainingThread: boolean, + }, + } = {}; + const appendUserInfo = ( + userInfo: AccountUserInfo | GlobalAccountUserInfo, + ) => { const { id } = userInfo; - if (excludeUserIDs.includes(id)) { + if (excludeUserIDs.includes(id) || id in results) { return; } if ( @@ -71,11 +94,11 @@ ) { return; } - results.push({ + results[id] = { ...userInfo, isMemberOfParentThread: userIsMember(parentThreadInfo, id), isMemberOfContainingThread: userIsMember(containingThreadInfo, id), - }); + }; }; if (text === '') { for (const id in userInfos) { @@ -88,18 +111,25 @@ } } + if (includeServerSearchUsers) { + for (const userInfo of includeServerSearchUsers) { + appendUserInfo(userInfo); + } + } + const blockedRelationshipsStatuses = new Set([ userRelationshipStatus.BLOCKED_BY_VIEWER, userRelationshipStatus.BLOCKED_VIEWER, userRelationshipStatus.BOTH_BLOCKED, ]); + let userResults = values(results); if (text === '') { - results = results.filter(userInfo => + userResults = userResults.filter(userInfo => containingThreadInfo ? userInfo.isMemberOfContainingThread && !blockedRelationshipsStatuses.has(userInfo.relationshipStatus) - : userInfo.relationshipStatus === userRelationshipStatus.FRIEND, + : userInfo?.relationshipStatus === userRelationshipStatus.FRIEND, ); } @@ -109,7 +139,7 @@ const containingThreadMembers = []; const parentThreadMembers = []; - for (const userResult of results) { + for (const userResult of userResults) { const relationshipStatus = userResult.relationshipStatus; if (blockedRelationshipsStatuses.has(relationshipStatus)) { blockedUsers.push(userResult); diff --git a/native/chat/compose-subchannel.react.js b/native/chat/compose-subchannel.react.js --- a/native/chat/compose-subchannel.react.js +++ b/native/chat/compose-subchannel.react.js @@ -198,15 +198,15 @@ ); const userSearchResults = React.useMemo( () => - getPotentialMemberItems( - usernameInputText, - otherUserInfos, - userSearchIndex, - userInfoInputIDs, - parentThreadInfo, - communityThreadInfo, + getPotentialMemberItems({ + text: usernameInputText, + userInfos: otherUserInfos, + searchIndex: userSearchIndex, + excludeUserIDs: userInfoInputIDs, + inputParentThreadInfo: parentThreadInfo, + inputCommunityThreadInfo: communityThreadInfo, threadType, - ), + }), [ usernameInputText, otherUserInfos, diff --git a/native/chat/message-list-container.react.js b/native/chat/message-list-container.react.js --- a/native/chat/message-list-container.react.js +++ b/native/chat/message-list-container.react.js @@ -251,12 +251,12 @@ const userSearchIndex = useSelector(userSearchIndexForPotentialMembers); const userSearchResults = React.useMemo( () => - getPotentialMemberItems( - usernameInputText, - otherUserInfos, - userSearchIndex, - userInfoInputArray.map(userInfo => userInfo.id), - ), + getPotentialMemberItems({ + text: usernameInputText, + userInfos: otherUserInfos, + searchIndex: userSearchIndex, + excludeUserIDs: userInfoInputArray.map(userInfo => userInfo.id), + }), [usernameInputText, otherUserInfos, userSearchIndex, userInfoInputArray], ); diff --git a/native/chat/settings/add-users-modal.react.js b/native/chat/settings/add-users-modal.react.js --- a/native/chat/settings/add-users-modal.react.js +++ b/native/chat/settings/add-users-modal.react.js @@ -171,15 +171,15 @@ ); const userSearchResults = React.useMemo( () => - getPotentialMemberItems( - usernameInputText, - otherUserInfos, - userSearchIndex, + getPotentialMemberItems({ + text: usernameInputText, + userInfos: otherUserInfos, + searchIndex: userSearchIndex, excludeUserIDs, - parentThreadInfo, - communityThreadInfo, - threadInfo.type, - ), + inputParentThreadInfo: parentThreadInfo, + inputCommunityThreadInfo: communityThreadInfo, + threadType: threadInfo.type, + }), [ usernameInputText, otherUserInfos, diff --git a/native/community-creation/community-creation-members.react.js b/native/community-creation/community-creation-members.react.js --- a/native/community-creation/community-creation-members.react.js +++ b/native/community-creation/community-creation-members.react.js @@ -146,17 +146,15 @@ const userSearchResults = React.useMemo( () => - getPotentialMemberItems( - usernameInputText, - otherUserInfos, - userSearchIndex, - selectedUserIDs, - null, - null, - announcement + getPotentialMemberItems({ + text: usernameInputText, + userInfos: otherUserInfos, + searchIndex: userSearchIndex, + excludeUserIDs: selectedUserIDs, + threadType: announcement ? threadTypes.COMMUNITY_ANNOUNCEMENT_ROOT : threadTypes.COMMUNITY_ROOT, - ), + }), [ announcement, otherUserInfos, diff --git a/web/chat/chat-thread-composer.react.js b/web/chat/chat-thread-composer.react.js --- a/web/chat/chat-thread-composer.react.js +++ b/web/chat/chat-thread-composer.react.js @@ -45,12 +45,12 @@ const userListItems = React.useMemo( () => - getPotentialMemberItems( - usernameInputText, - otherUserInfos, - userSearchIndex, - userInfoInputIDs, - ), + getPotentialMemberItems({ + text: usernameInputText, + userInfos: otherUserInfos, + searchIndex: userSearchIndex, + excludeUserIDs: userInfoInputIDs, + }), [usernameInputText, otherUserInfos, userSearchIndex, userInfoInputIDs], ); const userListItemsWithENSNames = useENSNames(userListItems); diff --git a/web/modals/threads/members/add-members-modal.react.js b/web/modals/threads/members/add-members-modal.react.js --- a/web/modals/threads/members/add-members-modal.react.js +++ b/web/modals/threads/members/add-members-modal.react.js @@ -59,15 +59,15 @@ const userSearchResults = React.useMemo( () => - getPotentialMemberItems( - searchText, - otherUserInfos, - userSearchIndex, + getPotentialMemberItems({ + text: searchText, + userInfos: otherUserInfos, + searchIndex: userSearchIndex, excludeUserIDs, - parentThreadInfo, - communityThreadInfo, - threadInfo.type, - ), + inputParentThreadInfo: parentThreadInfo, + inputCommunityThreadInfo: communityThreadInfo, + threadType: threadInfo.type, + }), [ communityThreadInfo, excludeUserIDs,