diff --git a/plugin-api/beta/client/hocs/index.js b/plugin-api/beta/client/hocs/index.js index 397d8b94d..8b91c83de 100644 --- a/plugin-api/beta/client/hocs/index.js +++ b/plugin-api/beta/client/hocs/index.js @@ -6,6 +6,7 @@ export { withEmit, excludeIf, withFragments, + withMutation, withForgotPassword, withSignIn, withSignUp, diff --git a/plugins/talk-plugin-notifications-category-reply/client/components/Toggle.js b/plugins/talk-plugin-notifications-category-reply/client/components/Toggle.js index a9a0ff519..fa32a0880 100644 --- a/plugins/talk-plugin-notifications-category-reply/client/components/Toggle.js +++ b/plugins/talk-plugin-notifications-category-reply/client/components/Toggle.js @@ -6,12 +6,12 @@ import styles from './Toggle.css'; class Toggle extends React.Component { render() { - const { checked } = this.props; + const { checked, onChange } = this.props; return (
{t('talk-plugin-notifications-category-reply.toggle_description')} - +
); @@ -20,6 +20,7 @@ class Toggle extends React.Component { Toggle.propTypes = { checked: PropTypes.bool, + onChange: PropTypes.func, }; export default Toggle; diff --git a/plugins/talk-plugin-notifications-category-reply/client/containers/Toggle.js b/plugins/talk-plugin-notifications-category-reply/client/containers/Toggle.js index 2d275e452..70812778c 100644 --- a/plugins/talk-plugin-notifications-category-reply/client/containers/Toggle.js +++ b/plugins/talk-plugin-notifications-category-reply/client/containers/Toggle.js @@ -5,14 +5,46 @@ import Toggle from '../components/Toggle'; import { withFragments } from 'plugin-api/beta/client/hocs'; class ToggleContainer extends React.Component { + constructor(props) { + super(props); + props.setTurnOffInputFragment({ onReply: false }); + + if (this.getOnReplySetting()) { + props.indicateOn(); + } + } + + componentWillReceiveProps(nextProps) { + const prevSetting = this.getOnReplySetting(this.props); + const nextSetting = this.getOnReplySetting(nextProps); + if (prevSetting && !nextSetting) { + nextProps.indicateOff(); + } else if (!prevSetting && nextSetting) { + nextProps.indicateOn(); + } + } + + getOnReplySetting = (props = this.props) => + props.root.me.notificationSettings.onReply; + + toggle = () => { + this.props.updateNotificationSettings({ + onReply: !this.getOnReplySetting(), + }); + }; + render() { - return ; + return ; } } ToggleContainer.propTypes = { data: PropTypes.object, root: PropTypes.object, + indicateOn: PropTypes.func.isRequired, + indicateOff: PropTypes.func.isRequired, + setTurnOffInputFragment: PropTypes.func.isRequired, + updateNotificationSettings: PropTypes.func.isRequired, }; const enhance = compose( diff --git a/plugins/talk-plugin-notifications-category-reply/client/graphql.js b/plugins/talk-plugin-notifications-category-reply/client/graphql.js new file mode 100644 index 000000000..2b216aa95 --- /dev/null +++ b/plugins/talk-plugin-notifications-category-reply/client/graphql.js @@ -0,0 +1,33 @@ +import { gql } from 'react-apollo'; + +export default { + mutations: { + UpdateNotificationSettings: ({ + variables: { input }, + state: { auth: { user: { id } } }, + }) => ({ + update: proxy => { + if (input.onReply === undefined) { + return; + } + + const fragment = gql` + fragment TalkNotifications_User_Fragment on User { + notificationSettings { + onReply + } + } + `; + const fragmentId = `User_${id}`; + const data = { + __typename: 'User', + notificationSettings: { + __typename: 'NotificationSettings', + onReply: input.onReply, + }, + }; + proxy.writeFragment({ fragment, id: fragmentId, data }); + }, + }), + }, +}; diff --git a/plugins/talk-plugin-notifications-category-reply/client/index.js b/plugins/talk-plugin-notifications-category-reply/client/index.js index 38a37e6ef..1e22c3a93 100644 --- a/plugins/talk-plugin-notifications-category-reply/client/index.js +++ b/plugins/talk-plugin-notifications-category-reply/client/index.js @@ -1,9 +1,11 @@ import Toggle from './containers/Toggle'; import translations from './translations.yml'; +import graphql from './graphql'; export default { slots: { notificationSettings: [Toggle], }, translations, + ...graphql, }; diff --git a/plugins/talk-plugin-notifications/client/components/Settings.js b/plugins/talk-plugin-notifications/client/components/Settings.js index b81b65373..91523621a 100644 --- a/plugins/talk-plugin-notifications/client/components/Settings.js +++ b/plugins/talk-plugin-notifications/client/components/Settings.js @@ -4,10 +4,27 @@ import { IfSlotIsNotEmpty } from 'plugin-api/beta/client/components'; import { Slot } from 'plugin-api/beta/client/components'; import { t } from 'plugin-api/beta/client/services'; import styles from './Settings.css'; +import { BareButton } from 'plugin-api/beta/client/components/ui'; class Settings extends React.Component { + childFactory = el => { + const pluginName = el.type.talkPluginName; + const props = { + indicateOn: () => this.props.indicateOn(pluginName), + indicateOff: () => this.props.indicateOff(pluginName), + }; + return React.cloneElement(el, props); + }; + render() { - const { root } = this.props; + const { + root, + setTurnOffInputFragment, + updateNotificationSettings, + turnOffAll, + turnOffButtonDisabled, + } = this.props; + return (
@@ -16,7 +33,17 @@ class Settings extends React.Component { {t('talk-plugin-notifications.settings_subtitle')}
- + + + {' '} + Turn Off All{' '} +
@@ -26,6 +53,12 @@ class Settings extends React.Component { Settings.propTypes = { root: PropTypes.object, + indicateOn: PropTypes.func.isRequired, + indicateOff: PropTypes.func.isRequired, + setTurnOffInputFragment: PropTypes.func.isRequired, + updateNotificationSettings: PropTypes.func.isRequired, + turnOffAll: PropTypes.func.isRequired, + turnOffButtonDisabled: PropTypes.bool.isRequired, }; export default Settings; diff --git a/plugins/talk-plugin-notifications/client/containers/Settings.js b/plugins/talk-plugin-notifications/client/containers/Settings.js index 9eb16ceee..ff07c6433 100644 --- a/plugins/talk-plugin-notifications/client/containers/Settings.js +++ b/plugins/talk-plugin-notifications/client/containers/Settings.js @@ -4,18 +4,53 @@ import { compose, gql } from 'react-apollo'; import Settings from '../components/Settings'; import { withFragments } from 'plugin-api/beta/client/hocs'; import { getSlotFragmentSpreads } from 'plugin-api/beta/client/utils'; +import { withUpdateNotificationSettings } from '../mutations'; const slots = ['notificationSettings']; class SettingsContainer extends React.Component { + state = { + hasNotifications: [], + turnOffInput: {}, + }; + + indicateOn = plugin => + this.setState({ + hasNotifications: this.state.hasNotifications.concat(plugin), + }); + indicateOff = plugin => + this.setState({ + hasNotifications: this.state.hasNotifications.filter(i => i !== plugin), + }); + setTurnOffInputFragment = fragment => + this.setState({ + turnOffInput: { ...this.state.turnOffInput, ...fragment }, + }); + + turnOffAll = () => { + this.props.updateNotificationSettings(this.state.turnOffInput); + }; + render() { - return ; + return ( + + ); } } SettingsContainer.propTypes = { data: PropTypes.object, root: PropTypes.object, + updateNotificationSettings: PropTypes.func.isRequired, }; const enhance = compose( @@ -26,7 +61,8 @@ const enhance = compose( ${getSlotFragmentSpreads(slots, 'root')} } `, - }) + }), + withUpdateNotificationSettings ); export default enhance(SettingsContainer); diff --git a/plugins/talk-plugin-notifications/client/graphql.js b/plugins/talk-plugin-notifications/client/graphql.js new file mode 100644 index 000000000..b48b63668 --- /dev/null +++ b/plugins/talk-plugin-notifications/client/graphql.js @@ -0,0 +1,23 @@ +import { gql } from 'react-apollo'; + +export default { + fragments: { + UpdateNotificationSettingsResponse: gql` + fragment Talk_UpdateNotificationSettingsResponse on UpdateNotificationSettingsResponse { + errors { + translation_key + } + } + `, + }, + mutations: { + UpdateNotificationSettings: () => ({ + optimisticResponse: { + updateNotificationSettings: { + __typename: 'UpdateNotificationSettingsResponse', + errors: null, + }, + }, + }), + }, +}; diff --git a/plugins/talk-plugin-notifications/client/index.js b/plugins/talk-plugin-notifications/client/index.js index 69b29888c..8d3b9a08a 100644 --- a/plugins/talk-plugin-notifications/client/index.js +++ b/plugins/talk-plugin-notifications/client/index.js @@ -1,9 +1,11 @@ import Settings from './containers/Settings'; import translations from './translations.yml'; +import graphql from './graphql'; export default { slots: { profileSettings: [Settings], }, translations, + ...graphql, }; diff --git a/plugins/talk-plugin-notifications/client/mutations.js b/plugins/talk-plugin-notifications/client/mutations.js new file mode 100644 index 000000000..83d50fc1f --- /dev/null +++ b/plugins/talk-plugin-notifications/client/mutations.js @@ -0,0 +1,23 @@ +import { withMutation } from 'plugin-api/beta/client/hocs'; +import { gql } from 'react-apollo'; + +export const withUpdateNotificationSettings = withMutation( + gql` + mutation UpdateNotificationSettings($input: NotificationSettingsInput!) { + updateNotificationSettings(input: $input) { + ...UpdateNotificationSettingsResponse + } + } + `, + { + props: ({ mutate }) => ({ + updateNotificationSettings: input => { + return mutate({ + variables: { + input, + }, + }); + }, + }), + } +);