diff --git a/web/chat/composed-message.react.js b/web/chat/composed-message.react.js --- a/web/chat/composed-message.react.js +++ b/web/chat/composed-message.react.js @@ -82,58 +82,83 @@ const { id } = item.messageInfo; const threadColor = threadInfo.color; - const contentClassName = classNames({ - [css.content]: true, - [css.viewerContent]: isViewer, - [css.nonViewerContent]: !isViewer, - }); - const messageBoxContainerClassName = classNames({ - [css.messageBoxContainer]: true, - [css.fixedWidthMessageBoxContainer]: props.fixedWidth, - }); - const messageBoxClassName = classNames({ - [css.messageBox]: true, - [css.fixedWidthMessageBox]: 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; + const contentClassName = React.useMemo( + () => + classNames({ + [css.content]: true, + [css.viewerContent]: isViewer, + [css.nonViewerContent]: !isViewer, + }), + [isViewer], + ); + const messageBoxContainerClassName = React.useMemo( + () => + classNames({ + [css.messageBoxContainer]: true, + [css.fixedWidthMessageBoxContainer]: props.fixedWidth, + }), + [props.fixedWidth], + ); + const messageBoxClassName = React.useMemo( + () => + classNames({ + [css.messageBox]: true, + [css.fixedWidthMessageBox]: props.fixedWidth, + }), + [props.fixedWidth], + ); + const messageBoxStyle = React.useMemo( + () => ({ + borderTopRightRadius: + isViewer && !item.startsCluster ? 0 : borderRadius, + borderBottomRightRadius: + isViewer && !item.endsCluster ? 0 : borderRadius, + borderTopLeftRadius: + !isViewer && !item.startsCluster ? 0 : borderRadius, + borderBottomLeftRadius: + !isViewer && !item.endsCluster ? 0 : borderRadius, + }), + [isViewer, item.startsCluster, item.endsCluster, borderRadius], + ); + const stringForUser = useStringForUser(shouldShowUsername ? creator : null); - if (stringForUser) { - authorName = ( + const authorName = React.useMemo(() => { + if (!stringForUser) { + return null; + } + return ( {stringForUser} ); - } + }, [stringForUser, pushUserProfileModal]); - let deliveryIcon = null; - let failedSendInfo = null; - if (isViewer) { - let deliveryIconSpan; - let deliveryIconColor = threadColor; + const notDeliveredP2PMessages = + item?.localMessageInfo?.outboundP2PMessageIDs; + const { deliveryIcon, failedSendInfo } = React.useMemo(() => { + if (!isViewer) { + return { deliveryIcon: null, failedSendInfo: null }; + } - const notDeliveredP2PMessages = - item?.localMessageInfo?.outboundP2PMessageIDs ?? []; + let returnedFailedSendInfo, deliveryIconSpan; + let deliveryIconColor = threadColor; if ( id !== null && id !== undefined && - notDeliveredP2PMessages.length === 0 + (!notDeliveredP2PMessages || notDeliveredP2PMessages.length === 0) ) { deliveryIconSpan = ; } else if (props.sendFailed) { deliveryIconSpan = ; deliveryIconColor = 'FF0000'; - failedSendInfo = ; + returnedFailedSendInfo = ( + + ); } else { deliveryIconSpan = ; } - deliveryIcon = ( + + const returnedDeliveryIcon = (
); - } + return { + deliveryIcon: returnedDeliveryIcon, + failedSendInfo: returnedFailedSendInfo, + }; + }, [ + isViewer, + threadColor, + id, + notDeliveredP2PMessages, + props.sendFailed, + item, + threadInfo, + ]); - let inlineEngagement = null; const label = getMessageLabel(hasBeenEdited, threadInfo.id); - if ( - item.threadCreatedFromMessage || - Object.keys(item.reactions).length > 0 || - label - ) { + const inlineEngagement = React.useMemo(() => { + if ( + !item.threadCreatedFromMessage && + Object.keys(item.reactions).length === 0 && + !label + ) { + return null; + } const positioning = isViewer ? 'right' : 'left'; - inlineEngagement = ( + return (
); - } + }, [ + item.threadCreatedFromMessage, + item.reactions, + label, + isViewer, + item.messageInfo, + threadInfo, + ]); - let avatar; - if (!isViewer && item.endsCluster) { - avatar = ( -
- -
- ); - } else if (!isViewer) { - avatar =
; - } - - const pinIconPositioning = isViewer ? 'left' : 'right'; - const pinIconName = pinIconPositioning === 'left' ? 'pin-mirror' : 'pin'; - const pinIconContainerClassName = classNames({ - [css.pinIconContainer]: true, - [css.pinIconLeft]: pinIconPositioning === 'left', - [css.pinIconRight]: pinIconPositioning === 'right', - }); - let pinIcon; - if (isPinned && shouldDisplayPinIndicator) { - pinIcon = ( + const avatar = React.useMemo(() => { + if (!isViewer && item.endsCluster) { + return ( +
+ +
+ ); + } else if (!isViewer) { + return
; + } + return undefined; + }, [isViewer, item.endsCluster, pushUserProfileModal, creator.id]); + + const shouldShowPinIcon = isPinned && shouldDisplayPinIndicator; + const pinIcon = React.useMemo(() => { + if (!shouldShowPinIcon) { + return null; + } + const pinIconPositioning = isViewer ? 'left' : 'right'; + const pinIconName = pinIconPositioning === 'left' ? 'pin-mirror' : 'pin'; + const pinIconContainerClassName = classNames({ + [css.pinIconContainer]: true, + [css.pinIconLeft]: pinIconPositioning === 'left', + [css.pinIconRight]: pinIconPositioning === 'right', + }); + return (
); - } - - return ( - - {authorName} -
- {avatar} -
- {pinIcon} + }, [shouldShowPinIcon, isViewer, threadColor]); + + const composedMessageID = getComposedMessageID(item.messageInfo); + return React.useMemo( + () => ( + <> + {authorName} +
+ {avatar}
- {props.children} + {pinIcon} +
+ {props.children} +
+ {deliveryIcon}
- {deliveryIcon} -
- {failedSendInfo} - {inlineEngagement} - + {failedSendInfo} + {inlineEngagement} + + ), + [ + authorName, + contentClassName, + avatar, + messageBoxContainerClassName, + onMouseEnter, + onMouseLeave, + pinIcon, + messageBoxClassName, + messageBoxStyle, + composedMessageID, + props.children, + deliveryIcon, + failedSendInfo, + inlineEngagement, + ], ); }, );