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 @@ -43,7 +43,13 @@ const notFriendNotice = 'not friend'; -function getPotentialMemberItems({ +const blockedRelationshipsStatuses = new Set([ + userRelationshipStatus.BLOCKED_BY_VIEWER, + userRelationshipStatus.BLOCKED_VIEWER, + userRelationshipStatus.BOTH_BLOCKED, +]); + +function usePotentialMemberItems({ text, userInfos, searchIndex, @@ -129,12 +135,6 @@ } } - const blockedRelationshipsStatuses = new Set([ - userRelationshipStatus.BLOCKED_BY_VIEWER, - userRelationshipStatus.BLOCKED_VIEWER, - userRelationshipStatus.BOTH_BLOCKED, - ]); - let userResults = values(results); if (text === '') { userResults = userResults.filter(userInfo => { @@ -152,95 +152,99 @@ }); } - const nonFriends = []; - const blockedUsers = []; - const friends = []; - const containingThreadMembers = []; - const parentThreadMembers = []; + const sortedMembers = React.useMemo(() => { + const nonFriends = []; + const blockedUsers = []; + const friends = []; + const containingThreadMembers = []; + const parentThreadMembers = []; - for (const userResult of userResults) { - const { relationshipStatus } = userResult; - if ( - relationshipStatus && - blockedRelationshipsStatuses.has(relationshipStatus) - ) { - blockedUsers.push(userResult); - } else if (userResult.isMemberOfParentThread) { - parentThreadMembers.push(userResult); - } else if (userResult.isMemberOfContainingThread) { - containingThreadMembers.push(userResult); - } else if (relationshipStatus === userRelationshipStatus.FRIEND) { - friends.push(userResult); - } else { - nonFriends.push(userResult); - } - } - - const sortedResults = parentThreadMembers - .concat(containingThreadMembers) - .concat(friends) - .concat(nonFriends) - .concat(blockedUsers); - - return sortedResults.map( - ({ - isMemberOfContainingThread, - isMemberOfParentThread, - relationshipStatus, - ...result - }) => { - let notice, alert; - const username = result.username; + for (const userResult of userResults) { + const { relationshipStatus } = userResult; if ( relationshipStatus && blockedRelationshipsStatuses.has(relationshipStatus) ) { - notice = 'user is blocked'; - alert = { - title: 'User is blocked', - text: - `Before you add ${username} to this chat, ` + - 'you’ll need to unblock them. You can do this from the Block List ' + - 'in the Profile tab.', - }; - } else if (!isMemberOfContainingThread && containingThreadInfo) { - if (threadType !== threadTypes.SIDEBAR) { - notice = 'not in community'; + blockedUsers.push(userResult); + } else if (userResult.isMemberOfParentThread) { + parentThreadMembers.push(userResult); + } else if (userResult.isMemberOfContainingThread) { + containingThreadMembers.push(userResult); + } else if (relationshipStatus === userRelationshipStatus.FRIEND) { + friends.push(userResult); + } else { + nonFriends.push(userResult); + } + } + + const sortedResults = parentThreadMembers + .concat(containingThreadMembers) + .concat(friends) + .concat(nonFriends) + .concat(blockedUsers); + + return sortedResults.map( + ({ + isMemberOfContainingThread, + isMemberOfParentThread, + relationshipStatus, + ...result + }) => { + let notice, alert; + const username = result.username; + if ( + relationshipStatus && + blockedRelationshipsStatuses.has(relationshipStatus) + ) { + notice = 'user is blocked'; alert = { - title: 'Not in community', - text: 'You can only add members of the community to this chat', + title: 'User is blocked', + text: + `Before you add ${username} to this chat, ` + + 'you’ll need to unblock them. You can do this from the Block List ' + + 'in the Profile tab.', }; - } else { - notice = 'not in parent chat'; + } else if (!isMemberOfContainingThread && containingThreadInfo) { + if (threadType !== threadTypes.SIDEBAR) { + notice = 'not in community'; + alert = { + title: 'Not in community', + text: 'You can only add members of the community to this chat', + }; + } else { + notice = 'not in parent chat'; + alert = { + title: 'Not in parent chat', + text: 'You can only add members of the parent chat to a thread', + }; + } + } else if ( + !containingThreadInfo && + relationshipStatus !== userRelationshipStatus.FRIEND + ) { + notice = notFriendNotice; alert = { - title: 'Not in parent chat', - text: 'You can only add members of the parent chat to a thread', + title: 'Not a friend', + text: + `Before you add ${username} to this chat, ` + + 'you’ll need to send them a friend request. ' + + 'You can do this from the Friend List in the Profile tab.', }; + } else if (parentThreadInfo && !isMemberOfParentThread) { + notice = 'not in parent chat'; } - } else if ( - !containingThreadInfo && - relationshipStatus !== userRelationshipStatus.FRIEND - ) { - notice = notFriendNotice; - alert = { - title: 'Not a friend', - text: - `Before you add ${username} to this chat, ` + - 'you’ll need to send them a friend request. ' + - 'You can do this from the Friend List in the Profile tab.', - }; - } else if (parentThreadInfo && !isMemberOfParentThread) { - notice = 'not in parent chat'; - } - if (notice) { - result = { ...result, notice }; - } - if (alert) { - result = { ...result, alert }; - } - return result; - }, - ); + if (notice) { + result = { ...result, notice }; + } + if (alert) { + result = { ...result, alert }; + } + return result; + }, + ); + }, [containingThreadInfo, parentThreadInfo, userResults, threadType]); + + return sortedMembers; } function useSearchMessages(): ( @@ -381,7 +385,7 @@ } export { - getPotentialMemberItems, + usePotentialMemberItems, notFriendNotice, useSearchMessages, useSearchUsers, 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 @@ -17,7 +17,7 @@ userInfoSelectorForPotentialMembers, userSearchIndexForPotentialMembers, } from 'lib/selectors/user-selectors.js'; -import { getPotentialMemberItems } from 'lib/shared/search-utils.js'; +import { usePotentialMemberItems } from 'lib/shared/search-utils.js'; import { threadInFilterList, userIsMember } from 'lib/shared/thread-utils.js'; import { type ThreadType, threadTypes } from 'lib/types/thread-types-enum.js'; import type { ThreadInfo } from 'lib/types/thread-types.js'; @@ -200,27 +200,15 @@ const communityThreadInfo = useSelector(state => community ? threadInfoSelector(state)[community] : null, ); - const userSearchResults = React.useMemo( - () => - getPotentialMemberItems({ - text: usernameInputText, - userInfos: otherUserInfos, - searchIndex: userSearchIndex, - excludeUserIDs: userInfoInputIDs, - inputParentThreadInfo: parentThreadInfo, - inputCommunityThreadInfo: communityThreadInfo, - threadType, - }), - [ - usernameInputText, - otherUserInfos, - userSearchIndex, - userInfoInputIDs, - parentThreadInfo, - communityThreadInfo, - threadType, - ], - ); + const userSearchResults = usePotentialMemberItems({ + text: usernameInputText, + userInfos: otherUserInfos, + searchIndex: userSearchIndex, + excludeUserIDs: userInfoInputIDs, + inputParentThreadInfo: parentThreadInfo, + inputCommunityThreadInfo: communityThreadInfo, + threadType, + }); const existingThreads: $ReadOnlyArray = React.useMemo(() => { if (userInfoInputIDs.length === 0) { 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 @@ -13,7 +13,7 @@ userSearchIndexForPotentialMembers, } from 'lib/selectors/user-selectors.js'; import { - getPotentialMemberItems, + usePotentialMemberItems, useSearchUsers, } from 'lib/shared/search-utils.js'; import { @@ -253,21 +253,13 @@ const serverSearchResults = useSearchUsers(usernameInputText); - const userSearchResults = React.useMemo(() => { - return getPotentialMemberItems({ - text: usernameInputText, - userInfos: otherUserInfos, - searchIndex: userSearchIndex, - excludeUserIDs: userInfoInputArray.map(userInfo => userInfo.id), - includeServerSearchUsers: serverSearchResults, - }); - }, [ - usernameInputText, - otherUserInfos, - userSearchIndex, - userInfoInputArray, - serverSearchResults, - ]); + const userSearchResults = usePotentialMemberItems({ + text: usernameInputText, + userInfos: otherUserInfos, + searchIndex: userSearchIndex, + excludeUserIDs: userInfoInputArray.map(userInfo => userInfo.id), + includeServerSearchUsers: serverSearchResults, + }); const [baseThreadInfo, setBaseThreadInfo] = React.useState( props.route.params.threadInfo, 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 @@ -14,7 +14,7 @@ userInfoSelectorForPotentialMembers, userSearchIndexForPotentialMembers, } from 'lib/selectors/user-selectors.js'; -import { getPotentialMemberItems } from 'lib/shared/search-utils.js'; +import { usePotentialMemberItems } from 'lib/shared/search-utils.js'; import { threadActualMembers } from 'lib/shared/thread-utils.js'; import type { ThreadInfo } from 'lib/types/thread-types.js'; import { type AccountUserInfo } from 'lib/types/user-types.js'; @@ -173,27 +173,15 @@ const communityThreadInfo = useSelector(state => community ? threadInfoSelector(state)[community] : null, ); - const userSearchResults = React.useMemo( - () => - getPotentialMemberItems({ - text: usernameInputText, - userInfos: otherUserInfos, - searchIndex: userSearchIndex, - excludeUserIDs, - inputParentThreadInfo: parentThreadInfo, - inputCommunityThreadInfo: communityThreadInfo, - threadType: threadInfo.type, - }), - [ - usernameInputText, - otherUserInfos, - userSearchIndex, - excludeUserIDs, - parentThreadInfo, - communityThreadInfo, - threadInfo.type, - ], - ); + const userSearchResults = usePotentialMemberItems({ + text: usernameInputText, + userInfos: otherUserInfos, + searchIndex: userSearchIndex, + excludeUserIDs, + inputParentThreadInfo: parentThreadInfo, + inputCommunityThreadInfo: communityThreadInfo, + threadType: threadInfo.type, + }); const onChangeTagInput = React.useCallback( (newUserInfoInputArray: $ReadOnlyArray) => { 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 @@ -13,7 +13,7 @@ userInfoSelectorForPotentialMembers, userSearchIndexForPotentialMembers, } from 'lib/selectors/user-selectors.js'; -import { getPotentialMemberItems } from 'lib/shared/search-utils.js'; +import { usePotentialMemberItems } from 'lib/shared/search-utils.js'; import type { LoadingStatus } from 'lib/types/loading-types.js'; import { threadTypes } from 'lib/types/thread-types-enum.js'; import type { AccountUserInfo } from 'lib/types/user-types.js'; @@ -144,25 +144,15 @@ setOptions, ]); - const userSearchResults = React.useMemo( - () => - getPotentialMemberItems({ - text: usernameInputText, - userInfos: otherUserInfos, - searchIndex: userSearchIndex, - excludeUserIDs: selectedUserIDs, - threadType: announcement - ? threadTypes.COMMUNITY_ANNOUNCEMENT_ROOT - : threadTypes.COMMUNITY_ROOT, - }), - [ - announcement, - otherUserInfos, - selectedUserIDs, - userSearchIndex, - usernameInputText, - ], - ); + const userSearchResults = usePotentialMemberItems({ + text: usernameInputText, + userInfos: otherUserInfos, + searchIndex: userSearchIndex, + excludeUserIDs: selectedUserIDs, + threadType: announcement + ? threadTypes.COMMUNITY_ANNOUNCEMENT_ROOT + : threadTypes.COMMUNITY_ROOT, + }); const onSelectUser = React.useCallback( ({ id }: AccountUserInfo) => { 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 @@ -11,7 +11,7 @@ import { useENSNames } from 'lib/hooks/ens-cache.js'; import { userSearchIndexForPotentialMembers } from 'lib/selectors/user-selectors.js'; import { - getPotentialMemberItems, + usePotentialMemberItems, useSearchUsers, notFriendNotice, } from 'lib/shared/search-utils.js'; @@ -60,23 +60,13 @@ const serverSearchResults = useSearchUsers(usernameInputText); - const userListItems = React.useMemo( - () => - getPotentialMemberItems({ - text: usernameInputText, - userInfos: otherUserInfos, - searchIndex: userSearchIndex, - excludeUserIDs: userInfoInputIDs, - includeServerSearchUsers: serverSearchResults, - }), - [ - usernameInputText, - otherUserInfos, - userSearchIndex, - userInfoInputIDs, - serverSearchResults, - ], - ); + const userListItems = usePotentialMemberItems({ + text: usernameInputText, + userInfos: otherUserInfos, + searchIndex: userSearchIndex, + excludeUserIDs: userInfoInputIDs, + includeServerSearchUsers: serverSearchResults, + }); 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 @@ -12,7 +12,7 @@ userSearchIndexForPotentialMembers, userInfoSelectorForPotentialMembers, } from 'lib/selectors/user-selectors.js'; -import { getPotentialMemberItems } from 'lib/shared/search-utils.js'; +import { usePotentialMemberItems } from 'lib/shared/search-utils.js'; import { threadActualMembers } from 'lib/shared/thread-utils.js'; import { useDispatchActionPromise } from 'lib/utils/action-utils.js'; @@ -54,27 +54,15 @@ [pendingUsersToAdd, threadInfo.members], ); - const userSearchResults = React.useMemo( - () => - getPotentialMemberItems({ - text: searchText, - userInfos: otherUserInfos, - searchIndex: userSearchIndex, - excludeUserIDs, - inputParentThreadInfo: parentThreadInfo, - inputCommunityThreadInfo: communityThreadInfo, - threadType: threadInfo.type, - }), - [ - communityThreadInfo, - excludeUserIDs, - otherUserInfos, - parentThreadInfo, - searchText, - threadInfo.type, - userSearchIndex, - ], - ); + const userSearchResults = usePotentialMemberItems({ + text: searchText, + userInfos: otherUserInfos, + searchIndex: userSearchIndex, + excludeUserIDs, + inputParentThreadInfo: parentThreadInfo, + inputCommunityThreadInfo: communityThreadInfo, + threadType: threadInfo.type, + }); const userSearchResultsWithENSNames = useENSNames(userSearchResults); const onSwitchUser = React.useCallback(