diff --git a/web/chat/robotext-message.react.js b/web/chat/robotext-message.react.js index a8730002b..6dc08e314 100644 --- a/web/chat/robotext-message.react.js +++ b/web/chat/robotext-message.react.js @@ -1,191 +1,196 @@ // @flow -import PropTypes from 'prop-types'; import * as React from 'react'; +import { useDispatch } from 'react-redux'; import { type RobotextChatMessageInfoItem } from 'lib/selectors/chat-selectors'; import { threadInfoSelector } from 'lib/selectors/thread-selectors'; import { splitRobotext, parseRobotextEntity } from 'lib/shared/message-utils'; import { useSidebarExistsOrCanBeCreated } from 'lib/shared/thread-utils'; -import { type ThreadInfo, threadInfoPropType } from 'lib/types/thread-types'; -import type { DispatchActionPayload } from 'lib/utils/action-utils'; -import { connect } from 'lib/utils/redux-utils'; +import type { Dispatch } from 'lib/types/redux-types'; +import { type ThreadInfo } from 'lib/types/thread-types'; import Markdown from '../markdown/markdown.react'; import { linkRules } from '../markdown/rules.react'; -import { type AppState, updateNavInfoActionType } from '../redux/redux-setup'; +import { updateNavInfoActionType } from '../redux/redux-setup'; +import { useSelector } from '../redux/redux-utils'; import css from './chat-message-list.css'; import { InlineSidebar } from './inline-sidebar.react'; import type { MessagePositionInfo, OnMessagePositionInfo, } from './message-position-types'; import SidebarTooltip from './sidebar-tooltip.react'; type BaseProps = {| +item: RobotextChatMessageInfoItem, +threadInfo: ThreadInfo, +setMouseOverMessagePosition: ( messagePositionInfo: MessagePositionInfo, ) => void, +mouseOverMessagePosition: ?OnMessagePositionInfo, |}; type Props = {| ...BaseProps, // Redux state +sidebarExistsOrCanBeCreated: boolean, |}; class RobotextMessage extends React.PureComponent { render() { let inlineSidebar; if (this.props.item.threadCreatedFromMessage) { inlineSidebar = (
); } const { item, threadInfo, sidebarExistsOrCanBeCreated } = this.props; const { id } = item.messageInfo; let sidebarTooltip; if ( this.props.mouseOverMessagePosition && this.props.mouseOverMessagePosition.item.messageInfo.id === id && sidebarExistsOrCanBeCreated ) { sidebarTooltip = ( ); } return (
{this.linkedRobotext()} {sidebarTooltip}
{inlineSidebar}
); } linkedRobotext() { const { item } = this.props; const { robotext } = item; const robotextParts = splitRobotext(robotext); const textParts = []; let keyIndex = 0; for (let splitPart of robotextParts) { if (splitPart === '') { continue; } if (splitPart.charAt(0) !== '<') { const key = `text${keyIndex++}`; textParts.push( {decodeURI(splitPart)} , ); continue; } const { rawText, entityType, id } = parseRobotextEntity(splitPart); if (entityType === 't' && id !== item.messageInfo.threadID) { textParts.push(); } else if (entityType === 'c') { textParts.push(); } else { textParts.push(rawText); } } return textParts; } onMouseEnter = (event: SyntheticEvent) => { const { item } = this.props; const rect = event.currentTarget.getBoundingClientRect(); const { top, bottom, left, right, height, width } = rect; const messagePosition = { top, bottom, left, right, height, width }; this.props.setMouseOverMessagePosition({ type: 'on', item, messagePosition, }); }; onMouseLeave = () => { const { item } = this.props; this.props.setMouseOverMessagePosition({ type: 'off', item }); }; } -type InnerThreadEntityProps = { - id: string, - name: string, - // Redux state - threadInfo: ThreadInfo, - // Redux dispatch functions - dispatchActionPayload: DispatchActionPayload, -}; +type BaseInnerThreadEntityProps = {| + +id: string, + +name: string, +|}; +type InnerThreadEntityProps = {| + ...BaseInnerThreadEntityProps, + +threadInfo: ThreadInfo, + +dispatch: Dispatch, +|}; class InnerThreadEntity extends React.PureComponent { - static propTypes = { - id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - threadInfo: threadInfoPropType.isRequired, - dispatchActionPayload: PropTypes.func.isRequired, - }; - render() { return {this.props.name}; } onClickThread = (event: SyntheticEvent) => { event.preventDefault(); const id = this.props.id; - this.props.dispatchActionPayload(updateNavInfoActionType, { - activeChatThreadID: id, + this.props.dispatch({ + type: updateNavInfoActionType, + payload: { + activeChatThreadID: id, + }, }); }; } -const ThreadEntity = connect( - (state: AppState, ownProps: { id: string }) => ({ - threadInfo: threadInfoSelector(state)[ownProps.id], - }), - null, - true, -)(InnerThreadEntity); +const ThreadEntity = React.memo( + function ConnectedInnerThreadEntity(props: BaseInnerThreadEntityProps) { + const { id } = props; + const threadInfo = useSelector((state) => threadInfoSelector(state)[id]); + const dispatch = useDispatch(); + + return ( + + ); + }, +); function ColorEntity(props: {| color: string |}) { const colorStyle = { color: props.color }; return {props.color}; } export default React.memo(function ConnectedRobotextMessage( props: BaseProps, ) { const sidebarExistsOrCanBeCreated = useSidebarExistsOrCanBeCreated( props.threadInfo, props.item, ); return ( ); });