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 @@ -71,7 +71,11 @@ } from '../types/user-types'; import { useDispatchActionPromise, useServerCall } from '../utils/action-utils'; import type { DispatchActionPromise } from '../utils/action-utils'; -import { entityTextToRawString } from '../utils/entity-text'; +import type { GetENSNames } from '../utils/ens-helpers'; +import { + entityTextToRawString, + getEntityTextAsString, +} from '../utils/entity-text'; import { values } from '../utils/objects'; import { useSelector } from '../utils/redux-utils'; import { firstLine } from '../utils/string-utils'; @@ -421,29 +425,21 @@ }; } -type CreatePendingSidebarInput = { +type SharedCreatePendingSidebarInput = { +sourceMessageInfo: ComposableMessageInfo | RobotextMessageInfo, +parentThreadInfo: ThreadInfo, +viewerID: string, - +markdownRules: ParserRules, }; -function createPendingSidebar(input: CreatePendingSidebarInput): ThreadInfo { - const { - sourceMessageInfo, - parentThreadInfo, - viewerID, - markdownRules, - } = input; - const { color, type: parentThreadType } = parentThreadInfo; - const messageTitleEntityText = getMessageTitle( - sourceMessageInfo, - parentThreadInfo, - markdownRules, - ); - const messageTitle = entityTextToRawString(messageTitleEntityText, { - ignoreViewer: true, - }); +type BaseCreatePendingSidebarInput = { + ...SharedCreatePendingSidebarInput, + +messageTitle: string, +}; +function baseCreatePendingSidebar( + input: BaseCreatePendingSidebarInput, +): ThreadInfo { + const { sourceMessageInfo, parentThreadInfo, viewerID, messageTitle } = input; + const { color, type: parentThreadType } = parentThreadInfo; const threadName = trimText(messageTitle, 30); const initialMembers = new Map(); @@ -489,6 +485,80 @@ }); } +// The message title here may have ETH addresses that aren't resolved to ENS +// names. This function should only be used in cases where we're sure that we +// don't care about the thread title. We should prefer createPendingSidebar +// wherever possible +type CreateUnresolvedPendingSidebarInput = { + ...SharedCreatePendingSidebarInput, + +markdownRules: ParserRules, +}; +function createUnresolvedPendingSidebar( + input: CreateUnresolvedPendingSidebarInput, +): ThreadInfo { + const { + sourceMessageInfo, + parentThreadInfo, + viewerID, + markdownRules, + } = input; + + const messageTitleEntityText = getMessageTitle( + sourceMessageInfo, + parentThreadInfo, + markdownRules, + ); + const messageTitle = entityTextToRawString(messageTitleEntityText, { + ignoreViewer: true, + }); + + return baseCreatePendingSidebar({ + sourceMessageInfo, + parentThreadInfo, + messageTitle, + viewerID, + }); +} + +type CreatePendingSidebarInput = { + ...SharedCreatePendingSidebarInput, + +markdownRules: ParserRules, + +getENSNames: ?GetENSNames, +}; +async function createPendingSidebar( + input: CreatePendingSidebarInput, +): Promise { + const { + sourceMessageInfo, + parentThreadInfo, + viewerID, + markdownRules, + getENSNames, + } = input; + + const messageTitleEntityText = getMessageTitle( + sourceMessageInfo, + parentThreadInfo, + markdownRules, + ); + const messageTitle = await getEntityTextAsString( + messageTitleEntityText, + getENSNames, + { ignoreViewer: true }, + ); + invariant( + messageTitle !== null && messageTitle !== undefined, + 'getEntityTextAsString only returns falsey when passed falsey', + ); + + return baseCreatePendingSidebar({ + sourceMessageInfo, + parentThreadInfo, + messageTitle, + viewerID, + }); +} + function pendingThreadType(numberOfOtherMembers: number): 4 | 6 | 7 { if (numberOfOtherMembers === 0) { return threadTypes.PRIVATE; @@ -1415,6 +1485,7 @@ pendingThreadIDRegex, parsePendingThreadID, createPendingThread, + createUnresolvedPendingSidebar, createPendingSidebar, pendingThreadType, createRealThreadFromPendingThread, diff --git a/native/chat/composed-message.react.js b/native/chat/composed-message.react.js --- a/native/chat/composed-message.react.js +++ b/native/chat/composed-message.react.js @@ -50,7 +50,7 @@ +deliveryIconOpacity: number | Node, // withInputState +inputState: ?InputState, - +navigateToSidebar: () => void, + +navigateToSidebar: () => mixed, }; class ComposedMessage extends React.PureComponent { render() { diff --git a/native/chat/sidebar-input-bar-height-measurer.react.js b/native/chat/sidebar-input-bar-height-measurer.react.js --- a/native/chat/sidebar-input-bar-height-measurer.react.js +++ b/native/chat/sidebar-input-bar-height-measurer.react.js @@ -7,7 +7,7 @@ import type { ChatMessageInfoItemWithHeight } from '../types/chat-types'; import { DummyChatInputBar } from './chat-input-bar.react'; import { useMessageListScreenWidth } from './composed-message-width'; -import { getSidebarThreadInfo } from './sidebar-navigation'; +import { getUnresolvedSidebarThreadInfo } from './sidebar-navigation'; type Props = { +sourceMessage: ChatMessageInfoItemWithHeight, @@ -23,7 +23,7 @@ state => state.currentUserInfo && state.currentUserInfo.id, ); const sidebarThreadInfo = React.useMemo(() => { - return getSidebarThreadInfo(sourceMessage, viewerID); + return getUnresolvedSidebarThreadInfo({ sourceMessage, viewerID }); }, [sourceMessage, viewerID]); if (!sidebarThreadInfo) { return null; diff --git a/native/chat/sidebar-navigation.js b/native/chat/sidebar-navigation.js --- a/native/chat/sidebar-navigation.js +++ b/native/chat/sidebar-navigation.js @@ -3,8 +3,13 @@ import invariant from 'invariant'; import * as React from 'react'; -import { createPendingSidebar } from 'lib/shared/thread-utils'; +import { ENSCacheContext } from 'lib/components/ens-cache-provider.react'; +import { + createPendingSidebar, + createUnresolvedPendingSidebar, +} from 'lib/shared/thread-utils'; import type { ThreadInfo } from 'lib/types/thread-types'; +import type { GetENSNames } from 'lib/utils/ens-helpers'; import { getDefaultTextMessageRules } from '../markdown/rules.react'; import { useSelector } from '../redux/redux-utils'; @@ -12,10 +17,40 @@ import { ChatContext } from './chat-context'; import { useNavigateToThread } from './message-list-types'; -function getSidebarThreadInfo( - sourceMessage: ChatMessageInfoItemWithHeight, - viewerID?: ?string, +type GetUnresolvedSidebarThreadInfoInput = { + +sourceMessage: ChatMessageInfoItemWithHeight, + +viewerID?: ?string, +}; +function getUnresolvedSidebarThreadInfo( + input: GetUnresolvedSidebarThreadInfoInput, ): ?ThreadInfo { + const { sourceMessage, viewerID } = input; + const threadCreatedFromMessage = sourceMessage.threadCreatedFromMessage; + if (threadCreatedFromMessage) { + return threadCreatedFromMessage; + } + + if (!viewerID) { + return null; + } + + const { messageInfo, threadInfo } = sourceMessage; + return createUnresolvedPendingSidebar({ + sourceMessageInfo: messageInfo, + parentThreadInfo: threadInfo, + viewerID, + markdownRules: getDefaultTextMessageRules().simpleMarkdownRules, + }); +} + +type GetSidebarThreadInfoInput = { + ...GetUnresolvedSidebarThreadInfoInput, + +getENSNames: ?GetENSNames, +}; +async function getSidebarThreadInfo( + input: GetSidebarThreadInfoInput, +): Promise { + const { sourceMessage, viewerID, getENSNames } = input; const threadCreatedFromMessage = sourceMessage.threadCreatedFromMessage; if (threadCreatedFromMessage) { return threadCreatedFromMessage; @@ -26,27 +61,33 @@ } const { messageInfo, threadInfo } = sourceMessage; - return createPendingSidebar({ + return await createPendingSidebar({ sourceMessageInfo: messageInfo, parentThreadInfo: threadInfo, viewerID, markdownRules: getDefaultTextMessageRules().simpleMarkdownRules, + getENSNames, }); } -function useNavigateToSidebar(item: ChatMessageInfoItemWithHeight): () => void { +function useNavigateToSidebar( + item: ChatMessageInfoItemWithHeight, +): () => mixed { const viewerID = useSelector( state => state.currentUserInfo && state.currentUserInfo.id, ); - const threadInfo = React.useMemo(() => getSidebarThreadInfo(item, viewerID), [ - item, - viewerID, - ]); const navigateToThread = useNavigateToThread(); - return React.useCallback(() => { + const cacheContext = React.useContext(ENSCacheContext); + const { getENSNames } = cacheContext; + return React.useCallback(async () => { + const threadInfo = await getSidebarThreadInfo({ + sourceMessage: item, + viewerID, + getENSNames, + }); invariant(threadInfo, 'threadInfo should be set'); navigateToThread({ threadInfo }); - }, [navigateToThread, threadInfo]); + }, [navigateToThread, item, viewerID, getENSNames]); } function useAnimatedNavigateToSidebar( @@ -63,7 +104,7 @@ } export { - getSidebarThreadInfo, + getUnresolvedSidebarThreadInfo, useNavigateToSidebar, useAnimatedNavigateToSidebar, }; diff --git a/native/chat/swipeable-message.react.js b/native/chat/swipeable-message.react.js --- a/native/chat/swipeable-message.react.js +++ b/native/chat/swipeable-message.react.js @@ -146,8 +146,8 @@ } type Props = { - +triggerReply?: () => void, - +triggerSidebar?: () => void, + +triggerReply?: () => mixed, + +triggerSidebar?: () => mixed, +isViewer: boolean, +messageBoxStyle: ViewStyle, +threadColor: string, diff --git a/native/chat/utils.js b/native/chat/utils.js --- a/native/chat/utils.js +++ b/native/chat/utils.js @@ -31,7 +31,7 @@ import { failedSendHeight } from './failed-send.react'; import { authorNameHeight } from './message-header.react'; import { multimediaMessageItemHeight } from './multimedia-message-utils'; -import { getSidebarThreadInfo } from './sidebar-navigation'; +import { getUnresolvedSidebarThreadInfo } from './sidebar-navigation'; import textMessageSendFailed from './text-message-send-failed'; import { timestampHeight } from './timestamp.react'; @@ -219,9 +219,10 @@ const viewerID = useSelector( state => state.currentUserInfo && state.currentUserInfo.id, ); - const sidebarThreadInfo = React.useMemo(() => { - return getSidebarThreadInfo(sourceMessage, viewerID); - }, [sourceMessage, viewerID]); + const sidebarThreadInfo = React.useMemo( + () => getUnresolvedSidebarThreadInfo({ sourceMessage, viewerID }), + [sourceMessage, viewerID], + ); const currentInputBarHeight = chatInputBarHeights.get(sourceMessage.threadInfo.id) ?? 0; diff --git a/web/selectors/thread-selectors.js b/web/selectors/thread-selectors.js --- a/web/selectors/thread-selectors.js +++ b/web/selectors/thread-selectors.js @@ -4,6 +4,7 @@ import * as React from 'react'; import { useDispatch } from 'react-redux'; +import { ENSCacheContext } from 'lib/components/ens-cache-provider.react'; import { createPendingSidebar } from 'lib/shared/thread-utils'; import type { ComposableMessageInfo, @@ -55,20 +56,25 @@ function useOnClickPendingSidebar( messageInfo: ComposableMessageInfo | RobotextMessageInfo, threadInfo: ThreadInfo, -): (event: SyntheticEvent) => void { +): (event: SyntheticEvent) => mixed { const dispatch = useDispatch(); const viewerID = useSelector(state => state.currentUserInfo?.id); + + const cacheContext = React.useContext(ENSCacheContext); + const { getENSNames } = cacheContext; + return React.useCallback( - (event: SyntheticEvent) => { + async (event: SyntheticEvent) => { event.preventDefault(); if (!viewerID) { return; } - const pendingSidebarInfo = createPendingSidebar({ + const pendingSidebarInfo = await createPendingSidebar({ sourceMessageInfo: messageInfo, parentThreadInfo: threadInfo, viewerID, markdownRules: getDefaultTextMessageRules().simpleMarkdownRules, + getENSNames, }); dispatch({ type: updateNavInfoActionType, @@ -78,7 +84,7 @@ }, }); }, - [viewerID, messageInfo, threadInfo, dispatch], + [viewerID, messageInfo, threadInfo, dispatch, getENSNames], ); }