diff --git a/native/chat/message-header.react.js b/native/chat/message-header.react.js index c791666e4..1efb3b5a7 100644 --- a/native/chat/message-header.react.js +++ b/native/chat/message-header.react.js @@ -1,82 +1,83 @@ // @flow import * as React from 'react'; import { View } from 'react-native'; -import { stringForUser } from 'lib/shared/user-utils'; +import { useStringForUser } from 'lib/hooks/ens-cache'; import { SingleLine } from '../components/single-line.react'; import { useStyles } from '../themes/colors'; import type { ChatMessageInfoItemWithHeight } from '../types/chat-types'; import { clusterEndHeight } from './chat-constants'; import type { DisplayType } from './timestamp.react'; import { Timestamp, timestampHeight } from './timestamp.react'; type Props = { +item: ChatMessageInfoItemWithHeight, +focused: boolean, +display: DisplayType, }; function MessageHeader(props: Props): React.Node { const styles = useStyles(unboundStyles); const { item, focused, display } = props; const { creator, time } = item.messageInfo; const { isViewer } = creator; const modalDisplay = display === 'modal'; + const shouldShowUsername = !isViewer && (modalDisplay || item.startsCluster); + const stringForUser = useStringForUser(shouldShowUsername ? creator : null); + let authorName = null; - if (!isViewer && (modalDisplay || item.startsCluster)) { + if (stringForUser) { const style = [styles.authorName]; if (modalDisplay) { style.push(styles.modal); } - authorName = ( - {stringForUser(creator)} - ); + authorName = {stringForUser}; } const timestamp = modalDisplay || item.startsConversation ? ( ) : null; let style = null; if (focused && !modalDisplay) { let topMargin = 0; if (!item.startsCluster && !item.messageInfo.creator.isViewer) { topMargin += authorNameHeight + clusterEndHeight; } if (!item.startsConversation) { topMargin += timestampHeight; } style = { marginTop: topMargin }; } return ( {timestamp} {authorName} ); } const authorNameHeight = 25; const unboundStyles = { authorName: { bottom: 0, color: 'listBackgroundSecondaryLabel', fontSize: 14, height: authorNameHeight, marginLeft: 12, marginRight: 7, paddingHorizontal: 12, paddingVertical: 4, }, modal: { // high contrast framed against OverlayNavigator-dimmed background color: 'white', }, }; export { MessageHeader, authorNameHeight }; diff --git a/web/chat/composed-message.react.js b/web/chat/composed-message.react.js index 0bd0f4e78..4889dfc3e 100644 --- a/web/chat/composed-message.react.js +++ b/web/chat/composed-message.react.js @@ -1,194 +1,199 @@ // @flow import classNames from 'classnames'; import * as React from 'react'; import { Circle as CircleIcon, CheckCircle as CheckCircleIcon, XCircle as XCircleIcon, } from 'react-feather'; +import { useStringForUser } from 'lib/hooks/ens-cache'; import { type ChatMessageInfoItem } from 'lib/selectors/chat-selectors'; -import { stringForUser } from 'lib/shared/user-utils'; import { assertComposableMessageType } from 'lib/types/message-types'; import { type ThreadInfo } from 'lib/types/thread-types'; import { type InputState, InputStateContext } from '../input/input-state'; import { tooltipPositions, useMessageTooltip } from '../utils/tooltip-utils'; import css from './chat-message-list.css'; import FailedSend from './failed-send.react'; import InlineEngagement from './inline-engagement.react'; const availableTooltipPositionsForViewerMessage = [ tooltipPositions.LEFT, tooltipPositions.LEFT_BOTTOM, tooltipPositions.LEFT_TOP, tooltipPositions.RIGHT, tooltipPositions.RIGHT_BOTTOM, tooltipPositions.RIGHT_TOP, tooltipPositions.BOTTOM, tooltipPositions.TOP, ]; const availableTooltipPositionsForNonViewerMessage = [ tooltipPositions.RIGHT, tooltipPositions.RIGHT_BOTTOM, tooltipPositions.RIGHT_TOP, tooltipPositions.LEFT, tooltipPositions.LEFT_BOTTOM, tooltipPositions.LEFT_TOP, tooltipPositions.BOTTOM, tooltipPositions.TOP, ]; type BaseProps = { +item: ChatMessageInfoItem, +threadInfo: ThreadInfo, +sendFailed: boolean, +children: React.Node, +fixedWidth?: boolean, +borderRadius: number, }; type BaseConfig = React.Config; type Props = { ...BaseProps, // withInputState +inputState: ?InputState, +onMouseLeave: ?() => mixed, +onMouseEnter: (event: SyntheticEvent) => mixed, +containsInlineEngagement: boolean, + +stringForUser: ?string, }; class ComposedMessage extends React.PureComponent { static defaultProps: { +borderRadius: number } = { borderRadius: 8, }; render(): React.Node { assertComposableMessageType(this.props.item.messageInfo.type); const { borderRadius, item, threadInfo } = this.props; const { id, creator } = item.messageInfo; const threadColor = threadInfo.color; const { isViewer } = creator; const contentClassName = classNames({ [css.content]: true, [css.viewerContent]: isViewer, [css.nonViewerContent]: !isViewer, }); const messageBoxContainerClassName = classNames({ [css.messageBoxContainer]: true, [css.fixedWidthMessageBoxContainer]: this.props.fixedWidth, }); const messageBoxClassName = classNames({ [css.messageBox]: true, [css.fixedWidthMessageBox]: this.props.fixedWidth, }); const messageBoxStyle = { borderTopRightRadius: isViewer && !item.startsCluster ? 0 : borderRadius, borderBottomRightRadius: isViewer && !item.endsCluster ? 0 : borderRadius, borderTopLeftRadius: !isViewer && !item.startsCluster ? 0 : borderRadius, borderBottomLeftRadius: !isViewer && !item.endsCluster ? 0 : borderRadius, }; let authorName = null; - if (!isViewer && item.startsCluster) { - authorName = ( - {stringForUser(creator)} - ); + const { stringForUser } = this.props; + if (stringForUser) { + authorName = {stringForUser}; } let deliveryIcon = null; let failedSendInfo = null; if (isViewer) { let deliveryIconSpan; let deliveryIconColor = threadColor; if (id !== null && id !== undefined) { deliveryIconSpan = ; } else if (this.props.sendFailed) { deliveryIconSpan = ; deliveryIconColor = 'FF0000'; failedSendInfo = ; } else { deliveryIconSpan = ; } deliveryIcon = (
{deliveryIconSpan}
); } let inlineEngagement = null; if ( (this.props.containsInlineEngagement && item.threadCreatedFromMessage) || item.reactions.size > 0 ) { const positioning = isViewer ? 'right' : 'left'; inlineEngagement = (
); } return ( {authorName}
{this.props.children}
{deliveryIcon}
{failedSendInfo} {inlineEngagement}
); } } type ConnectedConfig = React.Config< BaseProps, typeof ComposedMessage.defaultProps, >; const ConnectedComposedMessage: React.ComponentType = React.memo( function ConnectedComposedMessage(props) { const { item, threadInfo } = props; const inputState = React.useContext(InputStateContext); - const isViewer = props.item.messageInfo.creator.isViewer; + const { creator } = props.item.messageInfo; + const { isViewer } = creator; const availablePositions = isViewer ? availableTooltipPositionsForViewerMessage : availableTooltipPositionsForNonViewerMessage; const containsInlineEngagement = !!item.threadCreatedFromMessage; const { onMouseLeave, onMouseEnter } = useMessageTooltip({ item, threadInfo, availablePositions, }); + const shouldShowUsername = !isViewer && item.startsCluster; + const stringForUser = useStringForUser(shouldShowUsername ? creator : null); + return ( ); }, ); export default ConnectedComposedMessage;