Add check for min/max length for chat message

This commit is contained in:
Oswaldo Acauan 2017-06-01 14:24:29 +00:00
parent 6df3eb2afe
commit 3702da3e08
8 changed files with 105 additions and 50 deletions

View File

@ -35,6 +35,8 @@ class Chat extends Component {
lastReadMessageTime,
partnerIsLoggedOut,
isChatLocked,
minMessageLength,
maxMessageLength,
actions,
intl,
} = this.props;
@ -81,6 +83,8 @@ class Chat extends Component {
chatAreaId={ELEMENT_ID}
chatTitle={title}
chatName={chatName}
minMessageLength={minMessageLength}
maxMessageLength={maxMessageLength}
handleSendMessage={actions.handleSendMessage}
/>
</div>

View File

@ -99,13 +99,14 @@ export default injectIntl(createContainer(({ params, intl }) => {
partnerIsLoggedOut,
isChatLocked,
scrollPosition,
minMessageLength: CHAT_CONFIG.min_message_length,
maxMessageLength: CHAT_CONFIG.max_message_length,
actions: {
handleClosePrivateChat: chatID => ChatService.closePrivateChat(chatID),
handleSendMessage: message => {
ChatService.updateScrollPosition(chatID, null);
let sentMessage = ChatService.sendMessage(chatID, message);
return ChatService.sendMessage(chatID, message);
},
handleScrollUpdate: position => ChatService.updateScrollPosition(chatID, position),

View File

@ -27,6 +27,12 @@ const messages = defineMessages({
id: 'app.chat.inputPlaceholder',
description: 'Chat message input placeholder',
},
errorMinMessageLength: {
id: 'app.chat.errorMinMessageLength',
},
errorMaxMessageLength: {
id: 'app.chat.errorMaxMessageLength',
},
});
class MessageForm extends Component {
@ -35,6 +41,8 @@ class MessageForm extends Component {
this.state = {
message: '',
error: '',
hasErrors: false,
};
this.handleMessageChange = this.handleMessageChange.bind(this);
@ -44,7 +52,6 @@ class MessageForm extends Component {
}
handleMessageKeyDown(e) {
//TODO Prevent send message pressing enter on mobile and/or virtual keyboard
if (e.keyCode === 13 && !e.shiftKey) {
e.preventDefault();
@ -59,73 +66,98 @@ class MessageForm extends Component {
}
handleMessageChange(e) {
this.setState({ message: e.target.value });
const { intl } = this.props;
const message = e.target.value;
let error = '';
const { minMessageLength, maxMessageLength, } = this.props;
if (message.length < minMessageLength) {
error = intl.formatMessage(messages.errorMinMessageLength,
{ 0: minMessageLength - message.length });
}
if (message.length > maxMessageLength) {
error = intl.formatMessage(messages.errorMaxMessageLength,
{ 0: message.length - maxMessageLength });
}
this.setState({
message,
error,
});
}
handleSubmit(e) {
e.preventDefault();
const { disabled } = this.props;
const { disabled, minMessageLength, maxMessageLength, } = this.props;
let message = this.state.message.trim();
if (disabled) {
if (disabled
|| message.length === 0
|| message.length < minMessageLength
|| message.length > maxMessageLength) {
this.setState({ hasErrors: true, });
return false;
}
let message = this.state.message.trim();
// Sanitize. See: http://shebang.brandonmintern.com/foolproof-html-escaping-in-javascript/
let div = document.createElement('div');
div.appendChild(document.createTextNode(message));
message = div.innerHTML;
if (message) {
this.props.handleSendMessage(message);
}
this.setState({ message: '' });
return this.props.handleSendMessage(message)
.then(() => this.setState({
message: '',
hasErrors: false,
}));
}
render() {
const { intl, chatTitle, chatName, disabled } = this.props;
const { intl, chatTitle, chatName, disabled,
minMessageLength, maxMessageLength, } = this.props;
const { hasErrors, error } = this.state;
return (
<form
ref="form"
className={cx(this.props.className, styles.form)}
onSubmit={this.handleSubmit}>
{
// <MessageFormActions
// onClick={() => alert('Not supported yet...')}
// className={styles.actions}
// disabled={disabled}
// label={'More actions'}
// />
}
<TextareaAutosize
className={styles.input}
id="message-input"
placeholder={intl.formatMessage(messages.inputPlaceholder, { 0: chatName })}
aria-controls={this.props.chatAreaId}
aria-label={intl.formatMessage(messages.inputLabel, { 0: chatTitle })}
autoCorrect="off"
autoComplete="off"
spellCheck="true"
disabled={disabled}
value={this.state.message}
onChange={this.handleMessageChange}
onKeyDown={this.handleMessageKeyDown}
/>
<Button
className={styles.sendButton}
aria-label={intl.formatMessage(messages.submitLabel)}
type="submit"
disabled={disabled}
label={intl.formatMessage(messages.submitLabel)}
hideLabel={true}
icon={"send"}
onClick={()=>{}}
<div className={styles.wrapper}>
<TextareaAutosize
className={styles.input}
id="message-input"
placeholder={intl.formatMessage(messages.inputPlaceholder, { 0: chatName })}
aria-controls={this.props.chatAreaId}
aria-label={intl.formatMessage(messages.inputLabel, { 0: chatTitle })}
aria-invalid={ hasErrors ? 'true' : 'false' }
aria-describedby={ hasErrors ? 'message-input-error' : null }
autoCorrect="off"
autoComplete="off"
spellCheck="true"
disabled={disabled}
value={this.state.message}
onChange={this.handleMessageChange}
onKeyDown={this.handleMessageKeyDown}
/>
<Button
className={styles.sendButton}
aria-label={intl.formatMessage(messages.submitLabel)}
type="submit"
disabled={disabled}
label={intl.formatMessage(messages.submitLabel)}
hideLabel={true}
icon="send"
onClick={() => null}
/>
</div>
<div className={styles.info}>
{ hasErrors ? <span id="message-input-error">{error}</span> : null }
</div>
</form>
);
}

View File

@ -4,9 +4,14 @@
flex-grow: 0;
flex-shrink: 0;
align-self: flex-end;
width: 100%;
position: relative;
margin-bottom: -$sm-padding-x;
}
.wrapper {
display: flex;
flex-direction: row;
width: 100%;
}
.actions {
@ -72,3 +77,14 @@
color: $color-gray-light;
}
}
.info {
font-size: $font-size-base * .75;
color: $color-gray-light;
text-align: right;
padding: $border-size 0;
&:before {
content: "\00a0"; // non-breaking space
}
}

View File

@ -192,9 +192,7 @@ const sendMessage = (receiverID, message) => {
Storage.setItem(CLOSED_CHAT_LIST_KEY, _.without(currentClosedChats, receiver.id));
}
makeCall('sendChat', messagePayload);
return messagePayload;
return makeCall('sendChat', messagePayload);
};
const getScrollPosition = (receiverID) => {

View File

@ -8,7 +8,7 @@ $font-size-base: 1rem !default;
$font-size-large: 1.25rem !default;
$font-size-small: .875rem !default;
$line-height-base: 1.428571429 !default; // 20/14
$line-height-base: 1.25 !default; // 20/16
$line-height-computed: floor(($font-size-base * $line-height-base)) !default;
$headings-font-family: inherit !default;

View File

@ -1,5 +1,7 @@
# Chat service configurations
chat:
min_message_length: 1
max_message_length: 5000
grouping_messages_window: 60000
# Chat types
type_system: 'SYSTEM_MESSAGE'

View File

@ -10,6 +10,8 @@
"app.chat.submitLabel": "Send Message",
"app.chat.inputLabel": "Message input for chat {0}",
"app.chat.inputPlaceholder": "Message {0}",
"app.chat.errorMinMessageLength": "The message is {0} characters(s) too short",
"app.chat.errorMaxMessageLength": "The message is {0} characters(s) too long",
"app.chat.titlePublic": "Public Chat",
"app.chat.titlePrivate": "Private Chat with {0}",
"app.chat.partnerDisconnected": "{0} has left the meeting",