diff --git a/lib/shared/message-utils.js b/lib/shared/message-utils.js --- a/lib/shared/message-utils.js +++ b/lib/shared/message-utils.js @@ -32,7 +32,7 @@ } from '../types/messages/reaction'; import { type ThreadInfo } from '../types/thread-types'; import type { UserInfos } from '../types/user-types'; -import { type EntityText, entityTextToRawString } from '../utils/entity-text'; +import { type EntityText, useEntityTextAsString } from '../utils/entity-text'; import { codeBlockRegex, type ParserRules } from './markdown'; import { messageSpecs } from './messages/message-specs'; import { threadIsGroupChat } from './thread-utils'; @@ -480,30 +480,42 @@ }; }, [shouldDisplayUser, stringForUser, unread]); - const message = React.useMemo(() => { + const messageTitleEntityText = React.useMemo(() => { if (!messageInfo) { return messageInfo; } - const messageTitleEntityText = getMessageTitle( - messageInfo, - threadInfo, - markdownRules, - ); - const messageTitle = entityTextToRawString(messageTitleEntityText, { - threadID: threadInfo.id, - }); + return getMessageTitle(messageInfo, threadInfo, markdownRules); + }, [messageInfo, threadInfo, markdownRules]); + + const threadID = threadInfo.id; + const entityTextToStringParams = React.useMemo( + () => ({ + threadID, + }), + [threadID], + ); + const messageTitle = useEntityTextAsString( + messageTitleEntityText, + entityTextToStringParams, + ); + + const isTextMessage = messageInfo?.type === messageTypes.TEXT; + const message = React.useMemo(() => { + if (messageTitle === null || messageTitle === undefined) { + return messageTitle; + } let style; if (unread) { style = 'unread'; - } else if (messageInfo.type === messageTypes.TEXT) { + } else if (isTextMessage) { style = 'primary'; } else { style = 'secondary'; } return { text: messageTitle, style }; - }, [messageInfo, threadInfo, markdownRules, unread]); + }, [messageTitle, unread, isTextMessage]); return React.useMemo(() => { if (!message) { diff --git a/lib/utils/entity-text.js b/lib/utils/entity-text.js --- a/lib/utils/entity-text.js +++ b/lib/utils/entity-text.js @@ -335,22 +335,37 @@ ); } -function useENSNamesForEntityText(entityText: EntityText): EntityText { - const allObjects = React.useMemo( - () => - entityText.map(entity => - typeof entity === 'string' ? { type: 'text', text: entity } : entity, - ), - [entityText], - ); +function useENSNamesForEntityText(entityText: ?EntityText): ?EntityText { + const allObjects = React.useMemo(() => { + if (!entityText) { + return []; + } + return entityText.map(entity => + typeof entity === 'string' ? { type: 'text', text: entity } : entity, + ); + }, [entityText]); const objectsWithENSNames = useENSNames(allObjects); - return React.useMemo( - () => - objectsWithENSNames.map(entity => - entity.type === 'text' ? entity.text : entity, - ), - [objectsWithENSNames], - ); + return React.useMemo(() => { + if (!entityText) { + return entityText; + } + return objectsWithENSNames.map(entity => + entity.type === 'text' ? entity.text : entity, + ); + }, [entityText, objectsWithENSNames]); +} + +function useEntityTextAsString( + entityText: ?EntityText, + params?: EntityTextToRawStringParams, +): ?string { + const withENSNames = useENSNamesForEntityText(entityText); + return React.useMemo(() => { + if (!withENSNames) { + return withENSNames; + } + return entityTextToRawString(withENSNames, params); + }, [withENSNames, params]); } export { @@ -359,4 +374,5 @@ entityTextToReact, pluralizeEntityText, useENSNamesForEntityText, + useEntityTextAsString, }; diff --git a/native/chat/inner-robotext-message.react.js b/native/chat/inner-robotext-message.react.js --- a/native/chat/inner-robotext-message.react.js +++ b/native/chat/inner-robotext-message.react.js @@ -45,6 +45,10 @@ const { messageInfo, robotext } = item; const { threadID } = messageInfo; const robotextWithENSNames = useENSNamesForEntityText(robotext); + invariant( + robotextWithENSNames, + 'useENSNamesForEntityText only returns falsey when passed falsey', + ); const textParts = React.useMemo(() => { const darkColor = activeTheme === 'dark'; return entityTextToReact(robotextWithENSNames, threadID, { diff --git a/web/chat/robotext-message.react.js b/web/chat/robotext-message.react.js --- a/web/chat/robotext-message.react.js +++ b/web/chat/robotext-message.react.js @@ -1,5 +1,6 @@ // @flow +import invariant from 'invariant'; import * as React from 'react'; import { useDispatch } from 'react-redux'; @@ -52,6 +53,10 @@ const { messageInfo, robotext } = item; const { threadID } = messageInfo; const robotextWithENSNames = useENSNamesForEntityText(robotext); + invariant( + robotextWithENSNames, + 'useENSNamesForEntityText only returns falsey when passed falsey', + ); const textParts = React.useMemo(() => { return entityTextToReact(robotextWithENSNames, threadID, { // eslint-disable-next-line react/display-name