Major cleanup. Moved a lot of CSS variables out too root of CSS for easier styling.
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withRoomContext } from '../../../RoomContext';
|
||||
import MessageList from './MessageList';
|
||||
|
||||
class Chat extends Component
|
||||
{
|
||||
createNewMessage(text, sender, name, picture)
|
||||
{
|
||||
return {
|
||||
type : 'message',
|
||||
text,
|
||||
time : Date.now(),
|
||||
name,
|
||||
sender,
|
||||
picture
|
||||
};
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
const {
|
||||
roomClient,
|
||||
senderPlaceHolder,
|
||||
disabledInput,
|
||||
autofocus,
|
||||
displayName,
|
||||
picture
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div data-component='Chat'>
|
||||
<MessageList />
|
||||
<form
|
||||
data-component='Sender'
|
||||
onSubmit={(e) =>
|
||||
{
|
||||
e.preventDefault();
|
||||
const userInput = e.target.message.value;
|
||||
|
||||
if (userInput)
|
||||
{
|
||||
const message = this.createNewMessage(userInput, 'response', displayName, picture);
|
||||
|
||||
roomClient.sendChatMessage(message);
|
||||
}
|
||||
e.target.message.value = '';
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type='text'
|
||||
className='new-message'
|
||||
name='message'
|
||||
placeholder={senderPlaceHolder}
|
||||
disabled={disabledInput}
|
||||
autoFocus={autofocus}
|
||||
autoComplete='off'
|
||||
/>
|
||||
<input
|
||||
type='submit'
|
||||
className='send'
|
||||
value='Send'
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Chat.propTypes =
|
||||
{
|
||||
roomClient : PropTypes.any.isRequired,
|
||||
senderPlaceHolder : PropTypes.string,
|
||||
disabledInput : PropTypes.bool,
|
||||
autofocus : PropTypes.bool,
|
||||
displayName : PropTypes.string,
|
||||
picture : PropTypes.string
|
||||
};
|
||||
|
||||
Chat.defaultProps =
|
||||
{
|
||||
senderPlaceHolder : 'Type a message...',
|
||||
autofocus : false,
|
||||
displayName : null
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) =>
|
||||
{
|
||||
return {
|
||||
disabledInput : state.chatbehavior.disabledInput,
|
||||
displayName : state.me.displayName,
|
||||
picture : state.me.picture
|
||||
};
|
||||
};
|
||||
|
||||
const ChatContainer = withRoomContext(connect(
|
||||
mapStateToProps
|
||||
)(Chat));
|
||||
|
||||
export default ChatContainer;
|
||||
@@ -0,0 +1,98 @@
|
||||
import React, { Component } from 'react';
|
||||
import { compose } from 'redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import marked from 'marked';
|
||||
import { connect } from 'react-redux';
|
||||
import scrollToBottom from '../scrollToBottom';
|
||||
|
||||
const linkRenderer = new marked.Renderer();
|
||||
|
||||
linkRenderer.link = (href, title, text) =>
|
||||
{
|
||||
title = title ? title : href;
|
||||
text = text ? text : href;
|
||||
|
||||
return (`<a target='_blank' href='${ href }' title='${ title }'>${ text }</a>`);
|
||||
};
|
||||
|
||||
class MessageList extends Component
|
||||
{
|
||||
getTimeString(time)
|
||||
{
|
||||
return `${(time.getHours() < 10 ? '0' : '')}${time.getHours()}:${(time.getMinutes() < 10 ? '0' : '')}${time.getMinutes()}`;
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
const {
|
||||
chatmessages
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div data-component='MessageList' id='messages'>
|
||||
<Choose>
|
||||
<When condition={chatmessages.length > 0}>
|
||||
{
|
||||
chatmessages.map((message, i) =>
|
||||
{
|
||||
const messageTime = new Date(message.time);
|
||||
|
||||
const picture = (message.sender === 'response' ?
|
||||
message.picture : this.props.myPicture) || 'resources/images/avatar-empty.jpeg';
|
||||
|
||||
return (
|
||||
<div className='message' key={i}>
|
||||
<div className={message.sender}>
|
||||
<img className='message-avatar' src={picture} />
|
||||
|
||||
<div className='message-content'>
|
||||
<div
|
||||
className='message-text'
|
||||
// eslint-disable-next-line react/no-danger
|
||||
dangerouslySetInnerHTML={{ __html : marked.parse(
|
||||
message.text,
|
||||
{ sanitize: true, renderer: linkRenderer }
|
||||
) }}
|
||||
/>
|
||||
|
||||
<span className='message-time'>
|
||||
{message.name} - {this.getTimeString(messageTime)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
}
|
||||
</When>
|
||||
<Otherwise>
|
||||
<div className='empty'>
|
||||
<p>No one has said anything yet...</p>
|
||||
</div>
|
||||
</Otherwise>
|
||||
</Choose>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MessageList.propTypes =
|
||||
{
|
||||
chatmessages : PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
myPicture : PropTypes.string
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) =>
|
||||
{
|
||||
return {
|
||||
chatmessages : state.chatmessages,
|
||||
myPicture : state.me.picture
|
||||
};
|
||||
};
|
||||
|
||||
const MessageListContainer = compose(
|
||||
connect(mapStateToProps),
|
||||
scrollToBottom()
|
||||
)(MessageList);
|
||||
|
||||
export default MessageListContainer;
|
||||
Reference in New Issue
Block a user