diff options
author | enahum <nahumhbl@gmail.com> | 2017-02-27 17:55:12 -0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-02-27 17:55:12 -0300 |
commit | f07571d79de1c00529136cd74c075ddfc4784b41 (patch) | |
tree | fe67b9879fe6e09d65bf36260b77185e7f2c6704 /webapp | |
parent | 48f97a5a2a0754bfc0e639db7cce03943e990e32 (diff) | |
download | chat-f07571d79de1c00529136cd74c075ddfc4784b41.tar.gz chat-f07571d79de1c00529136cd74c075ddfc4784b41.tar.bz2 chat-f07571d79de1c00529136cd74c075ddfc4784b41.zip |
PLT-3193 Add channel notification preferences for push notifications (#5512)
* PLT-3193 Add channel notification preferences for push and email notifications
* Fixing UI
* Removing email as preferences from the UI for now
* move to action
* fix client test
Diffstat (limited to 'webapp')
-rw-r--r-- | webapp/actions/channel_actions.jsx | 8 | ||||
-rw-r--r-- | webapp/components/channel_notifications_modal.jsx | 262 | ||||
-rw-r--r-- | webapp/components/user_settings/email_notification_setting.jsx | 26 | ||||
-rw-r--r-- | webapp/i18n/en.json | 2 | ||||
-rw-r--r-- | webapp/utils/constants.jsx | 5 |
5 files changed, 254 insertions, 49 deletions
diff --git a/webapp/actions/channel_actions.jsx b/webapp/actions/channel_actions.jsx index 5f41d127d..582de54cc 100644 --- a/webapp/actions/channel_actions.jsx +++ b/webapp/actions/channel_actions.jsx @@ -316,9 +316,13 @@ export function autocompleteChannels(term, success, error) { ); } -export function updateChannelNotifyProps(data, success, error) { - Client.updateChannelNotifyProps(data, +export function updateChannelNotifyProps(data, options, success, error) { + Client.updateChannelNotifyProps(Object.assign({}, data, options), () => { + const member = ChannelStore.getMyMember(data.channel_id); + member.notify_props = Object.assign(member.notify_props, options); + ChannelStore.storeMyChannelMember(member); + if (success) { success(); } diff --git a/webapp/components/channel_notifications_modal.jsx b/webapp/components/channel_notifications_modal.jsx index 58ab9143f..e78755fe3 100644 --- a/webapp/components/channel_notifications_modal.jsx +++ b/webapp/components/channel_notifications_modal.jsx @@ -4,8 +4,6 @@ import SettingItemMin from 'components/setting_item_min.jsx'; import SettingItemMax from 'components/setting_item_max.jsx'; -import ChannelStore from 'stores/channel_store.jsx'; - import $ from 'jquery'; import React from 'react'; import {Modal} from 'react-bootstrap'; @@ -20,19 +18,24 @@ export default class ChannelNotificationsModal extends React.Component { this.updateSection = this.updateSection.bind(this); this.onHide = this.onHide.bind(this); - this.handleSubmitNotifyLevel = this.handleSubmitNotifyLevel.bind(this); - this.handleUpdateNotifyLevel = this.handleUpdateNotifyLevel.bind(this); - this.createNotifyLevelSection = this.createNotifyLevelSection.bind(this); + this.handleSubmitDesktopNotifyLevel = this.handleSubmitDesktopNotifyLevel.bind(this); + this.handleUpdateDesktopNotifyLevel = this.handleUpdateDesktopNotifyLevel.bind(this); + this.createDesktopNotifyLevelSection = this.createDesktopNotifyLevelSection.bind(this); this.handleSubmitMarkUnreadLevel = this.handleSubmitMarkUnreadLevel.bind(this); this.handleUpdateMarkUnreadLevel = this.handleUpdateMarkUnreadLevel.bind(this); this.createMarkUnreadLevelSection = this.createMarkUnreadLevelSection.bind(this); + this.handleSubmitPushNotificationLevel = this.handleSubmitPushNotificationLevel.bind(this); + this.handleUpdatePushNotificationLevel = this.handleUpdatePushNotificationLevel.bind(this); + this.createPushNotificationLevelSection = this.createPushNotificationLevelSection.bind(this); + this.state = { activeSection: '', show: true, notifyLevel: props.channelMember.notify_props.desktop, - unreadLevel: props.channelMember.notify_props.mark_unread + unreadLevel: props.channelMember.notify_props.mark_unread, + pushLevel: props.channelMember.notify_props.push || 'default' }; } @@ -47,7 +50,7 @@ export default class ChannelNotificationsModal extends React.Component { this.setState({show: false}); } - handleSubmitNotifyLevel() { + handleSubmitDesktopNotifyLevel() { const channelId = this.props.channel.id; const notifyLevel = this.state.notifyLevel; const currentUserId = this.props.currentUser.id; @@ -57,19 +60,14 @@ export default class ChannelNotificationsModal extends React.Component { return; } + const options = {desktop: notifyLevel}; const data = { channel_id: channelId, - user_id: currentUserId, - desktop: notifyLevel + user_id: currentUserId }; - updateChannelNotifyProps(data, + updateChannelNotifyProps(data, options, () => { - // YUCK - var member = ChannelStore.getMyMember(channelId); - member.notify_props.desktop = notifyLevel; - ChannelStore.storeMyChannelMember(member); - this.updateSection(''); }, (err) => { @@ -78,11 +76,11 @@ export default class ChannelNotificationsModal extends React.Component { ); } - handleUpdateNotifyLevel(notifyLevel) { + handleUpdateDesktopNotifyLevel(notifyLevel) { this.setState({notifyLevel}); } - createNotifyLevelSection(serverError) { + createDesktopNotifyLevelSection(serverError) { // Get glabal user setting for notifications const globalNotifyLevel = this.props.currentUser.notify_props ? this.props.currentUser.notify_props.desktop : 'all'; let globalNotifyLevelName; @@ -140,7 +138,7 @@ export default class ChannelNotificationsModal extends React.Component { type='radio' name='desktopNotificationLevel' checked={notifyActive[0]} - onChange={this.handleUpdateNotifyLevel.bind(this, 'default')} + onChange={this.handleUpdateDesktopNotifyLevel.bind(this, 'default')} /> <FormattedMessage id='channel_notifications.globalDefault' @@ -158,7 +156,7 @@ export default class ChannelNotificationsModal extends React.Component { type='radio' name='desktopNotificationLevel' checked={notifyActive[1]} - onChange={this.handleUpdateNotifyLevel.bind(this, 'all')} + onChange={this.handleUpdateDesktopNotifyLevel.bind(this, 'all')} /> <FormattedMessage id='channel_notifications.allActivity'/> </label> @@ -170,7 +168,7 @@ export default class ChannelNotificationsModal extends React.Component { type='radio' name='desktopNotificationLevel' checked={notifyActive[2]} - onChange={this.handleUpdateNotifyLevel.bind(this, 'mention')} + onChange={this.handleUpdateDesktopNotifyLevel.bind(this, 'mention')} /> <FormattedMessage id='channel_notifications.onlyMentions'/> </label> @@ -182,7 +180,7 @@ export default class ChannelNotificationsModal extends React.Component { type='radio' name='desktopNotificationLevel' checked={notifyActive[3]} - onChange={this.handleUpdateNotifyLevel.bind(this, 'none')} + onChange={this.handleUpdateDesktopNotifyLevel.bind(this, 'none')} /> <FormattedMessage id='channel_notifications.never'/> </label> @@ -208,7 +206,7 @@ export default class ChannelNotificationsModal extends React.Component { <SettingItemMax title={sendDesktop} inputs={inputs} - submit={this.handleSubmitNotifyLevel} + submit={this.handleSubmitDesktopNotifyLevel} server_error={serverError} updateSection={handleUpdateSection} extraInfo={extraInfo} @@ -254,18 +252,14 @@ export default class ChannelNotificationsModal extends React.Component { return; } + const options = {mark_unread: markUnreadLevel}; const data = { channel_id: channelId, - user_id: this.props.currentUser.id, - mark_unread: markUnreadLevel + user_id: this.props.currentUser.id }; - updateChannelNotifyProps(data, + updateChannelNotifyProps(data, options, () => { - // Yuck... - var member = ChannelStore.getMyMember(channelId); - member.notify_props.mark_unread = markUnreadLevel; - ChannelStore.storeMyChannelMember(member); this.updateSection(''); }, (err) => { @@ -375,8 +369,213 @@ export default class ChannelNotificationsModal extends React.Component { return content; } + handleSubmitPushNotificationLevel() { + const channelId = this.props.channel.id; + const notifyLevel = this.state.pushLevel; + const currentUserId = this.props.currentUser.id; + + if (this.props.channelMember.notify_props.push === notifyLevel) { + this.updateSection(''); + return; + } + + const options = {push: notifyLevel}; + const data = { + channel_id: channelId, + user_id: currentUserId + }; + + updateChannelNotifyProps(data, options, + () => { + this.updateSection(''); + }, + (err) => { + this.setState({serverError: err.message}); + } + ); + } + + handleUpdatePushNotificationLevel(pushLevel) { + this.setState({pushLevel}); + } + + createPushNotificationLevelSection(serverError) { + if (global.mm_config.SendPushNotifications === 'false') { + return null; + } + + // Get glabal user setting for notifications + const globalNotifyLevel = this.props.currentUser.notify_props ? this.props.currentUser.notify_props.push : 'all'; + let globalNotifyLevelName; + if (globalNotifyLevel === 'all') { + globalNotifyLevelName = ( + <FormattedMessage + id='channel_notifications.allActivity' + defaultMessage='For all activity' + /> + ); + } else if (globalNotifyLevel === 'mention') { + globalNotifyLevelName = ( + <FormattedMessage + id='channel_notifications.onlyMentions' + defaultMessage='Only for mentions' + /> + ); + } else { + globalNotifyLevelName = ( + <FormattedMessage + id='channel_notifications.never' + defaultMessage='Never' + /> + ); + } + + const sendPushNotifications = ( + <FormattedMessage + id='channel_notifications.push' + defaultMessage='Send mobile push notifications' + /> + ); + + const notificationLevel = this.state.pushLevel; + + let content; + if (this.state.activeSection === 'push') { + const notifyActive = [false, false, false, false]; + if (notificationLevel === 'default') { + notifyActive[0] = true; + } else if (notificationLevel === 'all') { + notifyActive[1] = true; + } else if (notificationLevel === 'mention') { + notifyActive[2] = true; + } else { + notifyActive[3] = true; + } + + const inputs = []; + + inputs.push( + <div key='channel-notification-level-radio'> + <div className='radio'> + <label> + <input + type='radio' + name='pushNotificationLevel' + checked={notifyActive[0]} + onChange={this.handleUpdatePushNotificationLevel.bind(this, 'default')} + /> + <FormattedMessage + id='channel_notifications.globalDefault' + defaultMessage='Global default ({notifyLevel})' + values={{ + notifyLevel: (globalNotifyLevelName) + }} + /> + </label> + <br/> + </div> + <div className='radio'> + <label> + <input + type='radio' + name='pushNotificationLevel' + checked={notifyActive[1]} + onChange={this.handleUpdatePushNotificationLevel.bind(this, 'all')} + /> + <FormattedMessage id='channel_notifications.allActivity'/> + </label> + <br/> + </div> + <div className='radio'> + <label> + <input + type='radio' + name='pushNotificationLevel' + checked={notifyActive[2]} + onChange={this.handleUpdatePushNotificationLevel.bind(this, 'mention')} + /> + <FormattedMessage id='channel_notifications.onlyMentions'/> + </label> + <br/> + </div> + <div className='radio'> + <label> + <input + type='radio' + name='pushNotificationLevel' + checked={notifyActive[3]} + onChange={this.handleUpdatePushNotificationLevel.bind(this, 'none')} + /> + <FormattedMessage id='channel_notifications.never'/> + </label> + </div> + </div> + ); + + const handleUpdateSection = function updateSection(e) { + this.updateSection(''); + e.preventDefault(); + }.bind(this); + + const extraInfo = ( + <span> + <FormattedMessage + id='channel_notifications.overridePush' + defaultMessage='Selecting an option other than "Global default" will override the global notification settings for mobile push notifications in account settings. Push notifications must be enabled by the System Admin.' + /> + </span> + ); + + content = ( + <SettingItemMax + title={sendPushNotifications} + inputs={inputs} + submit={this.handleSubmitPushNotificationLevel} + server_error={serverError} + updateSection={handleUpdateSection} + extraInfo={extraInfo} + /> + ); + } else { + let describe; + if (notificationLevel === 'default') { + describe = ( + <FormattedMessage + id='channel_notifications.globalDefault' + values={{ + notifyLevel: (globalNotifyLevelName) + }} + /> + ); + } else if (notificationLevel === 'mention') { + describe = (<FormattedMessage id='channel_notifications.onlyMentions'/>); + } else if (notificationLevel === 'all') { + describe = (<FormattedMessage id='channel_notifications.allActivity'/>); + } else { + describe = (<FormattedMessage id='channel_notifications.never'/>); + } + + content = ( + <SettingItemMin + title={sendPushNotifications} + describe={describe} + updateSection={() => { + this.updateSection('push'); + }} + /> + ); + } + + return ( + <div> + <div className='divider-light'/> + {content} + </div> + ); + } + render() { - var serverError = null; + let serverError = null; if (this.state.serverError) { serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>; } @@ -406,7 +605,8 @@ export default class ChannelNotificationsModal extends React.Component { > <br/> <div className='divider-dark first'/> - {this.createNotifyLevelSection(serverError)} + {this.createDesktopNotifyLevelSection(serverError)} + {this.createPushNotificationLevelSection(serverError)} <div className='divider-light'/> {this.createMarkUnreadLevelSection(serverError)} <div className='divider-dark'/> diff --git a/webapp/components/user_settings/email_notification_setting.jsx b/webapp/components/user_settings/email_notification_setting.jsx index a8319de29..457512507 100644 --- a/webapp/components/user_settings/email_notification_setting.jsx +++ b/webapp/components/user_settings/email_notification_setting.jsx @@ -13,10 +13,6 @@ import SettingItemMax from 'components/setting_item_max.jsx'; import {Preferences} from 'utils/constants.jsx'; -const INTERVAL_IMMEDIATE = 30; // "immediate" is a 30 second interval -const INTERVAL_FIFTEEN_MINUTES = 15 * 60; -const INTERVAL_HOUR = 60 * 60; - export default class EmailNotificationSetting extends React.Component { static propTypes = { activeSection: React.PropTypes.string.isRequired, @@ -36,7 +32,7 @@ export default class EmailNotificationSetting extends React.Component { this.collapse = this.collapse.bind(this); this.state = { - emailInterval: PreferenceStore.getInt(Preferences.CATEGORY_NOTIFICATIONS, Preferences.EMAIL_INTERVAL, INTERVAL_IMMEDIATE) + emailInterval: PreferenceStore.getInt(Preferences.CATEGORY_NOTIFICATIONS, Preferences.EMAIL_INTERVAL, Preferences.INTERVAL_IMMEDIATE) }; } @@ -66,7 +62,7 @@ export default class EmailNotificationSetting extends React.Component { if (this.props.enableEmail) { switch (this.state.emailInterval) { - case INTERVAL_IMMEDIATE: + case Preferences.INTERVAL_IMMEDIATE: description = ( <FormattedMessage id='user.settings.notifications.email.immediately' @@ -74,7 +70,7 @@ export default class EmailNotificationSetting extends React.Component { /> ); break; - case INTERVAL_HOUR: + case Preferences.INTERVAL_HOUR: description = ( <FormattedMessage id='user.settings.notifications.email.everyHour' @@ -119,13 +115,13 @@ export default class EmailNotificationSetting extends React.Component { <input type='radio' name='emailNotifications' - checked={this.props.enableEmail && this.state.emailInterval === INTERVAL_FIFTEEN_MINUTES} - onChange={this.handleChange.bind(this, 'true', INTERVAL_FIFTEEN_MINUTES)} + checked={this.props.enableEmail && this.state.emailInterval === Preferences.INTERVAL_FIFTEEN_MINUTES} + onChange={this.handleChange.bind(this, 'true', Preferences.INTERVAL_FIFTEEN_MINUTES)} /> <FormattedMessage id='user.settings.notifications.email.everyXMinutes' defaultMessage='Every {count} minutes' - values={{count: INTERVAL_FIFTEEN_MINUTES / 60}} + values={{count: Preferences.INTERVAL_FIFTEEN_MINUTES / 60}} /> </label> </div> @@ -134,8 +130,8 @@ export default class EmailNotificationSetting extends React.Component { <input type='radio' name='emailNotifications' - checked={this.props.enableEmail && this.state.emailInterval === INTERVAL_HOUR} - onChange={this.handleChange.bind(this, 'true', INTERVAL_HOUR)} + checked={this.props.enableEmail && this.state.emailInterval === Preferences.INTERVAL_HOUR} + onChange={this.handleChange.bind(this, 'true', Preferences.INTERVAL_HOUR)} /> <FormattedMessage id='user.settings.notifications.email.everyHour' @@ -170,8 +166,8 @@ export default class EmailNotificationSetting extends React.Component { <input type='radio' name='emailNotifications' - checked={this.props.enableEmail && this.state.emailInterval === INTERVAL_IMMEDIATE} - onChange={this.handleChange.bind(this, 'true', INTERVAL_IMMEDIATE)} + checked={this.props.enableEmail && this.state.emailInterval === Preferences.INTERVAL_IMMEDIATE} + onChange={this.handleChange.bind(this, 'true', Preferences.INTERVAL_IMMEDIATE)} /> <FormattedMessage id='user.settings.notifications.email.immediately' @@ -186,7 +182,7 @@ export default class EmailNotificationSetting extends React.Component { type='radio' name='emailNotifications' checked={!this.props.enableEmail} - onChange={this.handleChange.bind(this, 'false', INTERVAL_IMMEDIATE)} + onChange={this.handleChange.bind(this, 'false', Preferences.INTERVAL_IMMEDIATE)} /> <FormattedMessage id='user.settings.notifications.email.never' diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json index 86ab91c3c..8200c041a 100644 --- a/webapp/i18n/en.json +++ b/webapp/i18n/en.json @@ -1143,7 +1143,9 @@ "channel_notifications.never": "Never", "channel_notifications.onlyMentions": "Only for mentions", "channel_notifications.override": "Selecting an option other than \"Default\" will override the global notification settings. Desktop notifications are available on Firefox, Safari, and Chrome.", + "channel_notifications.overridePush": "Selecting an option other than \"Global default\" will override the global notification settings for mobile push notifications in account settings. Push notifications must be enabled by the System Admin.", "channel_notifications.preferences": "Notification Preferences for ", + "channel_notification.push": "Send mobile push notifications", "channel_notifications.sendDesktop": "Send desktop notifications", "channel_notifications.unreadInfo": "The channel name is bolded in the sidebar when there are unread messages. Selecting \"Only for mentions\" will bold the channel only when you are mentioned.", "channel_select.placeholder": "--- Select a channel ---", diff --git a/webapp/utils/constants.jsx b/webapp/utils/constants.jsx index 94fad3f35..fb256c60e 100644 --- a/webapp/utils/constants.jsx +++ b/webapp/utils/constants.jsx @@ -55,7 +55,10 @@ export const Preferences = { CATEGORY_FLAGGED_POST: 'flagged_post', CATEGORY_NOTIFICATIONS: 'notifications', CATEGORY_FAVORITE_CHANNEL: 'favorite_channel', - EMAIL_INTERVAL: 'email_interval' + EMAIL_INTERVAL: 'email_interval', + INTERVAL_IMMEDIATE: 30, // "immediate" is a 30 second interval + INTERVAL_FIFTEEN_MINUTES: 15 * 60, + INTERVAL_HOUR: 60 * 60 }; export const ActionTypes = keyMirror({ |