diff --git a/react/features/chat/components/web/Chat.js b/react/features/chat/components/web/Chat.js index 96ca6260a..e5731d3dc 100644 --- a/react/features/chat/components/web/Chat.js +++ b/react/features/chat/components/web/Chat.js @@ -12,8 +12,8 @@ import AbstractChat, { type Props } from '../AbstractChat'; import ChatInput from './ChatInput'; -import ChatMessageGroup from './ChatMessageGroup'; import DisplayNameForm from './DisplayNameForm'; +import MessageContainer from './MessageContainer'; /** * React Component for holding the chat feature in a side panel that slides in @@ -27,12 +27,6 @@ class Chat extends AbstractChat { */ _isExited: boolean; - /** - * Reference to the HTML element at the end of the list of displayed chat - * messages. Used for scrolling to the end of the chat messages. - */ - _messagesListEnd: ?HTMLElement; - /** * Initializes a new {@code Chat} instance. * @@ -43,32 +37,9 @@ class Chat extends AbstractChat { super(props); this._isExited = true; - this._messagesListEnd = null; // Bind event handlers so they are only bound once for every instance. this._renderPanelContent = this._renderPanelContent.bind(this); - this._setMessageListEndRef = this._setMessageListEndRef.bind(this); - } - - /** - * Implements React's {@link Component#componentDidMount()}. - * - * @inheritdoc - */ - componentDidMount() { - this._scrollMessagesToBottom(); - } - - /** - * Updates chat input focus. - * - * @inheritdoc - */ - componentDidUpdate(prevProps) { - if (this.props._messages !== prevProps._messages) { - this._scrollMessagesToBottom(); - - } } /** @@ -126,28 +97,9 @@ class Chat extends AbstractChat { * @returns {ReactElement} */ _renderChat() { - const groupedMessages = this._getMessagesGroupedBySender(); - - const messages = groupedMessages.map((group, index) => { - const messageType = group[0] && group[0].messageType; - - return ( - - ); - }); - - messages.push(
); - return ( <> -
- { messages } -
+ ); @@ -210,33 +162,6 @@ class Chat extends AbstractChat {
); } - - /** - * Automatically scrolls the displayed chat messages down to the latest. - * - * @private - * @returns {void} - */ - _scrollMessagesToBottom() { - if (this._messagesListEnd) { - this._messagesListEnd.scrollIntoView({ - behavior: this._isExited ? 'auto' : 'smooth' - }); - } - } - - _setMessageListEndRef: (?HTMLElement) => void; - - /** - * Sets a reference to the HTML element at the bottom of the message list. - * - * @param {Object} messageListEnd - The HTML element. - * @private - * @returns {void} - */ - _setMessageListEndRef(messageListEnd: ?HTMLElement) { - this._messagesListEnd = messageListEnd; - } } export default translate(connect(_mapStateToProps, _mapDispatchToProps)(Chat)); diff --git a/react/features/chat/components/web/MessageContainer.js b/react/features/chat/components/web/MessageContainer.js new file mode 100644 index 000000000..be3bc24b4 --- /dev/null +++ b/react/features/chat/components/web/MessageContainer.js @@ -0,0 +1,129 @@ +// @flow + +import React, { PureComponent } from 'react'; + +import ChatMessageGroup from './ChatMessageGroup'; + +type Props = { + + /** + * The messages array to render. + */ + messages: Array +} + +/** + * Displays all received chat messages, grouped by sender. + * + * @extends PureComponent + */ +export default class MessageContainer extends PureComponent { + static defaultProps = { + messages: [] + }; + + /** + * Reference to the HTML element at the end of the list of displayed chat + * messages. Used for scrolling to the end of the chat messages. + */ + _messagesListEndRef: Object; + + /** + * Initializes a new {@code MessageContainer} instance. + * + * @param {Props} props - The React {@code Component} props to initialize + * the new {@code MessageContainer} instance with. + */ + constructor(props: Props) { + super(props); + + this._messagesListEndRef = React.createRef(); + } + + /** + * Implements React's {@link Component#componentDidMount()}. + * + * @inheritdoc + */ + componentDidMount() { + this._scrollMessagesToBottom(); + } + + /** + * Updates chat input focus. + * + * @inheritdoc + */ + componentDidUpdate() { + this._scrollMessagesToBottom(); + } + + /** + * Implements {@code Component#render}. + * + * @inheritdoc + */ + render() { + const groupedMessages = this._getMessagesGroupedBySender(); + const messages = groupedMessages.map((group, index) => { + const messageType = group[0] && group[0].messageType; + + return ( + + ); + }); + + return ( +
+ { messages } +
+
+ ); + } + + /** + * Iterates over all the messages and creates nested arrays which hold + * consecutive messages sent by 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; + } + + /** + * Automatically scrolls the displayed chat messages down to the latest. + * + * @private + * @returns {void} + */ + _scrollMessagesToBottom() { + this._messagesListEndRef.current.scrollIntoView({ + behavior: 'smooth' + }); + } +}