summaryrefslogtreecommitdiffstats
path: root/webapp
diff options
context:
space:
mode:
authorenahum <nahumhbl@gmail.com>2017-02-27 17:55:12 -0300
committerGitHub <noreply@github.com>2017-02-27 17:55:12 -0300
commitf07571d79de1c00529136cd74c075ddfc4784b41 (patch)
treefe67b9879fe6e09d65bf36260b77185e7f2c6704 /webapp
parent48f97a5a2a0754bfc0e639db7cce03943e990e32 (diff)
downloadchat-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.jsx8
-rw-r--r--webapp/components/channel_notifications_modal.jsx262
-rw-r--r--webapp/components/user_settings/email_notification_setting.jsx26
-rw-r--r--webapp/i18n/en.json2
-rw-r--r--webapp/utils/constants.jsx5
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({