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 @@ -4,7 +4,11 @@ import { messageID } from './message-utils.js'; import SearchIndex from './search-index.js'; -import { getContainingThreadID, userIsMember } from './thread-utils.js'; +import { + getContainingThreadID, + userIsMember, + userSupportsThickThreads, +} from './thread-utils.js'; import { searchMessagesActionTypes, useSearchMessages as useSearchMessagesAction, @@ -24,6 +28,7 @@ } from '../selectors/chat-selectors.js'; import { useUserSearchIndex } from '../selectors/nav-selectors.js'; import { relationshipBlockedInEitherDirection } from '../shared/relationship-utils.js'; +import type { AuxUserInfos } from '../types/aux-user-types.js'; import type { MessageInfo, RawMessageInfo } from '../types/message-types.js'; import type { RoleInfo, @@ -36,6 +41,7 @@ import { type ThreadType, threadTypeIsSidebar, + threadTypeIsThick, } from '../types/thread-types-enum.js'; import type { AccountUserInfo, @@ -52,7 +58,7 @@ function appendUserInfo({ results, - excludeUserIDs, + shouldExcludeUserFromResult, userInfo, parentThreadInfo, communityThreadInfo, @@ -65,14 +71,14 @@ isMemberOfContainingThread: boolean, }, }, - +excludeUserIDs: $ReadOnlyArray, + +shouldExcludeUserFromResult: (userID: string) => boolean, +userInfo: AccountUserInfo | GlobalAccountUserInfo, +parentThreadInfo: ?ThreadInfo, +communityThreadInfo: ?ThreadInfo, +containingThreadInfo: ?ThreadInfo, }) { const { id } = userInfo; - if (excludeUserIDs.includes(id) || id in results) { + if (id in results || shouldExcludeUserFromResult(id)) { return; } @@ -104,6 +110,7 @@ function usePotentialMemberItems({ text, userInfos, + auxUserInfos, excludeUserIDs, includeServerSearchUsers, inputParentThreadInfo, @@ -112,6 +119,7 @@ }: { +text: string, +userInfos: { +[id: string]: AccountUserInfo }, + +auxUserInfos: AuxUserInfos, +excludeUserIDs: $ReadOnlyArray, +includeServerSearchUsers?: $ReadOnlyArray, +inputParentThreadInfo?: ?ThreadInfo, @@ -149,6 +157,20 @@ return null; }, [containingThreadID, communityThreadInfo, parentThreadInfo]); + const shouldExcludeUserFromResult = React.useCallback( + (userID: string) => { + if (excludeUserIDs.includes(userID)) { + return true; + } + return !!( + threadType && + threadTypeIsThick(threadType) && + !userSupportsThickThreads(userID, auxUserInfos) + ); + }, + [auxUserInfos, excludeUserIDs, threadType], + ); + const filteredUserResults = React.useMemo(() => { const results: { [id: string]: { @@ -161,7 +183,7 @@ for (const id in userInfos) { appendUserInfo({ results, - excludeUserIDs, + shouldExcludeUserFromResult, userInfo: userInfos[id], parentThreadInfo, communityThreadInfo, @@ -173,7 +195,7 @@ for (const id of ids) { appendUserInfo({ results, - excludeUserIDs, + shouldExcludeUserFromResult, userInfo: userInfos[id], parentThreadInfo, communityThreadInfo, @@ -186,7 +208,7 @@ for (const userInfo of includeServerSearchUsers) { appendUserInfo({ results, - excludeUserIDs, + shouldExcludeUserFromResult, userInfo, parentThreadInfo, communityThreadInfo, @@ -214,14 +236,14 @@ return userResults; }, [ - text, - userInfos, - searchIndex, - excludeUserIDs, + communityThreadInfo, + containingThreadInfo, includeServerSearchUsers, parentThreadInfo, - containingThreadInfo, - communityThreadInfo, + searchIndex, + shouldExcludeUserFromResult, + text, + userInfos, ]); const sortedMembers = React.useMemo(() => { diff --git a/lib/shared/thread-actions-utils.js b/lib/shared/thread-actions-utils.js --- a/lib/shared/thread-actions-utils.js +++ b/lib/shared/thread-actions-utils.js @@ -6,6 +6,7 @@ threadIsPending, threadOtherMembers, pendingThreadType, + userSupportsThickThreads, } from './thread-utils.js'; import { newThreadActionTypes, @@ -136,10 +137,8 @@ otherMemberIDs.length > 0, 'otherMemberIDs should not be empty for threads', ); - const allUsersSupportThickThreads = otherMemberIDs.every( - memberID => - auxUserInfos[memberID]?.deviceList && - auxUserInfos[memberID].deviceList.devices.length > 0, + const allUsersSupportThickThreads = otherMemberIDs.every(memberID => + userSupportsThickThreads(memberID, auxUserInfos), ); if (threadTypeIsThick(threadInfo.type) && allUsersSupportThickThreads) { const type = assertThickThreadType( diff --git a/lib/shared/thread-utils.js b/lib/shared/thread-utils.js --- a/lib/shared/thread-utils.js +++ b/lib/shared/thread-utils.js @@ -40,6 +40,7 @@ getRelativeMemberInfos, usersWithPersonalThreadSelector, } from '../selectors/user-selectors.js'; +import type { AuxUserInfos } from '../types/aux-user-types.js'; import type { RelativeMemberInfo, RawThreadInfo, @@ -1795,6 +1796,16 @@ }; } +function userSupportsThickThreads( + userID: string, + auxUserInfos: AuxUserInfos, +): boolean { + return ( + !!auxUserInfos[userID]?.deviceList && + auxUserInfos[userID].deviceList.devices.length > 0 + ); +} + export { threadHasPermission, useCommunityRootMembersToRole, @@ -1861,4 +1872,5 @@ extractMentionedMembers, isMemberActive, createThreadTimestamps, + userSupportsThickThreads, }; 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 @@ -196,9 +196,11 @@ const communityThreadInfo = useSelector(state => community ? threadInfoSelector(state)[community] : null, ); + const auxUserInfos = useSelector(state => state.auxUserStore.auxUserInfos); const userSearchResults = usePotentialMemberItems({ text: usernameInputText, userInfos: otherUserInfos, + auxUserInfos, excludeUserIDs: userInfoInputIDs, inputParentThreadInfo: parentThreadInfo, inputCommunityThreadInfo: communityThreadInfo, 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 @@ -267,9 +267,11 @@ const serverSearchResults = useSearchUsers(usernameInputText); + const auxUserInfos = useSelector(state => state.auxUserStore.auxUserInfos); const userSearchResults = usePotentialMemberItems({ text: usernameInputText, userInfos: otherUserInfos, + auxUserInfos, excludeUserIDs: userInfoInputArray.map(userInfo => userInfo.id), includeServerSearchUsers: serverSearchResults, }); 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 @@ -187,9 +187,11 @@ const communityThreadInfo = useSelector(state => community ? threadInfoSelector(state)[community] : null, ); + const auxUserInfos = useSelector(state => state.auxUserStore.auxUserInfos); const userSearchResults = usePotentialMemberItems({ text: usernameInputText, userInfos: otherUserInfos, + auxUserInfos, excludeUserIDs, inputParentThreadInfo: parentThreadInfo, inputCommunityThreadInfo: communityThreadInfo, 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 @@ -31,6 +31,7 @@ import type { InputState } from '../input/input-state.js'; import Alert from '../modals/alert.react.js'; import { updateNavInfoActionType } from '../redux/action-types.js'; +import { useSelector } from '../redux/redux-utils.js'; type Props = { +userInfoInputArray: $ReadOnlyArray, @@ -57,9 +58,11 @@ const searchResults = useSearchUsers(usernameInputText); + const auxUserInfos = useSelector(state => state.auxUserStore.auxUserInfos); const userListItems = usePotentialMemberItems({ text: usernameInputText, userInfos: otherUserInfos, + auxUserInfos, excludeUserIDs: userInfoInputIDs, includeServerSearchUsers: searchResults, }); diff --git a/web/settings/relationship/add-users-utils.js b/web/settings/relationship/add-users-utils.js --- a/web/settings/relationship/add-users-utils.js +++ b/web/settings/relationship/add-users-utils.js @@ -147,9 +147,11 @@ [previouslySelectedUsers, threadInfo.members], ); + const auxUserInfos = useSelector(state => state.auxUserStore.auxUserInfos); const userSearchResults = usePotentialMemberItems({ text: searchText, userInfos: otherUserInfos, + auxUserInfos, excludeUserIDs, inputParentThreadInfo: parentThreadInfo, inputCommunityThreadInfo: communityThreadInfo, @@ -213,9 +215,11 @@ [previouslySelectedUsers], ); + const auxUserInfos = useSelector(state => state.auxUserStore.auxUserInfos); const userSearchResults = usePotentialMemberItems({ text: searchText, userInfos: otherUserInfos, + auxUserInfos, excludeUserIDs: previouslySelectedUserIDs, inputParentThreadInfo: parentThreadInfo, inputCommunityThreadInfo: communityThreadInfo,