From d7622eb7a45afd9219afa3812717e3b0cc31ecd0 Mon Sep 17 00:00:00 2001 From: enahum Date: Mon, 13 Nov 2017 13:52:43 -0300 Subject: [PATCH] RN-360 Add support for interactive message buttons (#1131) --- app/components/post/post.js | 2 +- app/components/post_body/post_body.js | 2 + .../post_body_additional_content.js | 5 +- app/components/slack_attachments/index.js | 12 ++-- .../interactive_action/index.js | 26 ++++++++ .../interactive_action/interactive_action.js | 61 +++++++++++++++++++ .../slack_attachments/slack_attachment.js | 53 +++++++++++++--- 7 files changed, 147 insertions(+), 14 deletions(-) create mode 100644 app/components/slack_attachments/interactive_action/index.js create mode 100644 app/components/slack_attachments/interactive_action/interactive_action.js diff --git a/app/components/post/post.js b/app/components/post/post.js index 8f8c76c62..71dbe90c5 100644 --- a/app/components/post/post.js +++ b/app/components/post/post.js @@ -295,7 +295,7 @@ class Post extends PureComponent { theme } = this.props; - if (!renderReplies || !post.root_id) { + if (!renderReplies || !post.root_id || isPostEphemeral(post)) { return null; } diff --git a/app/components/post_body/post_body.js b/app/components/post_body/post_body.js index 5a454b4ed..7df3fd839 100644 --- a/app/components/post_body/post_body.js +++ b/app/components/post_body/post_body.js @@ -253,6 +253,7 @@ class PostBody extends PureComponent { blockStyles={blockStyles} navigator={navigator} message={message} + postId={postId} postProps={postProps} textStyles={textStyles} /> @@ -275,6 +276,7 @@ class PostBody extends PureComponent { blockStyles={blockStyles} navigator={navigator} message={message} + postId={postId} postProps={postProps} textStyles={textStyles} onLongPress={this.showOptionsContext} diff --git a/app/components/post_body_additional_content/post_body_additional_content.js b/app/components/post_body_additional_content/post_body_additional_content.js index 530f21cfd..592749f96 100644 --- a/app/components/post_body_additional_content/post_body_additional_content.js +++ b/app/components/post_body_additional_content/post_body_additional_content.js @@ -37,6 +37,7 @@ export default class PostBodyAdditionalContent extends PureComponent { navigator: PropTypes.object.isRequired, onLongPress: PropTypes.func, openGraphData: PropTypes.object, + postId: PropTypes.string.isRequired, postProps: PropTypes.object.isRequired, showLinkPreviews: PropTypes.bool.isRequired, textStyles: PropTypes.object, @@ -45,7 +46,7 @@ export default class PostBodyAdditionalContent extends PureComponent { static defaultProps = { onLongPress: emptyFunction - } + }; constructor(props) { super(props); @@ -152,6 +153,7 @@ export default class PostBodyAdditionalContent extends PureComponent { getSlackAttachment = () => { const { + postId, postProps, baseTextStyle, blockStyles, @@ -168,6 +170,7 @@ export default class PostBodyAdditionalContent extends PureComponent { baseTextStyle={baseTextStyle} blockStyles={blockStyles} navigator={navigator} + postId={postId} textStyles={textStyles} theme={theme} onLongPress={this.props.onLongPress} diff --git a/app/components/slack_attachments/index.js b/app/components/slack_attachments/index.js index a8b97e38e..f0b93670a 100644 --- a/app/components/slack_attachments/index.js +++ b/app/components/slack_attachments/index.js @@ -14,14 +14,15 @@ export default class SlackAttachments extends PureComponent { attachments: PropTypes.array.isRequired, baseTextStyle: CustomPropTypes.Style, blockStyles: PropTypes.object, - textStyles: PropTypes.object, + postId: PropTypes.string.isRequired, navigator: PropTypes.object.isRequired, + onLongPress: PropTypes.func.isRequired, theme: PropTypes.object, - onLongPress: PropTypes.func.isRequired + textStyles: PropTypes.object }; render() { - const {attachments, baseTextStyle, blockStyles, navigator, textStyles, theme, onLongPress} = this.props; + const {attachments, baseTextStyle, blockStyles, navigator, onLongPress, postId, theme, textStyles} = this.props; const content = []; attachments.forEach((attachment, i) => { @@ -31,10 +32,11 @@ export default class SlackAttachments extends PureComponent { baseTextStyle={baseTextStyle} blockStyles={blockStyles} key={'att_' + i} - textStyles={textStyles} navigator={navigator} - theme={theme} onLongPress={onLongPress} + postId={postId} + theme={theme} + textStyles={textStyles} /> ); }); diff --git a/app/components/slack_attachments/interactive_action/index.js b/app/components/slack_attachments/interactive_action/index.js new file mode 100644 index 000000000..dd7e40e53 --- /dev/null +++ b/app/components/slack_attachments/interactive_action/index.js @@ -0,0 +1,26 @@ +// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import {bindActionCreators} from 'redux'; +import {connect} from 'react-redux'; + +import {doPostAction} from 'mattermost-redux/actions/posts'; +import {getTheme} from 'mattermost-redux/selectors/entities/preferences'; + +import InteractiveAction from './interactive_action'; + +function mapStateToProps(state) { + return { + theme: getTheme(state) + }; +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators({ + doPostAction + }, dispatch) + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(InteractiveAction); diff --git a/app/components/slack_attachments/interactive_action/interactive_action.js b/app/components/slack_attachments/interactive_action/interactive_action.js new file mode 100644 index 000000000..b121da32b --- /dev/null +++ b/app/components/slack_attachments/interactive_action/interactive_action.js @@ -0,0 +1,61 @@ +// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import React, {PureComponent} from 'react'; +import {Text} from 'react-native'; +import PropTypes from 'prop-types'; +import Button from 'react-native-button'; + +import {wrapWithPreventDoubleTap} from 'app/utils/tap'; +import {makeStyleSheetFromTheme} from 'app/utils/theme'; + +export default class InteractiveAction extends PureComponent { + static propTypes = { + actions: PropTypes.shape({ + doPostAction: PropTypes.func.isRequired + }).isRequired, + id: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + postId: PropTypes.string.isRequired, + theme: PropTypes.object.isRequired + }; + + handleActionPress = wrapWithPreventDoubleTap(() => { + const {actions, id, postId} = this.props; + actions.doPostAction(postId, id); + }); + + render() { + const {name, theme} = this.props; + const style = getStyleSheet(theme); + + return ( + + ); + } +} + +const getStyleSheet = makeStyleSheetFromTheme((theme) => { + return { + button: { + borderRadius: 2, + backgroundColor: theme.buttonBg, + alignItems: 'center', + marginBottom: 2, + marginRight: 5, + marginTop: 10, + paddingHorizontal: 10, + paddingVertical: 7 + }, + text: { + color: theme.buttonColor, + fontSize: 12, + fontWeight: '600' + } + }; +}); diff --git a/app/components/slack_attachments/slack_attachment.js b/app/components/slack_attachments/slack_attachment.js index 6b923ab67..6071a3561 100644 --- a/app/components/slack_attachments/slack_attachment.js +++ b/app/components/slack_attachments/slack_attachment.js @@ -10,20 +10,23 @@ import { View } from 'react-native'; -import CustomPropTypes from 'app/constants/custom_prop_types'; -import Markdown from 'app/components/markdown'; import FormattedText from 'app/components/formatted_text'; +import Markdown from 'app/components/markdown'; +import CustomPropTypes from 'app/constants/custom_prop_types'; import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; +import InteractiveAction from './interactive_action'; + export default class SlackAttachment extends PureComponent { static propTypes = { attachment: PropTypes.object.isRequired, baseTextStyle: CustomPropTypes.Style, blockStyles: PropTypes.object, navigator: PropTypes.object.isRequired, - textStyles: PropTypes.object, + postId: PropTypes.string.isRequired, + onLongPress: PropTypes.func.isRequired, theme: PropTypes.object, - onLongPress: PropTypes.func.isRequired + textStyles: PropTypes.object }; constructor(props) { @@ -32,6 +35,37 @@ export default class SlackAttachment extends PureComponent { this.state = this.getInitState(); } + getActionView = (style) => { + const {attachment, postId} = this.props; + const {actions} = attachment; + + if (!actions || !actions.length) { + return null; + } + + const buttons = []; + + actions.forEach((action) => { + if (!action.id || !action.name) { + return; + } + buttons.push( + + ); + }); + + return ( + + {buttons} + + ); + }; + getCollapsedText = () => { let text = this.props.attachment.text || ''; if ((text.match(/\n/g) || []).length >= 5) { @@ -304,6 +338,7 @@ export default class SlackAttachment extends PureComponent { } const fields = this.getFieldsTable(style); + const actions = this.getActionView(style); let image; if (attachment.image_url) { @@ -330,6 +365,7 @@ export default class SlackAttachment extends PureComponent { {thumb} {text} {fields} + {actions} {image} @@ -344,8 +380,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { borderWidth: 1, flex: 1, marginTop: 5, - paddingHorizontal: 10, - paddingVertical: 7 + padding: 10 }, border: { borderLeftColor: changeOpacity(theme.linkColor, 0.6), @@ -366,7 +401,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { title: { color: theme.centerChannelColor, fontWeight: '600', - marginVertical: 5 + marginBottom: 5 }, titleLink: { color: theme.linkColor @@ -409,6 +444,10 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { image: { flex: 1, height: 50 + }, + actionsContainer: { + flex: 1, + flexDirection: 'row' } }; });