From 24eddf083f5fee5e8ccc8b8e69916b7b0a53436b Mon Sep 17 00:00:00 2001 From: "Michael H. Arieli" Date: Sat, 24 Nov 2018 18:55:27 -0800 Subject: [PATCH] Updated chat look and feel Changed to simple entry list --- src/client/actions/ChatActions.js | 5 +- src/client/components/Chat.js | 82 ++++- src/client/components/Input.js | 29 +- src/client/components/Video.js | 2 + src/client/components/__tests__/Input-test.js | 2 +- src/scss/_chat.scss | 286 +++++++++++------- 6 files changed, 279 insertions(+), 127 deletions(-) diff --git a/src/client/actions/ChatActions.js b/src/client/actions/ChatActions.js index 799a63f..8c1feaa 100644 --- a/src/client/actions/ChatActions.js +++ b/src/client/actions/ChatActions.js @@ -1,14 +1,15 @@ import * as constants from '../constants.js' import _ from 'underscore' -export function addMessage ({ userId, message, timestamp }) { +export function addMessage ({ userId, message, timestamp, image }) { return { type: constants.MESSAGE_ADD, payload: { id: _.uniqueId('chat'), userId, message, - timestamp + timestamp, + image } } } diff --git a/src/client/components/Chat.js b/src/client/components/Chat.js index 0edfe1c..a00b3aa 100644 --- a/src/client/components/Chat.js +++ b/src/client/components/Chat.js @@ -1,11 +1,12 @@ import PropTypes from 'prop-types' import React from 'react' -import socket from '../socket.js' +import moment from 'moment' export const MessagePropTypes = PropTypes.shape({ userId: PropTypes.string.isRequired, message: PropTypes.string.isRequired, - timestamp: PropTypes.string.isRequired + timestamp: PropTypes.string.isRequired, + image: PropTypes.string }) export default class Chat extends React.PureComponent { @@ -16,6 +17,43 @@ export default class Chat extends React.PureComponent { document.getElementById('chat').classList.remove('show') document.querySelector('.toolbar .chat').classList.remove('on') } + scrollToBottom = () => { + // this.chatScroll.scrollTop = this.chatScroll.scrollHeight + + const duration = 300 + const start = this.chatScroll.scrollTop + const end = this.chatScroll.scrollHeight + const change = end - start + const increment = 20 + + const easeInOut = (currentTime, start, change, duration) => { + currentTime /= duration / 2 + if (currentTime < 1) { + return change / 2 * currentTime * currentTime + start + } + currentTime -= 1 + return -change / 2 * (currentTime * (currentTime - 2) - 1) + start + } + + const animate = elapsedTime => { + elapsedTime += increment + const position = easeInOut(elapsedTime, start, change, duration) + this.chatScroll.scrollTop = position + if (elapsedTime < duration) { + setTimeout(() => { + animate(elapsedTime) + }, increment) + } + } + + animate(0) + } + componentDidMount () { + this.scrollToBottom() + } + componentDidUpdate () { + this.scrollToBottom() + } render () { const { messages } = this.props return ( @@ -28,23 +66,37 @@ export default class Chat extends React.PureComponent {
Chat
-
+
{ this.chatScroll = div }}> {messages.length ? ( messages.map((message, i) => ( -
-
-

{message.userId}

-

{message.message}

- {message.timestamp} +
+
+
+ {message.image ? ( +
+
+ +
+
+ ) : ( +
+
+ {message.userId.substr(0, 2).toUpperCase()} +
+
+ )} +
+
+
+ {moment(message.timestamp).fromNow()} +
+
+
+ {message.message}
-
)) ) : ( diff --git a/src/client/components/Input.js b/src/client/components/Input.js index 1f8a313..6989d24 100644 --- a/src/client/components/Input.js +++ b/src/client/components/Input.js @@ -1,6 +1,5 @@ import PropTypes from 'prop-types' import React from 'react' -import moment from 'moment' import socket from '../socket.js' export default class Input extends React.PureComponent { @@ -24,7 +23,7 @@ export default class Input extends React.PureComponent { this.submit() } handleKeyPress = e => { - if (e.key === 'Enter') { + if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault() this.submit() } @@ -37,8 +36,21 @@ export default class Input extends React.PureComponent { sendMessage(message) const userId = socket.id - const timestamp = moment().format('ddd, D MMM HH:mm a') - const payload = { userId, message, timestamp } + const timestamp = new Date() + let image = null + + // take snapshoot + try { + const video = document.getElementById(`video-${userId}`) + const canvas = document.createElement('canvas') + canvas.height = video.videoHeight + canvas.width = video.videoWidth + const avatar = canvas.getContext('2d') + avatar.drawImage(video, 0, 0, canvas.width, canvas.height) + image = canvas.toDataURL() + } catch (e) {} + + const payload = { userId, message, timestamp, image } socket.emit('new_message', payload) } this.setState({ message: '' }) @@ -46,15 +58,18 @@ export default class Input extends React.PureComponent { render () { const { message } = this.state return ( -
- +