diff --git a/src/components/views/dialogs/UserSettingsDialog.js b/src/components/views/dialogs/UserSettingsDialog.js index e893f96a5f..adcfa751c2 100644 --- a/src/components/views/dialogs/UserSettingsDialog.js +++ b/src/components/views/dialogs/UserSettingsDialog.js @@ -23,6 +23,7 @@ import GeneralSettingsTab from "../settings/tabs/GeneralSettingsTab"; import dis from '../../../dispatcher'; import SettingsStore from "../../../settings/SettingsStore"; import LabsSettingsTab from "../settings/tabs/LabsSettingsTab"; +import NotificationSettingsTab from "../settings/tabs/NotificationSettingsTab"; // TODO: Ditch this whole component export class TempTab extends React.Component { @@ -56,7 +57,7 @@ export default class UserSettingsDialog extends React.Component { tabs.push(new Tab( _td("Notifications"), "mx_UserSettingsDialog_bellIcon", -
Notifications Test
, + , )); tabs.push(new Tab( _td("Preferences"), diff --git a/src/components/views/elements/LabelledToggleSwitch.js b/src/components/views/elements/LabelledToggleSwitch.js new file mode 100644 index 0000000000..3d3025ad06 --- /dev/null +++ b/src/components/views/elements/LabelledToggleSwitch.js @@ -0,0 +1,42 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from 'react'; +import PropTypes from "prop-types"; +import ToggleSwitch from "./ToggleSwitch"; + +export default class LabelledToggleSwitch extends React.Component { + static propTypes = { + // The value for the toggle switch + value: PropTypes.bool.isRequired, + + // The function to call when the value changes + onChange: PropTypes.func.isRequired, + + // The translated label for the switch + label: PropTypes.string.isRequired, + }; + + render() { + // This is a minimal version of a SettingsFlag + return ( +
+ {this.props.label} + +
+ ); + } +} diff --git a/src/components/views/settings/Notifications.js b/src/components/views/settings/Notifications.js index 40c43e6b2e..c502ef6bc6 100644 --- a/src/components/views/settings/Notifications.js +++ b/src/components/views/settings/Notifications.js @@ -28,6 +28,8 @@ import { PushRuleVectorState, ContentRules, } from '../../../notifications'; +import * as SdkConfig from "../../../SdkConfig"; +import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; // TODO: this "view" component still has far too much application logic in it, // which should be factored out to other files. @@ -70,19 +72,6 @@ module.exports = React.createClass({ ERROR: "ERROR", // There was an error }, - propTypes: { - // The array of threepids from the JS SDK (required for email notifications) - threepids: React.PropTypes.array.isRequired, - // The brand string set when creating an email pusher - brand: React.PropTypes.string, - }, - - getDefaultProps: function() { - return { - threepids: [], - }; - }, - getInitialState: function() { return { phase: this.phases.LOADING, @@ -94,6 +83,7 @@ module.exports = React.createClass({ }, externalPushRules: [], // Push rules (except content rule) that have been defined outside Vector UI externalContentRules: [], // Keyword push rules that have been defined outside Vector UI + threepids: [], // used for email notifications }; }, @@ -101,42 +91,42 @@ module.exports = React.createClass({ this._refreshFromServer(); }, - onEnableNotificationsChange: function(event) { + onEnableNotificationsChange: function(checked) { const self = this; this.setState({ phase: this.phases.LOADING, }); - MatrixClientPeg.get().setPushRuleEnabled('global', self.state.masterPushRule.kind, self.state.masterPushRule.rule_id, !event.target.checked).done(function() { + MatrixClientPeg.get().setPushRuleEnabled('global', self.state.masterPushRule.kind, self.state.masterPushRule.rule_id, !checked).done(function() { self._refreshFromServer(); }); }, - onEnableDesktopNotificationsChange: function(event) { + onEnableDesktopNotificationsChange: function(checked) { SettingsStore.setValue( "notificationsEnabled", null, SettingLevel.DEVICE, - event.target.checked, + checked, ).finally(() => { this.forceUpdate(); }); }, - onEnableDesktopNotificationBodyChange: function(event) { + onEnableDesktopNotificationBodyChange: function(checked) { SettingsStore.setValue( "notificationBodyEnabled", null, SettingLevel.DEVICE, - event.target.checked, + checked, ).finally(() => { this.forceUpdate(); }); }, - onEnableAudioNotificationsChange: function(event) { + onEnableAudioNotificationsChange: function(checked) { SettingsStore.setValue( "audioNotificationsEnabled", null, SettingLevel.DEVICE, - event.target.checked, + checked, ).finally(() => { this.forceUpdate(); }); @@ -146,7 +136,7 @@ module.exports = React.createClass({ let emailPusherPromise; if (event.target.checked) { const data = {}; - data['brand'] = this.props.brand || 'Riot'; + data['brand'] = SdkConfig.get().brand || 'Riot'; emailPusherPromise = UserSettingsStore.addEmailPusher(address, data); } else { const emailPusher = UserSettingsStore.getEmailPusher(this.state.pushers, address); @@ -434,7 +424,6 @@ module.exports = React.createClass({ // Check if any legacy im.vector rules need to be ported to the new API // for overriding the actions of default rules. _portRulesToNewAPI: function(rulesets) { - const self = this; const needsUpdate = []; const cli = MatrixClientPeg.get(); @@ -633,6 +622,8 @@ module.exports = React.createClass({ externalPushRules: self.state.externalPushRules, }); }).done(); + + MatrixClientPeg.get().getThreePids().then((r) => this.setState({threepids: r.threepids})); }, _updatePushRuleActions: function(rule, actions, enabled) { @@ -691,27 +682,25 @@ module.exports = React.createClass({ return rows; }, + hasEmailPusher: function(pushers, address) { + if (pushers === undefined) { + return false; + } + for (let i = 0; i < pushers.length; ++i) { + if (pushers[i].kind === 'email' && pushers[i].pushkey === address) { + return true; + } + } + return false; + }, + emailNotificationsRow: function(address, label) { - return (
-
- -
-
- -
-
); + return ; }, render: function() { - const self = this; - let spinner; if (this.state.phase === this.phases.LOADING) { const Loader = sdk.getComponent("elements.Spinner"); @@ -720,23 +709,9 @@ module.exports = React.createClass({ let masterPushRuleDiv; if (this.state.masterPushRule) { - masterPushRuleDiv = ( -
-
- -
-
- -
-
- ); + masterPushRuleDiv = ; } // When enabled, the master rule inhibits all existing rules @@ -747,17 +722,17 @@ module.exports = React.createClass({ {masterPushRuleDiv}
- { _t('All notifications are currently disabled for all targets.') }. + { _t('All notifications are currently disabled for all targets.') }
); } - const emailThreepids = this.props.threepids.filter((tp) => tp.medium === "email"); + const emailThreepids = this.state.threepids.filter((tp) => tp.medium === "email"); let emailNotificationsRow; if (emailThreepids.length === 0) { emailNotificationsRow =
- { _t('Add an email address above to configure email notifications') } + { _t('Add an email address to configure email notifications') }
; } else { // This only supports the first email address in your profile for now @@ -788,7 +763,7 @@ module.exports = React.createClass({ let devicesSection; if (this.state.pushers === undefined) { devicesSection =
{ _t('Unable to fetch notification target list') }
; - } else if (this.state.pushers.length == 0) { + } else if (this.state.pushers.length === 0) { devicesSection = null; } else { // TODO: It would be great to be able to delete pushers from here too, @@ -836,50 +811,17 @@ module.exports = React.createClass({ { spinner } -
-
- -
-
- -
-
+ -
-
- -
-
- -
-
+ -
-
- -
-
- -
-
+ { emailNotificationsRow } diff --git a/src/components/views/settings/tabs/LabsSettingsTab.js b/src/components/views/settings/tabs/LabsSettingsTab.js index a815ddfdd4..a83abb3138 100644 --- a/src/components/views/settings/tabs/LabsSettingsTab.js +++ b/src/components/views/settings/tabs/LabsSettingsTab.js @@ -18,8 +18,8 @@ import React from 'react'; import {_t} from "../../../../languageHandler"; import PropTypes from "prop-types"; import SettingsStore from "../../../../settings/SettingsStore"; -import ToggleSwitch from "../../elements/ToggleSwitch"; import MatrixClientPeg from "../../../../MatrixClientPeg"; +import LabelledToggleSwitch from "../../elements/LabelledToggleSwitch"; const Modal = require("../../../../Modal"); const sdk = require("../../../../index"); @@ -65,15 +65,9 @@ export class LabsSettingToggle extends React.Component { }; render() { - // This is a minimal version of a SettingsFlag const label = _t(SettingsStore.getDisplayName(this.props.featureId)); const value = SettingsStore.isFeatureEnabled(this.props.featureId); - return ( -
- {label} - -
- ); + return ; } } diff --git a/src/components/views/settings/tabs/NotificationSettingsTab.js b/src/components/views/settings/tabs/NotificationSettingsTab.js new file mode 100644 index 0000000000..3a4e79f34c --- /dev/null +++ b/src/components/views/settings/tabs/NotificationSettingsTab.js @@ -0,0 +1,37 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from 'react'; +import {_t} from "../../../../languageHandler"; +const sdk = require("../../../../index"); + +export default class NotificationSettingsTab extends React.Component { + constructor() { + super(); + } + + render() { + const Notifications = sdk.getComponent("views.settings.Notifications"); + return ( +
+
{_t("Notifications")}
+
+ +
+
+ ); + } +} diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index e70f60c48b..20f7db0ebe 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -399,7 +399,7 @@ "Notify me for anything else": "Notify me for anything else", "Enable notifications for this account": "Enable notifications for this account", "All notifications are currently disabled for all targets.": "All notifications are currently disabled for all targets.", - "Add an email address above to configure email notifications": "Add an email address above to configure email notifications", + "Add an email address to configure email notifications": "Add an email address to configure email notifications", "Enable email notifications": "Enable email notifications", "Notifications on the following keywords follow rules which can’t be displayed here:": "Notifications on the following keywords follow rules which can’t be displayed here:", "Unable to fetch notification target list": "Unable to fetch notification target list", @@ -442,6 +442,7 @@ "Lazy loading members not supported": "Lazy loading members not supported", "Lazy loading is not supported by your current homeserver.": "Lazy loading is not supported by your current homeserver.", "Labs": "Labs", + "Notifications": "Notifications", "Cannot add any more widgets": "Cannot add any more widgets", "The maximum permitted number of widgets have already been added to this room.": "The maximum permitted number of widgets have already been added to this room.", "Add a widget": "Add a widget", @@ -720,7 +721,6 @@ "When someone puts a URL in their message, a URL preview can be shown to give more information about that link such as the title, description, and an image from the website.": "When someone puts a URL in their message, a URL preview can be shown to give more information about that link such as the title, description, and an image from the website.", "Members": "Members", "Files": "Files", - "Notifications": "Notifications", "Sunday": "Sunday", "Monday": "Monday", "Tuesday": "Tuesday",