Page MenuHomePhorge

D10387.1765034806.diff
No OneTemporary

Size
14 KB
Referenced Files
None
Subscribers
None

D10387.1765034806.diff

diff --git a/lib/selectors/user-selectors.js b/lib/selectors/user-selectors.js
--- a/lib/selectors/user-selectors.js
+++ b/lib/selectors/user-selectors.js
@@ -7,8 +7,6 @@
getAvatarForUser,
getRandomDefaultEmojiAvatar,
} from '../shared/avatar-utils.js';
-import SearchIndex from '../shared/search-index.js';
-import SentencePrefixSearchIndex from '../shared/sentence-prefix-search-index.js';
import { getSingleOtherUser } from '../shared/thread-utils.js';
import type { ClientEmojiAvatar } from '../types/avatar-types';
import type { MinimallyEncodedRawThreadInfo } from '../types/minimally-encoded-thread-permissions-types.js';
@@ -170,30 +168,6 @@
state.dataLoaded
);
-const addUsersToSearchIndex = (
- userInfos: UserInfos,
- searchIndex: SearchIndex | SentencePrefixSearchIndex,
-): void => {
- for (const id in userInfos) {
- const { username } = userInfos[id];
- if (!username) {
- continue;
- }
- searchIndex.addEntry(id, username);
- }
-};
-
-const userStoreMentionSearchIndex: (
- state: BaseAppState<>,
-) => SentencePrefixSearchIndex = createSelector(
- (state: BaseAppState<>) => state.userStore.userInfos,
- (userInfos: UserInfos) => {
- const searchIndex = new SentencePrefixSearchIndex();
- addUsersToSearchIndex(userInfos, searchIndex);
- return searchIndex;
- },
-);
-
const usersWithPersonalThreadSelector: (
state: BaseAppState<>,
) => $ReadOnlySet<string> = createSelector(
@@ -240,7 +214,6 @@
relativeMemberInfoSelectorForMembersOfThread,
userInfoSelectorForPotentialMembers,
isLoggedIn,
- userStoreMentionSearchIndex,
usersWithPersonalThreadSelector,
savedEmojiAvatarSelectorForCurrentUser,
};
diff --git a/lib/shared/mention-utils.js b/lib/shared/mention-utils.js
--- a/lib/shared/mention-utils.js
+++ b/lib/shared/mention-utils.js
@@ -1,9 +1,13 @@
// @flow
+import * as React from 'react';
+
import { oldValidUsernameRegexString } from './account-utils.js';
import SentencePrefixSearchIndex from './sentence-prefix-search-index.js';
import { threadOtherMembers } from './thread-utils.js';
import { stringForUserExplicit } from './user-utils.js';
+import { useENSNames } from '../hooks/ens-cache.js';
+import { useUserSearchIndex } from '../selectors/nav-selectors.js';
import { threadTypes } from '../types/thread-types-enum.js';
import type {
ChatMentionCandidates,
@@ -100,21 +104,34 @@
return null;
}
-function getMentionTypeaheadUserSuggestions(
- userSearchIndex: SentencePrefixSearchIndex,
+const useENSNamesOptions = { allAtOnce: true };
+function useMentionTypeaheadUserSuggestions(
threadMembers: $ReadOnlyArray<RelativeMemberInfo>,
viewerID: ?string,
- usernamePrefix: string,
+ typeaheadMatchedStrings: ?TypeaheadMatchedStrings,
): $ReadOnlyArray<MentionTypeaheadUserSuggestionItem> {
- const userIDs = userSearchIndex.getSearchResults(usernamePrefix);
- const usersInThread = threadOtherMembers(threadMembers, viewerID);
-
- return usersInThread
- .filter(user => usernamePrefix.length === 0 || userIDs.includes(user.id))
- .sort((userA, userB) =>
- stringForUserExplicit(userA).localeCompare(stringForUserExplicit(userB)),
- )
- .map(userInfo => ({ type: 'user', userInfo }));
+ const userSearchIndex = useUserSearchIndex(threadMembers);
+ const resolvedThredMembers = useENSNames(threadMembers, useENSNamesOptions);
+ const usernamePrefix: ?string = typeaheadMatchedStrings?.query;
+
+ return React.useMemo(() => {
+ // If typeaheadMatchedStrings is undefined, we want to return no results
+ if (usernamePrefix === undefined || usernamePrefix === null) {
+ return [];
+ }
+
+ const userIDs = userSearchIndex.getSearchResults(usernamePrefix);
+ const usersInThread = threadOtherMembers(resolvedThredMembers, viewerID);
+
+ return usersInThread
+ .filter(user => usernamePrefix.length === 0 || userIDs.includes(user.id))
+ .sort((userA, userB) =>
+ stringForUserExplicit(userA).localeCompare(
+ stringForUserExplicit(userB),
+ ),
+ )
+ .map(userInfo => ({ type: 'user', userInfo }));
+ }, [userSearchIndex, resolvedThredMembers, usernamePrefix, viewerID]);
}
function getMentionTypeaheadChatSuggestions(
@@ -157,31 +174,33 @@
return { newText, newSelectionStart };
}
-function getUserMentionsCandidates(
+function useUserMentionsCandidates(
threadInfo: ThreadInfo,
parentThreadInfo: ?ThreadInfo,
): $ReadOnlyArray<RelativeMemberInfo> {
- if (threadInfo.type !== threadTypes.SIDEBAR) {
- return threadInfo.members;
- }
- if (parentThreadInfo) {
- return parentThreadInfo.members;
- }
- // This scenario should not occur unless the user logs out while looking at a
- // sidebar. In that scenario, the Redux store may be cleared before ReactNav
- // finishes transitioning away from the previous screen
- return [];
+ return React.useMemo(() => {
+ if (threadInfo.type !== threadTypes.SIDEBAR) {
+ return threadInfo.members;
+ }
+ if (parentThreadInfo) {
+ return parentThreadInfo.members;
+ }
+ // This scenario should not occur unless the user logs out while looking at
+ // a sidebar. In that scenario, the Redux store may be cleared before
+ // ReactNav finishes transitioning away from the previous screen
+ return [];
+ }, [threadInfo, parentThreadInfo]);
}
export {
markdownUserMentionRegex,
isUserMentioned,
extractUserMentionsFromText,
- getMentionTypeaheadUserSuggestions,
+ useMentionTypeaheadUserSuggestions,
getMentionTypeaheadChatSuggestions,
getNewTextAndSelection,
getTypeaheadRegexMatches,
- getUserMentionsCandidates,
+ useUserMentionsCandidates,
chatMentionRegex,
encodeChatMentionText,
decodeChatMentionText,
diff --git a/native/chat/chat-input-bar.react.js b/native/chat/chat-input-bar.react.js
--- a/native/chat/chat-input-bar.react.js
+++ b/native/chat/chat-input-bar.react.js
@@ -37,15 +37,14 @@
} from 'lib/hooks/chat-mention-hooks.js';
import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js';
import { threadInfoSelector } from 'lib/selectors/thread-selectors.js';
-import { userStoreMentionSearchIndex } from 'lib/selectors/user-selectors.js';
import { colorIsDark } from 'lib/shared/color-utils.js';
import { useEditMessage } from 'lib/shared/edit-messages-utils.js';
import {
- getMentionTypeaheadUserSuggestions,
+ useMentionTypeaheadUserSuggestions,
getMentionTypeaheadChatSuggestions,
getTypeaheadRegexMatches,
type Selection,
- getUserMentionsCandidates,
+ useUserMentionsCandidates,
type MentionTypeaheadSuggestionItem,
type TypeaheadMatchedStrings,
} from 'lib/shared/mention-utils.js';
@@ -297,7 +296,6 @@
+dispatchActionPromise: DispatchActionPromise,
+joinThread: (request: ClientThreadJoinRequest) => Promise<ThreadJoinPayload>,
+inputState: ?InputState,
- +userSearchIndex: SentencePrefixSearchIndex,
+userMentionsCandidates: $ReadOnlyArray<RelativeMemberInfo>,
+chatMentionSearchIndex: SentencePrefixSearchIndex,
+chatMentionCandidates: ChatMentionCandidates,
@@ -1258,8 +1256,6 @@
const dispatchActionPromise = useDispatchActionPromise();
const callJoinThread = useJoinThread();
- const userSearchIndex = useSelector(userStoreMentionSearchIndex);
-
const { getChatMentionSearchIndex } = useChatMentionContext();
const chatMentionSearchIndex = getChatMentionSearchIndex(props.threadInfo);
@@ -1268,7 +1264,7 @@
parentThreadID ? threadInfoSelector(state)[parentThreadID] : null,
);
- const userMentionsCandidates = getUserMentionsCandidates(
+ const userMentionsCandidates = useUserMentionsCandidates(
props.threadInfo,
parentThreadInfo,
);
@@ -1303,50 +1299,43 @@
[selectionState.text, selectionState.selection],
);
- const typeaheadResults: {
- typeaheadMatchedStrings: ?TypeaheadMatchedStrings,
- suggestions: $ReadOnlyArray<MentionTypeaheadSuggestionItem>,
- } = React.useMemo(() => {
- if (!typeaheadRegexMatches) {
+ const typeaheadMatchedStrings: ?TypeaheadMatchedStrings =
+ React.useMemo(() => {
+ if (typeaheadRegexMatches === null) {
+ return null;
+ }
return {
- typeaheadMatchedStrings: null,
- suggestions: [],
+ textBeforeAtSymbol: typeaheadRegexMatches[1] ?? '',
+ query: typeaheadRegexMatches[4] ?? '',
};
- }
+ }, [typeaheadRegexMatches]);
- const typeaheadMatchedStrings: TypeaheadMatchedStrings = {
- textBeforeAtSymbol: typeaheadRegexMatches[1] ?? '',
- query: typeaheadRegexMatches[4] ?? '',
- };
+ const suggestedUsers = useMentionTypeaheadUserSuggestions(
+ userMentionsCandidates,
+ viewerID,
+ typeaheadMatchedStrings,
+ );
- const suggestedUsers = getMentionTypeaheadUserSuggestions(
- userSearchIndex,
- userMentionsCandidates,
- viewerID,
- typeaheadMatchedStrings.query,
- );
- const suggestedChats = getMentionTypeaheadChatSuggestions(
- chatMentionSearchIndex,
- chatMentionCandidates,
- typeaheadMatchedStrings.query,
- );
- const suggestions: $ReadOnlyArray<MentionTypeaheadSuggestionItem> = [
- ...suggestedUsers,
- ...suggestedChats,
- ];
+ const suggestions: $ReadOnlyArray<MentionTypeaheadSuggestionItem> =
+ React.useMemo(() => {
+ if (!typeaheadRegexMatches || !typeaheadMatchedStrings) {
+ return [];
+ }
- return {
+ const suggestedChats = getMentionTypeaheadChatSuggestions(
+ chatMentionSearchIndex,
+ chatMentionCandidates,
+ typeaheadMatchedStrings.query,
+ );
+
+ return [...suggestedUsers, ...suggestedChats];
+ }, [
+ chatMentionCandidates,
+ chatMentionSearchIndex,
+ typeaheadRegexMatches,
typeaheadMatchedStrings,
- suggestions,
- };
- }, [
- chatMentionCandidates,
- chatMentionSearchIndex,
- typeaheadRegexMatches,
- userMentionsCandidates,
- userSearchIndex,
- viewerID,
- ]);
+ suggestedUsers,
+ ]);
return (
<ChatInputBar
@@ -1366,7 +1355,6 @@
dispatchActionPromise={dispatchActionPromise}
joinThread={callJoinThread}
inputState={inputState}
- userSearchIndex={userSearchIndex}
userMentionsCandidates={userMentionsCandidates}
chatMentionSearchIndex={chatMentionSearchIndex}
chatMentionCandidates={chatMentionCandidates}
@@ -1379,8 +1367,8 @@
messageEditingContext={messageEditingContext}
selectionState={selectionState}
setSelectionState={setSelectionState}
- suggestions={typeaheadResults.suggestions}
- typeaheadMatchedStrings={typeaheadResults.typeaheadMatchedStrings}
+ suggestions={suggestions}
+ typeaheadMatchedStrings={typeaheadMatchedStrings}
/>
);
}
diff --git a/web/chat/chat-input-bar.react.js b/web/chat/chat-input-bar.react.js
--- a/web/chat/chat-input-bar.react.js
+++ b/web/chat/chat-input-bar.react.js
@@ -16,14 +16,13 @@
} from 'lib/hooks/chat-mention-hooks.js';
import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js';
import { threadInfoSelector } from 'lib/selectors/thread-selectors.js';
-import { userStoreMentionSearchIndex } from 'lib/selectors/user-selectors.js';
import {
- getMentionTypeaheadUserSuggestions,
getTypeaheadRegexMatches,
- getUserMentionsCandidates,
+ useUserMentionsCandidates,
getMentionTypeaheadChatSuggestions,
type MentionTypeaheadSuggestionItem,
type TypeaheadMatchedStrings,
+ useMentionTypeaheadUserSuggestions,
} from 'lib/shared/mention-utils.js';
import { localIDPrefix, trimMessage } from 'lib/shared/message-utils.js';
import {
@@ -586,7 +585,6 @@
const calendarQuery = useSelector(nonThreadCalendarQuery);
const dispatchActionPromise = useDispatchActionPromise();
const callJoinThread = useJoinThread();
- const userSearchIndex = useSelector(userStoreMentionSearchIndex);
const { getChatMentionSearchIndex } = useChatMentionContext();
const chatMentionSearchIndex = getChatMentionSearchIndex(props.threadInfo);
@@ -595,7 +593,7 @@
parentThreadID ? threadInfoSelector(state)[parentThreadID] : null,
);
- const userMentionsCandidates = getUserMentionsCandidates(
+ const userMentionsCandidates = useUserMentionsCandidates(
props.threadInfo,
parentThreadInfo,
);
@@ -617,17 +615,16 @@
[props.inputState.textCursorPosition, props.inputState.draft],
);
- const typeaheadMatchedStrings: ?TypeaheadMatchedStrings = React.useMemo(
- () =>
- typeaheadRegexMatches !== null
- ? {
- textBeforeAtSymbol:
- typeaheadRegexMatches.groups?.textPrefix ?? '',
- query: typeaheadRegexMatches.groups?.mentionText ?? '',
- }
- : null,
- [typeaheadRegexMatches],
- );
+ const typeaheadMatchedStrings: ?TypeaheadMatchedStrings =
+ React.useMemo(() => {
+ if (typeaheadRegexMatches === null) {
+ return null;
+ }
+ return {
+ textBeforeAtSymbol: typeaheadRegexMatches.groups?.textPrefix ?? '',
+ query: typeaheadRegexMatches.groups?.mentionText ?? '',
+ };
+ }, [typeaheadRegexMatches]);
React.useEffect(() => {
if (props.inputState.typeaheadState.keepUpdatingThreadMembers) {
@@ -644,16 +641,16 @@
chatMentionCandidates,
]);
+ const suggestedUsers = useMentionTypeaheadUserSuggestions(
+ props.inputState.typeaheadState.frozenUserMentionsCandidates,
+ viewerID,
+ typeaheadMatchedStrings,
+ );
+
const suggestions = React.useMemo(() => {
if (!typeaheadMatchedStrings) {
return ([]: $ReadOnlyArray<MentionTypeaheadSuggestionItem>);
}
- const suggestedUsers = getMentionTypeaheadUserSuggestions(
- userSearchIndex,
- props.inputState.typeaheadState.frozenUserMentionsCandidates,
- viewerID,
- typeaheadMatchedStrings.query,
- );
const suggestedChats = getMentionTypeaheadChatSuggestions(
chatMentionSearchIndex,
props.inputState.typeaheadState.frozenChatMentionsCandidates,
@@ -664,11 +661,9 @@
...suggestedChats,
]: $ReadOnlyArray<MentionTypeaheadSuggestionItem>);
}, [
+ suggestedUsers,
typeaheadMatchedStrings,
- userSearchIndex,
- props.inputState.typeaheadState.frozenUserMentionsCandidates,
props.inputState.typeaheadState.frozenChatMentionsCandidates,
- viewerID,
chatMentionSearchIndex,
]);

File Metadata

Mime Type
text/plain
Expires
Sat, Dec 6, 3:26 PM (17 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5839134
Default Alt Text
D10387.1765034806.diff (14 KB)

Event Timeline