Changeset View
Changeset View
Standalone View
Standalone View
web/chat/chat-input-bar.react.js
Show All 10 Lines | |||||
} from 'lib/actions/thread-actions.js'; | } from 'lib/actions/thread-actions.js'; | ||||
import SWMansionIcon from 'lib/components/SWMansionIcon.react.js'; | import SWMansionIcon from 'lib/components/SWMansionIcon.react.js'; | ||||
import { | import { | ||||
useChatMentionContext, | useChatMentionContext, | ||||
useThreadChatMentionCandidates, | useThreadChatMentionCandidates, | ||||
} from 'lib/hooks/chat-mention-hooks.js'; | } from 'lib/hooks/chat-mention-hooks.js'; | ||||
import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; | import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; | ||||
import { threadInfoSelector } from 'lib/selectors/thread-selectors.js'; | import { threadInfoSelector } from 'lib/selectors/thread-selectors.js'; | ||||
import { userStoreMentionSearchIndex } from 'lib/selectors/user-selectors.js'; | |||||
import { | import { | ||||
getMentionTypeaheadUserSuggestions, | |||||
getTypeaheadRegexMatches, | getTypeaheadRegexMatches, | ||||
getUserMentionsCandidates, | useUserMentionsCandidates, | ||||
getMentionTypeaheadChatSuggestions, | getMentionTypeaheadChatSuggestions, | ||||
type MentionTypeaheadSuggestionItem, | type MentionTypeaheadSuggestionItem, | ||||
type TypeaheadMatchedStrings, | type TypeaheadMatchedStrings, | ||||
useMentionTypeaheadUserSuggestions, | |||||
} from 'lib/shared/mention-utils.js'; | } from 'lib/shared/mention-utils.js'; | ||||
import { localIDPrefix, trimMessage } from 'lib/shared/message-utils.js'; | import { localIDPrefix, trimMessage } from 'lib/shared/message-utils.js'; | ||||
import { | import { | ||||
threadHasPermission, | threadHasPermission, | ||||
viewerIsMember, | viewerIsMember, | ||||
threadFrozenDueToViewerBlock, | threadFrozenDueToViewerBlock, | ||||
threadActualMembers, | threadActualMembers, | ||||
checkIfDefaultMembersAreVoiced, | checkIfDefaultMembersAreVoiced, | ||||
▲ Show 20 Lines • Show All 546 Lines • ▼ Show 20 Lines | React.memo<BaseProps>(function ConnectedChatInputBar(props) { | ||||
); | ); | ||||
const createThreadLoadingStatus = useSelector( | const createThreadLoadingStatus = useSelector( | ||||
createThreadLoadingStatusSelector, | createThreadLoadingStatusSelector, | ||||
); | ); | ||||
const threadCreationInProgress = createThreadLoadingStatus === 'loading'; | const threadCreationInProgress = createThreadLoadingStatus === 'loading'; | ||||
const calendarQuery = useSelector(nonThreadCalendarQuery); | const calendarQuery = useSelector(nonThreadCalendarQuery); | ||||
const dispatchActionPromise = useDispatchActionPromise(); | const dispatchActionPromise = useDispatchActionPromise(); | ||||
const callJoinThread = useJoinThread(); | const callJoinThread = useJoinThread(); | ||||
const userSearchIndex = useSelector(userStoreMentionSearchIndex); | |||||
const { getChatMentionSearchIndex } = useChatMentionContext(); | const { getChatMentionSearchIndex } = useChatMentionContext(); | ||||
const chatMentionSearchIndex = getChatMentionSearchIndex(props.threadInfo); | const chatMentionSearchIndex = getChatMentionSearchIndex(props.threadInfo); | ||||
const { parentThreadID } = props.threadInfo; | const { parentThreadID } = props.threadInfo; | ||||
const parentThreadInfo = useSelector(state => | const parentThreadInfo = useSelector(state => | ||||
parentThreadID ? threadInfoSelector(state)[parentThreadID] : null, | parentThreadID ? threadInfoSelector(state)[parentThreadID] : null, | ||||
); | ); | ||||
const userMentionsCandidates = getUserMentionsCandidates( | const userMentionsCandidates = useUserMentionsCandidates( | ||||
props.threadInfo, | props.threadInfo, | ||||
parentThreadInfo, | parentThreadInfo, | ||||
); | ); | ||||
const chatMentionCandidates = useThreadChatMentionCandidates( | const chatMentionCandidates = useThreadChatMentionCandidates( | ||||
props.threadInfo, | props.threadInfo, | ||||
); | ); | ||||
const typeaheadRegexMatches = React.useMemo( | const typeaheadRegexMatches = React.useMemo( | ||||
() => | () => | ||||
getTypeaheadRegexMatches( | getTypeaheadRegexMatches( | ||||
props.inputState.draft, | props.inputState.draft, | ||||
{ | { | ||||
start: props.inputState.textCursorPosition, | start: props.inputState.textCursorPosition, | ||||
end: props.inputState.textCursorPosition, | end: props.inputState.textCursorPosition, | ||||
}, | }, | ||||
webMentionTypeaheadRegex, | webMentionTypeaheadRegex, | ||||
), | ), | ||||
[props.inputState.textCursorPosition, props.inputState.draft], | [props.inputState.textCursorPosition, props.inputState.draft], | ||||
); | ); | ||||
const typeaheadMatchedStrings: ?TypeaheadMatchedStrings = React.useMemo( | const typeaheadMatchedStrings: ?TypeaheadMatchedStrings = | ||||
() => | React.useMemo(() => { | ||||
typeaheadRegexMatches !== null | if (typeaheadRegexMatches === null) { | ||||
? { | return null; | ||||
textBeforeAtSymbol: | |||||
typeaheadRegexMatches.groups?.textPrefix ?? '', | |||||
query: typeaheadRegexMatches.groups?.mentionText ?? '', | |||||
} | } | ||||
: null, | return { | ||||
[typeaheadRegexMatches], | textBeforeAtSymbol: typeaheadRegexMatches.groups?.textPrefix ?? '', | ||||
); | query: typeaheadRegexMatches.groups?.mentionText ?? '', | ||||
}; | |||||
}, [typeaheadRegexMatches]); | |||||
React.useEffect(() => { | React.useEffect(() => { | ||||
if (props.inputState.typeaheadState.keepUpdatingThreadMembers) { | if (props.inputState.typeaheadState.keepUpdatingThreadMembers) { | ||||
const setter = props.inputState.setTypeaheadState; | const setter = props.inputState.setTypeaheadState; | ||||
setter({ | setter({ | ||||
frozenUserMentionsCandidates: userMentionsCandidates, | frozenUserMentionsCandidates: userMentionsCandidates, | ||||
frozenChatMentionsCandidates: chatMentionCandidates, | frozenChatMentionsCandidates: chatMentionCandidates, | ||||
}); | }); | ||||
} | } | ||||
}, [ | }, [ | ||||
userMentionsCandidates, | userMentionsCandidates, | ||||
props.inputState.setTypeaheadState, | props.inputState.setTypeaheadState, | ||||
props.inputState.typeaheadState.keepUpdatingThreadMembers, | props.inputState.typeaheadState.keepUpdatingThreadMembers, | ||||
chatMentionCandidates, | chatMentionCandidates, | ||||
]); | ]); | ||||
const suggestedUsers = useMentionTypeaheadUserSuggestions( | |||||
props.inputState.typeaheadState.frozenUserMentionsCandidates, | |||||
viewerID, | |||||
typeaheadMatchedStrings, | |||||
); | |||||
const suggestions = React.useMemo(() => { | const suggestions = React.useMemo(() => { | ||||
if (!typeaheadMatchedStrings) { | if (!typeaheadMatchedStrings) { | ||||
return ([]: $ReadOnlyArray<MentionTypeaheadSuggestionItem>); | return ([]: $ReadOnlyArray<MentionTypeaheadSuggestionItem>); | ||||
} | } | ||||
const suggestedUsers = getMentionTypeaheadUserSuggestions( | |||||
userSearchIndex, | |||||
props.inputState.typeaheadState.frozenUserMentionsCandidates, | |||||
viewerID, | |||||
typeaheadMatchedStrings.query, | |||||
); | |||||
const suggestedChats = getMentionTypeaheadChatSuggestions( | const suggestedChats = getMentionTypeaheadChatSuggestions( | ||||
chatMentionSearchIndex, | chatMentionSearchIndex, | ||||
props.inputState.typeaheadState.frozenChatMentionsCandidates, | props.inputState.typeaheadState.frozenChatMentionsCandidates, | ||||
typeaheadMatchedStrings.query, | typeaheadMatchedStrings.query, | ||||
); | ); | ||||
return ([ | return ([ | ||||
...suggestedUsers, | ...suggestedUsers, | ||||
...suggestedChats, | ...suggestedChats, | ||||
]: $ReadOnlyArray<MentionTypeaheadSuggestionItem>); | ]: $ReadOnlyArray<MentionTypeaheadSuggestionItem>); | ||||
}, [ | }, [ | ||||
suggestedUsers, | |||||
typeaheadMatchedStrings, | typeaheadMatchedStrings, | ||||
userSearchIndex, | |||||
props.inputState.typeaheadState.frozenUserMentionsCandidates, | |||||
props.inputState.typeaheadState.frozenChatMentionsCandidates, | props.inputState.typeaheadState.frozenChatMentionsCandidates, | ||||
viewerID, | |||||
chatMentionSearchIndex, | chatMentionSearchIndex, | ||||
]); | ]); | ||||
return ( | return ( | ||||
<ChatInputBar | <ChatInputBar | ||||
{...props} | {...props} | ||||
viewerID={viewerID} | viewerID={viewerID} | ||||
joinThreadLoadingStatus={joinThreadLoadingStatus} | joinThreadLoadingStatus={joinThreadLoadingStatus} | ||||
Show All 15 Lines |