diff --git a/lib/shared/typeahead-utils.js b/lib/shared/typeahead-utils.js --- a/lib/shared/typeahead-utils.js +++ b/lib/shared/typeahead-utils.js @@ -2,17 +2,22 @@ import type { RelativeMemberInfo } from '../types/thread-types'; import SearchIndex from './search-index'; +import { threadOtherMembers } from './thread-utils'; import { stringForUserExplicit } from './user-utils'; function getTypeaheadUserSuggestions( userSearchIndex: SearchIndex, - usersInThread: $ReadOnlyArray, - typedPrefix: string, + threadMembers: $ReadOnlyArray, + viewerID: ?string, + typedUsernamePrefix: string, ): $ReadOnlyArray { - const userIDs = userSearchIndex.getSearchResults(typedPrefix); + const userIDs = userSearchIndex.getSearchResults(typedUsernamePrefix); + const usersInThread = threadOtherMembers(threadMembers, viewerID); return usersInThread - .filter(user => typedPrefix.length === 0 || userIDs.includes(user.id)) + .filter( + user => typedUsernamePrefix.length === 0 || userIDs.includes(user.id), + ) .sort((userA, userB) => stringForUserExplicit(userA).localeCompare(stringForUserExplicit(userB)), ); 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 @@ -15,7 +15,6 @@ relativeMemberInfoSelectorForMembersOfThread, } from 'lib/selectors/user-selectors'; import { localIDPrefix, trimMessage } from 'lib/shared/message-utils'; -import SearchIndex from 'lib/shared/search-index'; import { threadHasPermission, viewerIsMember, @@ -23,6 +22,7 @@ threadActualMembers, checkIfDefaultMembersAreVoiced, } from 'lib/shared/thread-utils'; +import { getTypeaheadUserSuggestions } from 'lib/shared/typeahead-utils'; import type { CalendarQuery } from 'lib/types/entry-types'; import type { LoadingStatus } from 'lib/types/loading-types'; import { messageTypes } from 'lib/types/message-types'; @@ -73,9 +73,8 @@ +dispatchActionPromise: DispatchActionPromise, // async functions that hit server APIs +joinThread: (request: ClientThreadJoinRequest) => Promise, - +userSearchIndex: SearchIndex, - +threadMembers: $ReadOnlyArray, +typeaheadMatchedStrings: ?TypeaheadMatchedStrings, + +suggestedUsers: $ReadOnlyArray, }; export type TypeaheadMatchedStrings = { +entireText: string, @@ -331,15 +330,17 @@ } let typeaheadTooltip; - if (this.props.typeaheadMatchedStrings && this.textarea) { + if ( + this.props.suggestedUsers.length > 0 && + this.props.typeaheadMatchedStrings && + this.textarea + ) { typeaheadTooltip = ( ); } @@ -549,13 +550,26 @@ typeaheadRegexMatches !== null ? { entireText: typeaheadRegexMatches[0], - textBeforeAtSymbol: typeaheadRegexMatches[1], - usernamePrefix: typeaheadRegexMatches[2], + textBeforeAtSymbol: + typeaheadRegexMatches.groups?.textPrefix ?? '', + usernamePrefix: typeaheadRegexMatches.groups?.username ?? '', } : null, [typeaheadRegexMatches], ); + const suggestedUsers: $ReadOnlyArray = React.useMemo(() => { + if (!typeaheadMatchedStrings) { + return []; + } + return getTypeaheadUserSuggestions( + userSearchIndex, + threadMembers, + viewerID, + typeaheadMatchedStrings.usernamePrefix, + ); + }, [userSearchIndex, threadMembers, viewerID, typeaheadMatchedStrings]); + return ( ); }, diff --git a/web/chat/typeahead-tooltip.react.js b/web/chat/typeahead-tooltip.react.js --- a/web/chat/typeahead-tooltip.react.js +++ b/web/chat/typeahead-tooltip.react.js @@ -3,9 +3,6 @@ import classNames from 'classnames'; import * as React from 'react'; -import SearchIndex from 'lib/shared/search-index'; -import { threadOtherMembers } from 'lib/shared/thread-utils'; -import { getTypeaheadUserSuggestions } from 'lib/shared/typeahead-utils'; import type { RelativeMemberInfo } from 'lib/types/thread-types'; import Button from '../components/button.react'; @@ -20,21 +17,13 @@ export type TypeaheadTooltipProps = { +inputState: InputState, +textarea: HTMLTextAreaElement, - +userSearchIndex: SearchIndex, - +threadMembers: $ReadOnlyArray, - +viewerID: ?string, +matchedStrings: TypeaheadMatchedStrings, + +suggestedUsers: $ReadOnlyArray, }; function TypeaheadTooltip(props: TypeaheadTooltipProps): React.Node { - const { - inputState, - textarea, - userSearchIndex, - threadMembers, - viewerID, - matchedStrings, - } = props; + const { inputState, textarea, matchedStrings, suggestedUsers } = props; + const [isVisibleForAnimation, setIsVisibleForAnimation] = React.useState( false, ); @@ -48,21 +37,8 @@ const { entireText: matchedText, textBeforeAtSymbol: matchedTextBeforeAtSymbol, - usernamePrefix: matchedUsernamePrefix, } = matchedStrings; - const typedPrefix = matchedUsernamePrefix ?? ''; - - const suggestedUsers = React.useMemo( - () => - getTypeaheadUserSuggestions( - userSearchIndex, - threadOtherMembers(threadMembers, viewerID), - typedPrefix, - ), - [userSearchIndex, threadMembers, viewerID, typedPrefix], - ); - const actions = React.useMemo( () => getTypeaheadTooltipActions(