From f31e8e09f54418f867f95192a71e67b450340c13 Mon Sep 17 00:00:00 2001 From: samogot Date: Tue, 19 Jul 2016 15:27:23 +0300 Subject: PLT-914 Add mention notifications for replies on a comment thread (#3130) * PLT-914 Add mention notifications for replies on a comment thread * remove useless store method fix highlighting comments posted before th user write something to thread * refactor out isCommentMention function after rebase * change comment bar highlighting to replay icon mention highlighting * settings and always visible highlight * fix unit tests for new settings * change highlight behaviour - if any message in comment thread generates mention - all thread is highlighted - remove always visible highlightion * fix bug about the textarea in the center channel not clearing * fix default settings value notify_props.comments * do not highlight own comments if there is no other user's messages in thread * refactor out ReactDOM.findDOMNode * refactor out using of UserStore from component --- webapp/components/post_view/components/post.jsx | 6 + .../post_view/components/post_header.jsx | 2 + .../components/post_view/components/post_info.jsx | 8 +- .../components/post_view/components/post_list.jsx | 27 +++- .../user_settings/user_settings_notifications.jsx | 154 +++++++++++++++++++-- webapp/i18n/en.json | 5 + webapp/sass/layout/_post.scss | 5 +- 7 files changed, 191 insertions(+), 16 deletions(-) (limited to 'webapp') diff --git a/webapp/components/post_view/components/post.jsx b/webapp/components/post_view/components/post.jsx index ff443e355..3fdd8094e 100644 --- a/webapp/components/post_view/components/post.jsx +++ b/webapp/components/post_view/components/post.jsx @@ -76,6 +76,10 @@ export default class Post extends React.Component { return true; } + if (nextProps.isCommentMention !== this.props.isCommentMention) { + return true; + } + if (nextProps.shouldHighlight !== this.props.shouldHighlight) { return true; } @@ -231,6 +235,7 @@ export default class Post extends React.Component { post={post} sameRoot={this.props.sameRoot} commentCount={commentCount} + isCommentMention={this.props.isCommentMention} handleCommentClick={this.handleCommentClick} handleDropdownOpened={this.handleDropdownOpened} isLastComment={this.props.isLastComment} @@ -274,6 +279,7 @@ Post.propTypes = { compactDisplay: React.PropTypes.bool, previewCollapsed: React.PropTypes.string, commentCount: React.PropTypes.number, + isCommentMention: React.PropTypes.bool, useMilitaryTime: React.PropTypes.bool.isRequired, emojis: React.PropTypes.object.isRequired }; diff --git a/webapp/components/post_view/components/post_header.jsx b/webapp/components/post_view/components/post_header.jsx index e76358304..07b601baf 100644 --- a/webapp/components/post_view/components/post_header.jsx +++ b/webapp/components/post_view/components/post_header.jsx @@ -63,6 +63,7 @@ export default class PostHeader extends React.Component { = 1) { @@ -182,11 +183,15 @@ export default class PostInfo extends React.Component { commentCountText = ''; } + if (this.props.isCommentMention) { + highlightMentionClass = ' mention--highlight'; + } + if (post.state !== Constants.POST_FAILED && post.state !== Constants.POST_LOADING && !Utils.isPostEphemeral(post)) { comments = ( 0, firstNameKey, - channelKey + channelKey, + notifyCommentsLevel: comments }; } @@ -103,6 +107,10 @@ const holders = defineMessages({ id: 'user.settings.notifications.wordsTrigger', defaultMessage: 'Words that trigger mentions' }, + comments: { + id: 'user.settings.notifications.comments', + defaultMessage: 'Comment threads notifications' + }, close: { id: 'user.settings.notifications.close', defaultMessage: 'Close' @@ -140,6 +148,7 @@ class NotificationsTab extends React.Component { data.desktop_sound = this.state.enableSound; data.desktop = this.state.notifyLevel; data.push = this.state.notifyPushLevel; + data.comments = this.state.notifyCommentsLevel; var mentionKeys = []; if (this.state.usernameKey) { @@ -195,21 +204,26 @@ class NotificationsTab extends React.Component { } handleNotifyRadio(notifyLevel) { this.setState({notifyLevel}); - ReactDOM.findDOMNode(this.refs.wrapper).focus(); + this.refs.wrapper.focus(); + } + + handleNotifyCommentsRadio(notifyCommentsLevel) { + this.setState({notifyCommentsLevel}); + this.refs.wrapper.focus(); } handlePushRadio(notifyPushLevel) { this.setState({notifyPushLevel}); - ReactDOM.findDOMNode(this.refs.wrapper).focus(); + this.refs.wrapper.focus(); } handleEmailRadio(enableEmail) { this.setState({enableEmail}); - ReactDOM.findDOMNode(this.refs.wrapper).focus(); + this.refs.wrapper.focus(); } handleSoundRadio(enableSound) { this.setState({enableSound}); - ReactDOM.findDOMNode(this.refs.wrapper).focus(); + this.refs.wrapper.focus(); } updateUsernameKey(val) { this.setState({usernameKey: val}); @@ -224,10 +238,10 @@ class NotificationsTab extends React.Component { this.setState({channelKey: val}); } updateCustomMentionKeys() { - var checked = ReactDOM.findDOMNode(this.refs.customcheck).checked; + var checked = this.refs.customcheck.checked; if (checked) { - var text = ReactDOM.findDOMNode(this.refs.custommentions).value; + var text = this.refs.custommentions.value; // remove all spaces and split string into individual keys this.setState({customKeys: text.replace(/ /g, ''), customKeysChecked: true}); @@ -236,7 +250,7 @@ class NotificationsTab extends React.Component { } } onCustomChange() { - ReactDOM.findDOMNode(this.refs.customcheck).checked = true; + this.refs.customcheck.checked = true; this.updateCustomMentionKeys(); } createPushNotificationSection() { @@ -902,6 +916,126 @@ class NotificationsTab extends React.Component { ); } + var commentsSection; + var handleUpdateCommentsSection; + if (this.props.activeSection === 'comments') { + var commentsActive = [false, false, false]; + if (this.state.notifyCommentsLevel === 'never') { + commentsActive[2] = true; + } else if (this.state.notifyCommentsLevel === 'root') { + commentsActive[1] = true; + } else { + commentsActive[0] = true; + } + + let inputs = []; + + inputs.push( +
+
+ +
+
+
+ +
+
+
+ +
+
+ ); + + const extraInfo = ( + + + + ); + + commentsSection = ( + + ); + } else { + let describe = ''; + if (this.state.notifyCommentsLevel === 'never') { + describe = ( + + ); + } else if (this.state.notifyCommentsLevel === 'root') { + describe = ( + + ); + } else { + describe = ( + + ); + } + + handleUpdateCommentsSection = function updateCommentsSection() { + this.props.updateSection('comments'); + }.bind(this); + + commentsSection = ( + + ); + } + const pushNotificationSection = this.createPushNotificationSection(); return ( @@ -952,6 +1086,8 @@ class NotificationsTab extends React.Component { {pushNotificationSection}
{keysSection} +
+ {commentsSection}
diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json index 27c5b7da4..3a514d0b3 100644 --- a/webapp/i18n/en.json +++ b/webapp/i18n/en.json @@ -1610,6 +1610,11 @@ "user.settings.notification.soundConfig": "Please configure notification sounds in your browser settings", "user.settings.notifications.channelWide": "Channel-wide mentions \"@channel\", \"@all\"", "user.settings.notifications.close": "Close", + "user.settings.notifications.comments": "Comment threads notifications", + "user.settings.notifications.commentsAny": "Mention any comments in a thread you participated in (This will include both mentions to your root post and any comments after you commented on a post)", + "user.settings.notifications.commentsInfo": "Mode of triggering notifications on posts in comment threads you participated in.", + "user.settings.notifications.commentsNever": "No mentions for comments", + "user.settings.notifications.commentsRoot": "Mention any comments on your post", "user.settings.notifications.desktop": "Send desktop notifications", "user.settings.notifications.desktopSounds": "Desktop notification sounds", "user.settings.notifications.emailInfo": "Email notifications are sent for mentions and direct messages after you’ve been offline for more than 60 seconds or away from {siteName} for more than 5 minutes.", diff --git a/webapp/sass/layout/_post.scss b/webapp/sass/layout/_post.scss index f95bb3e59..d4dec54d7 100644 --- a/webapp/sass/layout/_post.scss +++ b/webapp/sass/layout/_post.scss @@ -560,7 +560,7 @@ body.ios { .img-div { max-height: 150px; max-width: 150px; - } + } p { line-height: inherit; @@ -572,7 +572,7 @@ body.ios { ol, ul { - clear: both; + clear: both; padding-left: 20px; } } @@ -1070,7 +1070,6 @@ body.ios { display: inline-block; margin-right: 6px; visibility: hidden; - svg { fill: inherit; position: relative; -- cgit v1.2.3-1-g7c22