RN-335 Reaction shortcut (#920)
* RN-335 Reaction shortcut * Review feedback
This commit is contained in:
parent
ad80fd37c7
commit
8694f59e80
5 changed files with 77 additions and 19 deletions
17
app/actions/views/emoji.js
Normal file
17
app/actions/views/emoji.js
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {addReaction} from 'mattermost-redux/actions/posts';
|
||||
import {getPostsInCurrentChannel, makeGetPostsForThread} from 'mattermost-redux/selectors/entities/posts';
|
||||
|
||||
const getPostsForThread = makeGetPostsForThread();
|
||||
|
||||
export function addReactionToLatestPost(emoji, rootId) {
|
||||
return async (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const posts = rootId ? getPostsForThread(state, {rootId}) : getPostsInCurrentChannel(state);
|
||||
const lastPost = posts[0];
|
||||
|
||||
dispatch(addReaction(lastPost.id, emoji));
|
||||
};
|
||||
}
|
||||
|
|
@ -13,15 +13,19 @@ import {
|
|||
import Emoji from 'app/components/emoji';
|
||||
import {makeStyleSheetFromTheme, changeOpacity} from 'app/utils/theme';
|
||||
|
||||
const EMOJI_REGEX = /\B(:([^:\r\n\s]*))$/i;
|
||||
const EMOJI_REGEX = /(^|\s|^\+|^-)(:([^:\s]*))$/i;
|
||||
|
||||
export default class EmojiSuggestion extends Component {
|
||||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
addReactionToLatestPost: PropTypes.func.isRequired
|
||||
}).isRequired,
|
||||
cursorPosition: PropTypes.number,
|
||||
emojis: PropTypes.array.isRequired,
|
||||
postDraft: PropTypes.string,
|
||||
theme: PropTypes.object.isRequired,
|
||||
onChangeText: PropTypes.func.isRequired
|
||||
onChangeText: PropTypes.func.isRequired,
|
||||
rootId: PropTypes.string
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
|
@ -47,7 +51,7 @@ export default class EmojiSuggestion extends Component {
|
|||
return;
|
||||
}
|
||||
|
||||
const matchTerm = match[2];
|
||||
const matchTerm = match[3];
|
||||
if (matchTerm !== this.state.matchTerm) {
|
||||
this.setState({
|
||||
matchTerm
|
||||
|
|
@ -70,16 +74,22 @@ export default class EmojiSuggestion extends Component {
|
|||
}
|
||||
|
||||
completeSuggestion = (emoji) => {
|
||||
const {cursorPosition, onChangeText, postDraft} = this.props;
|
||||
const {actions, cursorPosition, onChangeText, postDraft, rootId} = this.props;
|
||||
const emojiPart = postDraft.substring(0, cursorPosition);
|
||||
|
||||
let completedDraft = emojiPart.replace(EMOJI_REGEX, `:${emoji}: `);
|
||||
if (emojiPart.startsWith('+:')) {
|
||||
actions.addReactionToLatestPost(emoji, rootId);
|
||||
onChangeText('');
|
||||
} else {
|
||||
let completedDraft = emojiPart.replace(EMOJI_REGEX, `:${emoji}: `);
|
||||
|
||||
if (postDraft.length > cursorPosition) {
|
||||
completedDraft += postDraft.substring(cursorPosition);
|
||||
if (postDraft.length > cursorPosition) {
|
||||
completedDraft += postDraft.substring(cursorPosition);
|
||||
}
|
||||
|
||||
onChangeText(completedDraft);
|
||||
}
|
||||
|
||||
onChangeText(completedDraft);
|
||||
this.setState({
|
||||
active: false,
|
||||
emojiComplete: true
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@
|
|||
|
||||
import {connect} from 'react-redux';
|
||||
import {createSelector} from 'reselect';
|
||||
import {bindActionCreators} from 'redux';
|
||||
|
||||
import {getCustomEmojisByName} from 'mattermost-redux/selectors/entities/emojis';
|
||||
|
||||
import {addReactionToLatestPost} from 'app/actions/views/emoji';
|
||||
import {getTheme} from 'app/selectors/preferences';
|
||||
import {EmojiIndicesByAlias} from 'app/utils/emojis';
|
||||
|
||||
|
|
@ -47,4 +49,12 @@ function mapStateToProps(state, ownProps) {
|
|||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(EmojiSuggestion);
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
addReactionToLatestPost
|
||||
}, dispatch)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(EmojiSuggestion);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {connect} from 'react-redux';
|
|||
import {createPost} from 'mattermost-redux/actions/posts';
|
||||
import {userTyping} from 'mattermost-redux/actions/websocket';
|
||||
|
||||
import {addReactionToLatestPost} from 'app/actions/views/emoji';
|
||||
import {handleClearFiles, handleRemoveLastFile, handleUploadFiles} from 'app/actions/views/file_upload';
|
||||
import {getTheme} from 'app/selectors/preferences';
|
||||
import {canUploadFilesOnMobile} from 'mattermost-redux/selectors/entities/general';
|
||||
|
|
@ -29,6 +30,7 @@ function mapStateToProps(state, ownProps) {
|
|||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
addReactionToLatestPost,
|
||||
createPost,
|
||||
handleClearFiles,
|
||||
handleRemoveLastFile,
|
||||
|
|
|
|||
|
|
@ -27,10 +27,12 @@ import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
|||
const INITIAL_HEIGHT = Platform.OS === 'ios' ? 34 : 36;
|
||||
const MAX_CONTENT_HEIGHT = 100;
|
||||
const MAX_MESSAGE_LENGTH = 4000;
|
||||
const IS_REACTION_REGEX = /(^\+:([^:\s]*):)$/i;
|
||||
|
||||
class PostTextbox extends PureComponent {
|
||||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
addReactionToLatestPost: PropTypes.func.isRequired,
|
||||
createPost: PropTypes.func.isRequired,
|
||||
handleClearFiles: PropTypes.func.isRequired,
|
||||
handleRemoveLastFile: PropTypes.func.isRequired,
|
||||
|
|
@ -137,7 +139,16 @@ class PostTextbox extends PureComponent {
|
|||
return;
|
||||
}
|
||||
|
||||
const hasFailedImages = this.props.files.some((f) => f.failed);
|
||||
const {files, value} = this.props;
|
||||
|
||||
const isReactionMatch = value.match(IS_REACTION_REGEX);
|
||||
if (isReactionMatch) {
|
||||
const emoji = isReactionMatch[2];
|
||||
this.sendReaction(emoji);
|
||||
return;
|
||||
}
|
||||
|
||||
const hasFailedImages = files.some((f) => f.failed);
|
||||
if (hasFailedImages) {
|
||||
const {intl} = this.props;
|
||||
|
||||
|
|
@ -163,19 +174,21 @@ class PostTextbox extends PureComponent {
|
|||
};
|
||||
|
||||
sendMessage = () => {
|
||||
const files = this.props.files.filter((f) => !f.failed);
|
||||
const {actions, currentUserId, channelId, files, rootId, value} = this.props;
|
||||
|
||||
const postFiles = files.filter((f) => !f.failed);
|
||||
const post = {
|
||||
user_id: this.props.currentUserId,
|
||||
channel_id: this.props.channelId,
|
||||
root_id: this.props.rootId,
|
||||
parent_id: this.props.rootId,
|
||||
message: this.props.value
|
||||
user_id: currentUserId,
|
||||
channel_id: channelId,
|
||||
root_id: rootId,
|
||||
parent_id: rootId,
|
||||
message: value
|
||||
};
|
||||
|
||||
this.props.actions.createPost(post, files);
|
||||
actions.createPost(post, postFiles);
|
||||
this.handleTextChange('');
|
||||
if (this.props.files.length) {
|
||||
this.props.actions.handleClearFiles(this.props.channelId, this.props.rootId);
|
||||
if (postFiles.length) {
|
||||
actions.handleClearFiles(channelId, rootId);
|
||||
}
|
||||
|
||||
// Shrink the input textbox since the layout events lag slightly
|
||||
|
|
@ -184,6 +197,12 @@ class PostTextbox extends PureComponent {
|
|||
});
|
||||
};
|
||||
|
||||
sendReaction = (emoji) => {
|
||||
const {actions, rootId} = this.props;
|
||||
actions.addReactionToLatestPost(emoji, rootId);
|
||||
this.handleTextChange('');
|
||||
}
|
||||
|
||||
handleTextChange = (text) => {
|
||||
const {
|
||||
onChangeText,
|
||||
|
|
|
|||
Loading…
Reference in a new issue