// @flow import React from 'react'; import Transition from 'react-transition-group/Transition'; import { translate } from '../../../base/i18n'; import { connect } from '../../../base/redux'; import AbstractChat, { _mapDispatchToProps, _mapStateToProps, type Props } from '../AbstractChat'; import ChatInput from './ChatInput'; import DisplayNameForm from './DisplayNameForm'; import MessageContainer from './MessageContainer'; /** * React Component for holding the chat feature in a side panel that slides in * and out of view. */ class Chat extends AbstractChat { /** * Whether or not the {@code Chat} component is off-screen, having finished * its hiding animation. */ _isExited: boolean; /** * Initializes a new {@code Chat} instance. * * @param {Object} props - The read-only properties with which the new * instance is to be initialized. */ constructor(props: Props) { super(props); this._isExited = true; // Bind event handlers so they are only bound once for every instance. this._renderPanelContent = this._renderPanelContent.bind(this); } /** * Implements React's {@link Component#render()}. * * @inheritdoc * @returns {ReactElement} */ render() { return ( { this._renderPanelContent } ); } /** * Iterates over all the messages and creates nested arrays which hold * consecutive messages sent be the same participant. * * @private * @returns {Array>} */ _getMessagesGroupedBySender() { const messagesCount = this.props._messages.length; const groups = []; let currentGrouping = []; let currentGroupParticipantId; for (let i = 0; i < messagesCount; i++) { const message = this.props._messages[i]; if (message.id === currentGroupParticipantId) { currentGrouping.push(message); } else { groups.push(currentGrouping); currentGrouping = [ message ]; currentGroupParticipantId = message.id; } } groups.push(currentGrouping); return groups; } /** * Returns a React Element for showing chat messages and a form to send new * chat messages. * * @private * @returns {ReactElement} */ _renderChat() { return ( <> ); } /** * Instantiates a React Element to display at the top of {@code Chat} to * close {@code Chat}. * * @private * @returns {ReactElement} */ _renderChatHeader() { return (
X
); } _renderPanelContent: (string) => React$Node | null; /** * Renders the contents of the chat panel, depending on the current * animation state provided by {@code Transition}. * * @param {string} state - The current display transition state of the * {@code Chat} component, as provided by {@code Transition}. * @private * @returns {ReactElement | null} */ _renderPanelContent(state) { this._isExited = state === 'exited'; const { _isOpen, _showNamePrompt } = this.props; const ComponentToRender = !_isOpen && state === 'exited' ? null : ( <> { this._renderChatHeader() } { _showNamePrompt ? : this._renderChat() } ); let className = ''; if (_isOpen) { className = 'slideInExt'; } else if (this._isExited) { className = 'invisible'; } return (
{ ComponentToRender }
); } } export default translate(connect(_mapStateToProps, _mapDispatchToProps)(Chat));