diff options
author | Joram Wilander <jwawilander@gmail.com> | 2016-08-29 09:52:59 -0400 |
---|---|---|
committer | Christopher Speller <crspeller@gmail.com> | 2016-08-29 09:52:59 -0400 |
commit | a76db5b84f661f1254da6d04af5100f858051bb4 (patch) | |
tree | b2b931c24b0b3a2fe622a1e2129186612fc82200 | |
parent | d252e61c662479155081aeaf34fe0c6e4c3705d1 (diff) | |
download | chat-a76db5b84f661f1254da6d04af5100f858051bb4.tar.gz chat-a76db5b84f661f1254da6d04af5100f858051bb4.tar.bz2 chat-a76db5b84f661f1254da6d04af5100f858051bb4.zip |
PLT-2074 Refactor desktop notification settings UI and add setting for duration (#3883)
* Refactor desktop notification settings UI and add setting for duration
* Update en.json
* Update desktop_notification_settings.jsx
-rw-r--r-- | webapp/actions/user_actions.jsx | 2 | ||||
-rw-r--r-- | webapp/components/setting_item_min.jsx | 2 | ||||
-rw-r--r-- | webapp/components/user_settings/desktop_notification_settings.jsx | 454 | ||||
-rw-r--r-- | webapp/components/user_settings/user_settings_notifications.jsx | 295 | ||||
-rw-r--r-- | webapp/i18n/en.json | 22 | ||||
-rw-r--r-- | webapp/stores/notification_store.jsx | 17 | ||||
-rw-r--r-- | webapp/utils/constants.jsx | 3 | ||||
-rw-r--r-- | webapp/utils/utils.jsx | 18 |
8 files changed, 542 insertions, 271 deletions
diff --git a/webapp/actions/user_actions.jsx b/webapp/actions/user_actions.jsx index ede1ebb7a..2d5fd805c 100644 --- a/webapp/actions/user_actions.jsx +++ b/webapp/actions/user_actions.jsx @@ -81,4 +81,4 @@ function onThemeSaved(teamId, theme, onSuccess) { }); onSuccess(); -}
\ No newline at end of file +} diff --git a/webapp/components/setting_item_min.jsx b/webapp/components/setting_item_min.jsx index 1c5fd40f3..edcc81693 100644 --- a/webapp/components/setting_item_min.jsx +++ b/webapp/components/setting_item_min.jsx @@ -33,7 +33,7 @@ export default class SettingItemMin extends React.Component { > <li className='col-sm-9 section-title'>{this.props.title}</li> {editButton} - <li className='col-sm-10 section-describe'>{this.props.describe}</li> + <li className='col-sm-12 section-describe'>{this.props.describe}</li> </ul> ); } diff --git a/webapp/components/user_settings/desktop_notification_settings.jsx b/webapp/components/user_settings/desktop_notification_settings.jsx new file mode 100644 index 000000000..e5376c7ee --- /dev/null +++ b/webapp/components/user_settings/desktop_notification_settings.jsx @@ -0,0 +1,454 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import SettingItemMin from 'components/setting_item_min.jsx'; +import SettingItemMax from 'components/setting_item_max.jsx'; + +import * as Utils from 'utils/utils.jsx'; +import * as UserAgent from 'utils/user_agent.jsx'; + +import React from 'react'; +import {FormattedMessage} from 'react-intl'; + +export default class DesktopNotificationSettings extends React.Component { + constructor(props) { + super(props); + + this.buildMaximizedSetting = this.buildMaximizedSetting.bind(this); + this.buildMinimizedSetting = this.buildMinimizedSetting.bind(this); + + this.state = {}; + } + + buildMaximizedSetting() { + let inputs = []; + let extraInfo = null; + + const activityRadio = [false, false, false]; + if (this.props.activity === 'mention') { + activityRadio[1] = true; + } else if (this.props.activity === 'none') { + activityRadio[2] = true; + } else { + activityRadio[0] = true; + } + + let soundSection; + let durationSection; + if (this.props.activity !== 'none') { + const soundRadio = [false, false]; + if (this.props.sound === 'false') { + soundRadio[1] = true; + } else { + soundRadio[0] = true; + } + + if (UserAgent.isFirefox()) { + soundSection = ( + <div> + <hr/> + <label> + <FormattedMessage + id='user.settings.notifications.desktop.sound' + defaultMessage='Notification sound' + /> + </label> + <br/> + <FormattedMessage + id='user.settings.notifications.soundConfig' + defaultMessage='Please configure notification sounds in your browser settings' + /> + </div> + ); + } else { + soundSection = ( + <div> + <hr/> + <label> + <FormattedMessage + id='user.settings.notifications.desktop.sound' + defaultMessage='Notification sound' + /> + </label> + <br/> + <div className='radio'> + <label> + <input + type='radio' + name='notificationSounds' + checked={soundRadio[0]} + onChange={() => this.props.setParentState('desktopSound', 'true')} + /> + <FormattedMessage + id='user.settings.notifications.on' + defaultMessage='On' + /> + </label> + <br/> + </div> + <div className='radio'> + <label> + <input + type='radio' + name='notificationSounds' + checked={soundRadio[1]} + onChange={() => this.props.setParentState('desktopSound', 'false')} + /> + <FormattedMessage + id='user.settings.notifications.off' + defaultMessage='Off' + /> + </label> + <br/> + </div> + <br/> + <span> + <FormattedMessage + id='user.settings.notifications.sounds_info' + defaultMessage='Notification sounds are available on IE11, Edge, Safari and Chrome.' + /> + </span> + </div> + ); + } + + const durationRadio = [false, false, false, false]; + if (this.props.duration === '3') { + durationRadio[0] = true; + } else if (this.props.duration === '10') { + durationRadio[2] = true; + } else if (this.props.duration === '0') { + durationRadio[3] = true; + } else { + durationRadio[1] = true; + } + + durationSection = ( + <div> + <hr/> + <label> + <FormattedMessage + id='user.settings.notifications.desktop.duration' + defaultMessage='Notification duration' + /> + </label> + <br/> + <div className='radio'> + <label> + <input + type='radio' + name='desktopDuration' + checked={durationRadio[0]} + onChange={() => this.props.setParentState('desktopDuration', '3')} + /> + <FormattedMessage + id='user.settings.notifications.desktop.seconds' + defaultMessage='{seconds} seconds' + values={{ + seconds: '3' + }} + /> + </label> + <br/> + </div> + <div className='radio'> + <label> + <input + type='radio' + name='desktopDuration' + checked={durationRadio[1]} + onChange={() => this.props.setParentState('desktopDuration', '5')} + /> + <FormattedMessage + id='user.settings.notifications.desktop.seconds' + defaultMessage='{seconds} seconds' + values={{ + seconds: '5' + }} + /> + </label> + <br/> + </div> + <div className='radio'> + <label> + <input + type='radio' + name='desktopDuration' + checked={durationRadio[2]} + onChange={() => this.props.setParentState('desktopDuration', '10')} + /> + <FormattedMessage + id='user.settings.notifications.desktop.seconds' + defaultMessage='{seconds} seconds' + values={{ + seconds: '10' + }} + /> + </label> + </div> + <div className='radio'> + <label> + <input + type='radio' + name='desktopDuration' + checked={durationRadio[3]} + onChange={() => this.props.setParentState('desktopDuration', '0')} + /> + <FormattedMessage + id='user.settings.notifications.desktop.unlimited' + defaultMessage='Unlimited' + /> + </label> + </div> + </div> + ); + + extraInfo = ( + <span> + <FormattedMessage + id='user.settings.notifications.desktop.durationInfo' + defaultMessage='Sets how long desktop notifications will remain on screen.' + /> + </span> + ); + } + + inputs.push( + <div key='userNotificationLevelOption'> + <label> + <FormattedMessage + id='user.settings.notifications.desktop' + defaultMessage='Send desktop notifications' + /> + </label> + <br/> + <div className='radio'> + <label> + <input + type='radio' + name='desktopNotificationLevel' + checked={activityRadio[0]} + onChange={() => this.props.setParentState('desktopActivity', 'all')} + /> + <FormattedMessage + id='user.settings.notifications.allActivity' + defaultMessage='For all activity' + /> + </label> + <br/> + </div> + <div className='radio'> + <label> + <input + type='radio' + name='desktopNotificationLevel' + checked={activityRadio[1]} + onChange={() => this.props.setParentState('desktopActivity', 'mention')} + /> + <FormattedMessage + id='user.settings.notifications.onlyMentions' + defaultMessage='Only for mentions and direct messages' + /> + </label> + <br/> + </div> + <div className='radio'> + <label> + <input + type='radio' + name='desktopNotificationLevel' + checked={activityRadio[2]} + onChange={() => this.props.setParentState('desktopActivity', 'none')} + /> + <FormattedMessage + id='user.settings.notifications.never' + defaultMessage='Never' + /> + </label> + </div> + <br/> + <span> + <FormattedMessage + id='user.settings.notifications.info' + defaultMessage='Desktop notifications are available on Firefox, Safari, and Chrome.' + /> + </span> + {soundSection} + {durationSection} + </div> + ); + + return ( + <SettingItemMax + title={Utils.localizeMessage('user.settings.notifications.desktop.title', 'Desktop notifications')} + extraInfo={extraInfo} + inputs={inputs} + submit={this.props.submit} + server_error={this.props.error} + updateSection={this.props.cancel} + /> + ); + } + + buildMinimizedSetting() { + let describe = ''; + if (this.props.activity === 'mention') { + if (UserAgent.isFirefox()) { + if (this.props.duration === '0') { + describe = ( + <FormattedMessage + id='user.settings.notifications.desktop.mentionsFirefoxForever' + defaultMessage='For mentions and direct messages, shown indefinitely' + /> + ); + } else { + describe = ( + <FormattedMessage + id='user.settings.notifications.desktop.mentionsFirefoxTimed' + defaultMessage='For mentions and direct messages, shown for {seconds} seconds' + values={{ + seconds: this.props.duration + }} + /> + ); + } + } else if (this.props.sound === 'false') { + if (this.props.duration === '0') { + describe = ( + <FormattedMessage + id='user.settings.notifications.desktop.mentionsNoSoundForever' + defaultMessage='For mentions and direct messages, without sound, shown indefinitely' + /> + ); + } else { + describe = ( + <FormattedMessage + id='user.settings.notifications.desktop.mentionsNoSoundTimed' + defaultMessage='For mentions and direct messages, without sound, shown for {seconds} seconds' + values={{ + seconds: this.props.duration + }} + /> + ); + } + } else { + if (this.props.duration === '0') { //eslint-disable-line no-lonely-if + describe = ( + <FormattedMessage + id='user.settings.notifications.desktop.mentionsSoundForever' + defaultMessage='For mentions and direct messages, with sound, shown indefinitely' + /> + ); + } else { + describe = ( + <FormattedMessage + id='user.settings.notifications.desktop.mentionsSoundTimed' + defaultMessage='For mentions and direct messages, with sound, shown for {seconds} seconds' + values={{ + seconds: this.props.duration + }} + /> + ); + } + } + } else if (this.props.activity === 'none') { + describe = ( + <FormattedMessage + id='user.settings.notifications.off' + defaultMessage='Off' + /> + ); + } else { + if (UserAgent.isFirefox()) { //eslint-disable-line no-lonely-if + if (this.props.duration === '0') { + describe = ( + <FormattedMessage + id='user.settings.notifications.desktop.allFirefoxForever' + defaultMessage='For all activity, shown indefinitely' + /> + ); + } else { + describe = ( + <FormattedMessage + id='user.settings.notifications.desktop.allFirefoxTimed' + defaultMessage='For all activity, shown for {seconds} seconds' + values={{ + seconds: this.props.duration + }} + /> + ); + } + } else if (this.props.sound === 'false') { + if (this.props.duration === '0') { + describe = ( + <FormattedMessage + id='user.settings.notifications.desktop.allNoSoundForever' + defaultMessage='For all activity, without sound, shown indefinitely' + /> + ); + } else { + describe = ( + <FormattedMessage + id='user.settings.notifications.desktop.allNoSoundTimed' + defaultMessage='For all activity, without sound, shown for {seconds} seconds' + values={{ + seconds: this.props.duration + }} + /> + ); + } + } else { + if (this.props.duration === '0') { //eslint-disable-line no-lonely-if + describe = ( + <FormattedMessage + id='user.settings.notifications.desktop.allSoundForever' + defaultMessage='For all activity, with sound, shown indefinitely' + /> + ); + } else { + describe = ( + <FormattedMessage + id='user.settings.notifications.desktop.allSoundTimed' + defaultMessage='For all activity, with sound, shown for {seconds} seconds' + values={{ + seconds: this.props.duration + }} + /> + ); + } + } + } + + const handleUpdateDesktopSection = function updateDesktopSection() { + this.props.updateSection('desktop'); + }.bind(this); + + return ( + <SettingItemMin + title={Utils.localizeMessage('user.settings.notifications.desktop.title', 'Desktop notifications')} + describe={describe} + updateSection={handleUpdateDesktopSection} + /> + ); + } + + render() { + if (this.props.active) { + return this.buildMaximizedSetting(); + } + + return this.buildMinimizedSetting(); + } +} + +DesktopNotificationSettings.propTypes = { + activity: React.PropTypes.string.isRequired, + sound: React.PropTypes.string.isRequired, + duration: React.PropTypes.string.isRequired, + updateSection: React.PropTypes.func, + setParentState: React.PropTypes.func, + submit: React.PropTypes.func, + cancel: React.PropTypes.func, + error: React.PropTypes.string, + active: React.PropTypes.bool +}; diff --git a/webapp/components/user_settings/user_settings_notifications.jsx b/webapp/components/user_settings/user_settings_notifications.jsx index b3953ec17..a18cdf041 100644 --- a/webapp/components/user_settings/user_settings_notifications.jsx +++ b/webapp/components/user_settings/user_settings_notifications.jsx @@ -4,12 +4,12 @@ import $ from 'jquery'; import SettingItemMin from 'components/setting_item_min.jsx'; import SettingItemMax from 'components/setting_item_max.jsx'; +import DesktopNotificationSettings from './desktop_notification_settings.jsx'; import UserStore from 'stores/user_store.jsx'; import Client from 'client/web_client.jsx'; import * as AsyncClient from 'utils/async_client.jsx'; -import * as UserAgent from 'utils/user_agent.jsx'; import * as Utils from 'utils/utils.jsx'; import Constants from 'utils/constants.jsx'; @@ -18,21 +18,24 @@ import {FormattedMessage} from 'react-intl'; function getNotificationsStateFromStores() { const user = UserStore.getCurrentUser(); - const soundNeeded = !UserAgent.isFirefox(); - let sound = 'true'; let desktop = 'default'; + let sound = 'true'; + let desktopDuration = '5'; let comments = 'never'; let enableEmail = 'true'; let pushActivity = 'mention'; let pushStatus = Constants.UserStatuses.ONLINE; if (user.notify_props) { + if (user.notify_props.desktop) { + desktop = user.notify_props.desktop; + } if (user.notify_props.desktop_sound) { sound = user.notify_props.desktop_sound; } - if (user.notify_props.desktop) { - desktop = user.notify_props.desktop; + if (user.notify_props.desktop_duration) { + desktopDuration = user.notify_props.desktop_duration; } if (user.notify_props.comments) { comments = user.notify_props.comments; @@ -85,12 +88,12 @@ function getNotificationsStateFromStores() { } return { - notifyLevel: desktop, + desktopActivity: desktop, + desktopDuration, enableEmail, pushActivity, pushStatus, - soundNeeded, - enableSound: sound, + desktopSound: sound, usernameKey, mentionKey, customKeys, @@ -110,16 +113,15 @@ export default class NotificationsTab extends React.Component { this.handleSubmit = this.handleSubmit.bind(this); this.handleCancel = this.handleCancel.bind(this); this.updateSection = this.updateSection.bind(this); - this.updateState = this.updateState.bind(this); + this.setStateValue = this.setStateValue.bind(this); this.onListenerChange = this.onListenerChange.bind(this); - this.handleNotifyRadio = this.handleNotifyRadio.bind(this); this.handleEmailRadio = this.handleEmailRadio.bind(this); - this.handleSoundRadio = this.handleSoundRadio.bind(this); this.updateUsernameKey = this.updateUsernameKey.bind(this); this.updateMentionKey = this.updateMentionKey.bind(this); this.updateFirstNameKey = this.updateFirstNameKey.bind(this); this.updateChannelKey = this.updateChannelKey.bind(this); this.updateCustomMentionKeys = this.updateCustomMentionKeys.bind(this); + this.updateState = this.updateState.bind(this); this.onCustomChange = this.onCustomChange.bind(this); this.createPushNotificationSection = this.createPushNotificationSection.bind(this); @@ -130,8 +132,9 @@ export default class NotificationsTab extends React.Component { var data = {}; data.user_id = this.props.user.id; data.email = this.state.enableEmail; - data.desktop_sound = this.state.enableSound; - data.desktop = this.state.notifyLevel; + data.desktop_sound = this.state.desktopSound; + data.desktop = this.state.desktopActivity; + data.desktop_duration = this.state.desktopDuration; data.push = this.state.pushActivity; data.push_status = this.state.pushStatus; data.comments = this.state.notifyCommentsLevel; @@ -166,12 +169,18 @@ export default class NotificationsTab extends React.Component { } handleCancel(e) { + e.preventDefault(); this.updateState(); this.props.updateSection(''); - e.preventDefault(); $('.settings-modal .modal-body').scrollTop(0).perfectScrollbar('update'); } + setStateValue(key, value) { + const data = {}; + data[key] = value; + this.setState(data); + } + updateSection(section) { this.updateState(); this.props.updateSection(section); @@ -196,11 +205,6 @@ export default class NotificationsTab extends React.Component { this.updateState(); } - handleNotifyRadio(notifyLevel) { - this.setState({notifyLevel}); - this.refs.wrapper.focus(); - } - handleNotifyCommentsRadio(notifyCommentsLevel) { this.setState({notifyCommentsLevel}); this.refs.wrapper.focus(); @@ -221,11 +225,6 @@ export default class NotificationsTab extends React.Component { this.refs.wrapper.focus(); } - handleSoundRadio(enableSound) { - this.setState({enableSound}); - this.refs.wrapper.focus(); - } - updateUsernameKey(val) { this.setState({usernameKey: val}); } @@ -261,7 +260,7 @@ export default class NotificationsTab extends React.Component { } createPushNotificationSection() { - let handleUpdateDesktopSection; + let handleUpdatePushSection; if (this.props.activeSection === 'push') { let inputs = []; let extraInfo = null; @@ -495,7 +494,7 @@ export default class NotificationsTab extends React.Component { } } - handleUpdateDesktopSection = function updateDesktopSection() { + handleUpdatePushSection = function updateDesktopSection() { this.props.updateSection('push'); }.bind(this); @@ -503,240 +502,14 @@ export default class NotificationsTab extends React.Component { <SettingItemMin title={Utils.localizeMessage('user.settings.notifications.push', 'Send mobile push notifications')} describe={describe} - updateSection={handleUpdateDesktopSection} + updateSection={handleUpdatePushSection} /> ); } render() { const serverError = this.state.serverError; - - var user = this.props.user; - - var desktopSection; - var handleUpdateDesktopSection; - if (this.props.activeSection === 'desktop') { - var notifyActive = [false, false, false]; - if (this.state.notifyLevel === 'mention') { - notifyActive[1] = true; - } else if (this.state.notifyLevel === 'none') { - notifyActive[2] = true; - } else { - notifyActive[0] = true; - } - - let inputs = []; - - inputs.push( - <div key='userNotificationLevelOption'> - <div className='radio'> - <label> - <input - type='radio' - name='desktopNotificationLevel' - checked={notifyActive[0]} - onChange={this.handleNotifyRadio.bind(this, 'all')} - /> - <FormattedMessage - id='user.settings.notifications.allActivity' - defaultMessage='For all activity' - /> - </label> - <br/> - </div> - <div className='radio'> - <label> - <input - type='radio' - name='desktopNotificationLevel' - checked={notifyActive[1]} - onChange={this.handleNotifyRadio.bind(this, 'mention')} - /> - <FormattedMessage - id='user.settings.notifications.onlyMentions' - defaultMessage='Only for mentions and direct messages' - /> - </label> - <br/> - </div> - <div className='radio'> - <label> - <input - type='radio' - name='desktopNotificationLevel' - checked={notifyActive[2]} - onChange={this.handleNotifyRadio.bind(this, 'none')} - /> - <FormattedMessage - id='user.settings.notifications.never' - defaultMessage='Never' - /> - </label> - </div> - </div> - ); - - const extraInfo = ( - <span> - <FormattedMessage - id='user.settings.notifications.info' - defaultMessage='Desktop notifications are available on Firefox, Safari, Chrome, Internet Explorer, and Edge.' - /> - </span> - ); - - desktopSection = ( - <SettingItemMax - title={Utils.localizeMessage('user.settings.notifications.desktop', 'Send desktop notifications')} - extraInfo={extraInfo} - inputs={inputs} - submit={this.handleSubmit} - server_error={serverError} - updateSection={this.handleCancel} - /> - ); - } else { - let describe = ''; - if (this.state.notifyLevel === 'mention') { - describe = ( - <FormattedMessage - id='user.settings.notifications.onlyMentions' - defaultMessage='Only for mentions and direct messages' - /> - ); - } else if (this.state.notifyLevel === 'none') { - describe = ( - <FormattedMessage - id='user.settings.notifications.never' - defaultMessage='Never' - /> - ); - } else { - describe = ( - <FormattedMessage - id='user.settings.notification.allActivity' - defaultMessage='For all activity' - /> - ); - } - - handleUpdateDesktopSection = function updateDesktopSection() { - this.props.updateSection('desktop'); - }.bind(this); - - desktopSection = ( - <SettingItemMin - title={Utils.localizeMessage('user.settings.notifications.desktop', 'Send desktop notifications')} - describe={describe} - updateSection={handleUpdateDesktopSection} - /> - ); - } - - var soundSection; - var handleUpdateSoundSection; - if (this.props.activeSection === 'sound' && this.state.soundNeeded) { - var soundActive = [false, false]; - if (this.state.enableSound === 'false') { - soundActive[1] = true; - } else { - soundActive[0] = true; - } - - let inputs = []; - - inputs.push( - <div key='userNotificationSoundOptions'> - <div className='radio'> - <label> - <input - type='radio' - name='notificationSounds' - checked={soundActive[0]} - onChange={this.handleSoundRadio.bind(this, 'true')} - /> - <FormattedMessage - id='user.settings.notifications.on' - defaultMessage='On' - /> - </label> - <br/> - </div> - <div className='radio'> - <label> - <input - type='radio' - name='notificationSounds' - checked={soundActive[1]} - onChange={this.handleSoundRadio.bind(this, 'false')} - /> - <FormattedMessage - id='user.settings.notifications.off' - defaultMessage='Off' - /> - </label> - <br/> - </div> - </div> - ); - - const extraInfo = ( - <span> - <FormattedMessage - id='user.settings.notifications.sounds_info' - defaultMessage='Desktop notifications sounds are available on Firefox, Safari, Chrome, Internet Explorer, and Edge.' - /> - </span> - ); - - soundSection = ( - <SettingItemMax - title={Utils.localizeMessage('user.settings.notifications.desktopSounds', 'Desktop notification sounds')} - extraInfo={extraInfo} - inputs={inputs} - submit={this.handleSubmit} - server_error={serverError} - updateSection={this.handleCancel} - /> - ); - } else { - let describe = ''; - if (!this.state.soundNeeded) { - describe = ( - <FormattedMessage - id='user.settings.notifications.soundConfig' - defaultMessage='Please configure notification sounds in your browser settings' - /> - ); - } else if (this.state.enableSound === 'false') { - describe = ( - <FormattedMessage - id='user.settings.notifications.off' - defaultMessage='Off' - /> - ); - } else { - describe = ( - <FormattedMessage - id='user.settings.notifications.on' - defaultMessage='On' - /> - ); - } - - handleUpdateSoundSection = function updateSoundSection() { - this.props.updateSection('sound'); - }.bind(this); - - soundSection = ( - <SettingItemMin - title={Utils.localizeMessage('user.settings.notifications.desktopSounds', 'Desktop notification sounds')} - describe={describe} - updateSection={handleUpdateSoundSection} - disableOpen={!this.state.soundNeeded} - /> - ); - } + const user = this.props.user; var keysSection; var handleUpdateKeysSection; @@ -1089,9 +862,17 @@ export default class NotificationsTab extends React.Component { /> </h3> <div className='divider-dark first'/> - {desktopSection} - <div className='divider-light'/> - {soundSection} + <DesktopNotificationSettings + activity={this.state.desktopActivity} + sound={this.state.desktopSound} + duration={this.state.desktopDuration} + updateSection={this.updateSection} + setParentState={this.setStateValue} + submit={this.handleSubmit} + cancel={this.handleCancel} + error={this.state.serverError} + active={this.props.activeSection === 'desktop'} + /> <div className='divider-light'/> <EmailNotificationSetting activeSection={this.props.activeSection} diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json index 71a903b5b..1190462b0 100644 --- a/webapp/i18n/en.json +++ b/webapp/i18n/en.json @@ -1865,6 +1865,24 @@ "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.desktop.mentionsFirefoxForever": "For mentions and direct messages, shown indefinitely", + "user.settings.notifications.desktop.mentionsFirefoxTimed": "For mentions and direct messages, shown for {seconds} seconds", + "user.settings.notifications.desktop.mentionsNoSoundForever": "For mentions and direct messages, without sound, shown indefinitely", + "user.settings.notifications.desktop.mentionsNoSoundTimed": "For mentions and direct messages, without sound, shown for {seconds} seconds", + "user.settings.notifications.desktop.mentionsSoundForever": "For mentions and direct messages, with sound, shown indefinitely", + "user.settings.notifications.desktop.mentionsSoundTimed": "For mentions and direct messages, with sound, shown for {seconds} seconds", + "user.settings.notifications.desktop.allFirefoxForever": "For all activity, shown indefinitely", + "user.settings.notifications.desktop.allFirefoxTimed": "For all activity, shown for {seconds} seconds", + "user.settings.notifications.desktop.allNoSoundForever": "For all activity, without sound, shown indefinitely", + "user.settings.notifications.desktop.allNoSoundTimed": "For all activity, without sound, shown for {seconds} seconds", + "user.settings.notifications.desktop.allSoundForever": "For all activity, with sound, shown indefinitely", + "user.settings.notifications.desktop.allSoundTimed": "For all activity, with sound, shown for {seconds} seconds", + "user.settings.notifications.desktop.title": "Desktop notifications", + "user.settings.notifications.desktop.unlimited": "Unlimited", + "user.settings.notifications.desktop.seconds": "{seconds} seconds", + "user.settings.notifications.desktop.durationInfo": "Sets how long desktop notifications will remain on screen.", + "user.settings.notifications.desktop.duration": "Notification duration", + "user.settings.notifications.desktop.sound": "Notification sound", "user.settings.notifications.desktopSounds": "Desktop notification sounds", "user.settings.notifications.emailBatchingInfo": "Notifications are combined into a single email and sent at the maximum frequency selected here.", "user.settings.notifications.emailInfo": "Email notifications that are sent for mentions and direct messages when you are offline or away from {siteName} for more than 5 minutes.", @@ -1873,7 +1891,7 @@ "user.settings.notifications.everyXMinutes": "Every {count, plural, one {minute} other {{count, number} minutes}}", "user.settings.notifications.header": "Notifications", "user.settings.notifications.immediately": "Immediately", - "user.settings.notifications.info": "Desktop notifications are available on Firefox, Safari, Chrome, Internet Explorer, and Edge.", + "user.settings.notifications.info": "Desktop notifications are available on Firefox, Safari, and Chrome.", "user.settings.notifications.never": "Never", "user.settings.notifications.noWords": "No words configured", "user.settings.notifications.off": "Off", @@ -1884,7 +1902,7 @@ "user.settings.notifications.sensitiveUsername": "Your non-case sensitive username \"{username}\"", "user.settings.notifications.sensitiveWords": "Other non-case sensitive words, separated by commas:", "user.settings.notifications.soundConfig": "Please configure notification sounds in your browser settings", - "user.settings.notifications.sounds_info": "Desktop notifications sounds are available on Firefox, Safari, Chrome, Internet Explorer, and Edge.", + "user.settings.notifications.sounds_info": "Notification sounds are available on IE11, Edge, Safari and Chrome.", "user.settings.notifications.teamWide": "Team-wide mentions \"@all\"", "user.settings.notifications.title": "Notification Settings", "user.settings.notifications.usernameMention": "Your username mentioned \"@{username}\"", diff --git a/webapp/stores/notification_store.jsx b/webapp/stores/notification_store.jsx index 507954a10..c5122dd7a 100644 --- a/webapp/stores/notification_store.jsx +++ b/webapp/stores/notification_store.jsx @@ -79,17 +79,26 @@ class NotificationStoreClass extends EventEmitter { notifyText = notifyText.substring(0, 49) + '...'; } + let body = ''; if (notifyText.length === 0) { if (msgProps.image) { - Utils.notifyMe(title, username + Utils.localizeMessage('channel_loader.uploadedImage', ' uploaded an image'), channel, teamId); + body = username + Utils.localizeMessage('channel_loader.uploadedImage', ' uploaded an image'); } else if (msgProps.otherFile) { - Utils.notifyMe(title, username + Utils.localizeMessage('channel_loader.uploadedFile', ' uploaded a file'), channel, teamId); + body = Utils.localizeMessage('channel_loader.uploadedFile', ' uploaded a file'); } else { - Utils.notifyMe(title, username + Utils.localizeMessage('channel_loader.something', ' did something new'), channel, teamId); + body = username + Utils.localizeMessage('channel_loader.something', ' did something new'); } } else { - Utils.notifyMe(title, username + Utils.localizeMessage('channel_loader.wrote', ' wrote: ') + notifyText, channel, teamId); + body = username + Utils.localizeMessage('channel_loader.wrote', ' wrote: ') + notifyText; } + + let duration = Constants.DEFAULT_NOTIFICATION_DURATION; + if (user.notify_props && user.notify_props.desktop_duration) { + duration = parseInt(user.notify_props.desktop_duration, 10) * 1000; + } + + Utils.notifyMe(title, body, channel, teamId, duration); + if (!user.notify_props || user.notify_props.desktop_sound === 'true') { Utils.ding(); } diff --git a/webapp/utils/constants.jsx b/webapp/utils/constants.jsx index 60cc82ff6..1ec20d3e8 100644 --- a/webapp/utils/constants.jsx +++ b/webapp/utils/constants.jsx @@ -809,7 +809,8 @@ export const Constants = { PERMISSIONS_SYSTEM_ADMIN: 'system_admin', MENTION_MEMBERS: 'mention.members', MENTION_NONMEMBERS: 'mention.nonmembers', - MENTION_SPECIAL: 'mention.special' + MENTION_SPECIAL: 'mention.special', + DEFAULT_NOTIFICATION_DURATION: 5000 }; export default Constants; diff --git a/webapp/utils/utils.jsx b/webapp/utils/utils.jsx index 3059ce529..2780196db 100644 --- a/webapp/utils/utils.jsx +++ b/webapp/utils/utils.jsx @@ -86,18 +86,23 @@ export function getCookie(name) { var requestedNotificationPermission = false; -export function notifyMe(title, body, channel, teamId) { +export function notifyMe(title, body, channel, teamId, duration) { if (!('Notification' in window)) { return; } + let notificationDuration = Constants.DEFAULT_NOTIFICATION_DURATION; + if (duration != null) { + notificationDuration = duration; + } + if (Notification.permission === 'granted' || (Notification.permission === 'default' && !requestedNotificationPermission)) { requestedNotificationPermission = true; Notification.requestPermission((permission) => { if (permission === 'granted') { try { - var notification = new Notification(title, {body, tag: body, icon: icon50}); + var notification = new Notification(title, {body, tag: body, icon: icon50, requireInteraction: notificationDuration === 0}); notification.onclick = () => { window.focus(); if (channel) { @@ -108,9 +113,12 @@ export function notifyMe(title, body, channel, teamId) { browserHistory.push(TeamStore.getCurrentTeamUrl() + '/channels/town-square'); } }; - setTimeout(() => { - notification.close(); - }, 5000); + + if (notificationDuration > 0) { + setTimeout(() => { + notification.close(); + }, notificationDuration); + } } catch (e) { console.error(e); //eslint-disable-line no-console } |