diff --git a/plugins/talk-plugin-notifications-category-featured/client/containers/Toggle.js b/plugins/talk-plugin-notifications-category-featured/client/containers/Toggle.js
deleted file mode 100644
index f888789f3..000000000
--- a/plugins/talk-plugin-notifications-category-featured/client/containers/Toggle.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { compose, gql } from 'react-apollo';
-import Toggle from 'talk-plugin-notifications/client/components/Toggle';
-import { t } from 'plugin-api/beta/client/services';
-import { withFragments } from 'plugin-api/beta/client/hocs';
-
-class ToggleContainer extends React.Component {
- constructor(props) {
- super(props);
- props.setTurnOffInputFragment({ onFeatured: false });
-
- if (this.getOnFeaturedSetting()) {
- props.indicateOn();
- }
- }
-
- componentWillReceiveProps(nextProps) {
- const prevSetting = this.getOnFeaturedSetting(this.props);
- const nextSetting = this.getOnFeaturedSetting(nextProps);
- if (prevSetting && !nextSetting) {
- nextProps.indicateOff();
- } else if (!prevSetting && nextSetting) {
- nextProps.indicateOn();
- }
- }
-
- getOnFeaturedSetting = (props = this.props) =>
- props.root.me.notificationSettings.onFeatured;
-
- toggle = () => {
- this.props.updateNotificationSettings({
- onFeatured: !this.getOnFeaturedSetting(),
- });
- };
-
- render() {
- return (
-
- {t('talk-plugin-notifications-category-featured.toggle_description')}
-
- );
- }
-}
-
-ToggleContainer.propTypes = {
- data: PropTypes.object,
- root: PropTypes.object,
- indicateOn: PropTypes.func.isRequired,
- indicateOff: PropTypes.func.isRequired,
- setTurnOffInputFragment: PropTypes.func.isRequired,
- updateNotificationSettings: PropTypes.func.isRequired,
- disabled: PropTypes.bool.isRequired,
-};
-
-const enhance = compose(
- withFragments({
- root: gql`
- fragment TalkNotificationsCategoryFeatured_Toggle_root on RootQuery {
- me {
- notificationSettings {
- onFeatured
- }
- }
- }
- `,
- })
-);
-
-export default enhance(ToggleContainer);
diff --git a/plugins/talk-plugin-notifications-category-featured/client/graphql.js b/plugins/talk-plugin-notifications-category-featured/client/graphql.js
deleted file mode 100644
index 440a6f7fa..000000000
--- a/plugins/talk-plugin-notifications-category-featured/client/graphql.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import { gql } from 'react-apollo';
-
-export default {
- mutations: {
- UpdateNotificationSettings: ({
- variables: { input },
- state: { auth: { user: { id } } },
- }) => ({
- update: proxy => {
- if (input.onFeatured === undefined) {
- return;
- }
-
- const fragment = gql`
- fragment TalkNotificationsCategoryFeatured_User_Fragment on User {
- notificationSettings {
- onFeatured
- }
- }
- `;
- const fragmentId = `User_${id}`;
- const data = {
- __typename: 'User',
- notificationSettings: {
- __typename: 'NotificationSettings',
- onFeatured: input.onFeatured,
- },
- };
- proxy.writeFragment({ fragment, id: fragmentId, data });
- },
- }),
- },
-};
diff --git a/plugins/talk-plugin-notifications-category-featured/client/index.js b/plugins/talk-plugin-notifications-category-featured/client/index.js
index 1e22c3a93..74c0c2aa5 100644
--- a/plugins/talk-plugin-notifications-category-featured/client/index.js
+++ b/plugins/talk-plugin-notifications-category-featured/client/index.js
@@ -1,11 +1,14 @@
-import Toggle from './containers/Toggle';
import translations from './translations.yml';
-import graphql from './graphql';
+import { t } from 'plugin-api/beta/client/services';
+import { createSettingsToggle } from 'talk-plugin-notifications/client/api/factories';
+
+const SettingsToggle = createSettingsToggle('onFeatured', () =>
+ t('talk-plugin-notifications-category-featured.toggle_description')
+);
export default {
slots: {
- notificationSettings: [Toggle],
+ notificationSettings: [SettingsToggle],
},
translations,
- ...graphql,
};
diff --git a/plugins/talk-plugin-notifications-category-reply/client/containers/Toggle.js b/plugins/talk-plugin-notifications-category-reply/client/containers/Toggle.js
deleted file mode 100644
index c55be5f90..000000000
--- a/plugins/talk-plugin-notifications-category-reply/client/containers/Toggle.js
+++ /dev/null
@@ -1,110 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { compose, gql } from 'react-apollo';
-import Toggle from 'talk-plugin-notifications/client/components/Toggle';
-import { t } from 'plugin-api/beta/client/services';
-import {
- withFragments,
- withGraphQLExtension,
-} 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 (
-
- {t('talk-plugin-notifications-category-reply.toggle_description')}
-
- );
- }
-}
-
-ToggleContainer.propTypes = {
- data: PropTypes.object,
- root: PropTypes.object,
- indicateOn: PropTypes.func.isRequired,
- indicateOff: PropTypes.func.isRequired,
- setTurnOffInputFragment: PropTypes.func.isRequired,
- updateNotificationSettings: PropTypes.func.isRequired,
- disabled: PropTypes.bool.isRequired,
-};
-
-const extension = {
- mutations: {
- UpdateNotificationSettings: ({
- variables: { input },
- state: { auth: { user: { id } } },
- }) => ({
- update: proxy => {
- if (input.onReply === undefined) {
- return;
- }
-
- const fragment = gql`
- fragment TalkNotificationsCategoryReply_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 });
- },
- }),
- },
-};
-
-const enhance = compose(
- withFragments({
- root: gql`
- fragment TalkNotificationsCategoryReply_Toggle_root on RootQuery {
- me {
- notificationSettings {
- onReply
- }
- }
- }
- `,
- }),
- withGraphQLExtension(extension)
-);
-
-export default enhance(ToggleContainer);
diff --git a/plugins/talk-plugin-notifications-category-reply/client/graphql.js b/plugins/talk-plugin-notifications-category-reply/client/graphql.js
deleted file mode 100644
index 623e72366..000000000
--- a/plugins/talk-plugin-notifications-category-reply/client/graphql.js
+++ /dev/null
@@ -1,33 +0,0 @@
-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 TalkNotificationsCategoryReply_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 fa10c15e2..098a1397e 100644
--- a/plugins/talk-plugin-notifications-category-reply/client/index.js
+++ b/plugins/talk-plugin-notifications-category-reply/client/index.js
@@ -1,8 +1,14 @@
-import Toggle from './containers/Toggle';
import translations from './translations.yml';
+import { t } from 'plugin-api/beta/client/services';
+import { createSettingsToggle } from 'talk-plugin-notifications/client/api/factories';
+
+const SettingsToggle = createSettingsToggle('onReply', () =>
+ t('talk-plugin-notifications-category-reply.toggle_description')
+);
+
export default {
slots: {
- notificationSettings: [Toggle],
+ notificationSettings: [SettingsToggle],
},
translations,
};
diff --git a/plugins/talk-plugin-notifications-category-staff/client/containers/Toggle.js b/plugins/talk-plugin-notifications-category-staff/client/containers/Toggle.js
deleted file mode 100644
index 62a4cbbce..000000000
--- a/plugins/talk-plugin-notifications-category-staff/client/containers/Toggle.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { compose, gql } from 'react-apollo';
-import Toggle from 'talk-plugin-notifications/client/components/Toggle';
-import { t } from 'plugin-api/beta/client/services';
-import { withFragments } from 'plugin-api/beta/client/hocs';
-
-class ToggleContainer extends React.Component {
- constructor(props) {
- super(props);
- props.setTurnOffInputFragment({ onStaffReply: 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.onStaffReply;
-
- toggle = () => {
- this.props.updateNotificationSettings({
- onStaffReply: !this.getOnReplySetting(),
- });
- };
-
- render() {
- return (
-
- {t('talk-plugin-notifications-category-staff.toggle_description')}
-
- );
- }
-}
-
-ToggleContainer.propTypes = {
- data: PropTypes.object,
- root: PropTypes.object,
- indicateOn: PropTypes.func.isRequired,
- indicateOff: PropTypes.func.isRequired,
- setTurnOffInputFragment: PropTypes.func.isRequired,
- updateNotificationSettings: PropTypes.func.isRequired,
- disabled: PropTypes.bool.isRequired,
-};
-
-const enhance = compose(
- withFragments({
- root: gql`
- fragment TalkNotificationsCategoryStaffReply_User_Fragment on RootQuery {
- me {
- notificationSettings {
- onStaffReply
- }
- }
- }
- `,
- })
-);
-
-export default enhance(ToggleContainer);
diff --git a/plugins/talk-plugin-notifications-category-staff/client/graphql.js b/plugins/talk-plugin-notifications-category-staff/client/graphql.js
deleted file mode 100644
index 2e8007d4f..000000000
--- a/plugins/talk-plugin-notifications-category-staff/client/graphql.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import { gql } from 'react-apollo';
-
-export default {
- mutations: {
- UpdateNotificationSettings: ({
- variables: { input },
- state: { auth: { user: { id } } },
- }) => ({
- update: proxy => {
- if (input.onStaffReply === undefined) {
- return;
- }
-
- const fragment = gql`
- fragment TalkNotificationsCategoryStaffReply_User_Fragment on User {
- notificationSettings {
- onStaffReply
- }
- }
- `;
- const fragmentId = `User_${id}`;
- const data = {
- __typename: 'User',
- notificationSettings: {
- __typename: 'NotificationSettings',
- onStaffReply: input.onStaffReply,
- },
- };
- proxy.writeFragment({ fragment, id: fragmentId, data });
- },
- }),
- },
-};
diff --git a/plugins/talk-plugin-notifications-category-staff/client/index.js b/plugins/talk-plugin-notifications-category-staff/client/index.js
index 1e22c3a93..e273fceaa 100644
--- a/plugins/talk-plugin-notifications-category-staff/client/index.js
+++ b/plugins/talk-plugin-notifications-category-staff/client/index.js
@@ -1,11 +1,14 @@
-import Toggle from './containers/Toggle';
import translations from './translations.yml';
-import graphql from './graphql';
+import { t } from 'plugin-api/beta/client/services';
+import { createSettingsToggle } from 'talk-plugin-notifications/client/api/factories';
+
+const SettingsToggle = createSettingsToggle('onStaffReply', () =>
+ t('talk-plugin-notifications-category-staff.toggle_description')
+);
export default {
slots: {
- notificationSettings: [Toggle],
+ notificationSettings: [SettingsToggle],
},
translations,
- ...graphql,
};
diff --git a/plugins/talk-plugin-notifications/client/api/components/Toggle.css b/plugins/talk-plugin-notifications/client/api/components/Toggle.css
new file mode 100644
index 000000000..3f5b02705
--- /dev/null
+++ b/plugins/talk-plugin-notifications/client/api/components/Toggle.css
@@ -0,0 +1,20 @@
+.title {
+ display: inline-block;
+ width: 100%;
+ cursor: pointer;
+ user-select: none;
+
+ &.disabled {
+ color: #e5e5e5;
+ cursor: default;
+ }
+}
+
+.toggle {
+ display: flex;
+ align-items: center;
+}
+
+.checkBox {
+ text-align: right;
+}
diff --git a/plugins/talk-plugin-notifications/client/api/components/Toggle.js b/plugins/talk-plugin-notifications/client/api/components/Toggle.js
new file mode 100644
index 000000000..40e7da4e6
--- /dev/null
+++ b/plugins/talk-plugin-notifications/client/api/components/Toggle.js
@@ -0,0 +1,41 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Checkbox } from 'plugin-api/beta/client/components/ui';
+import styles from './Toggle.css';
+import uuid from 'uuid/v4';
+import cn from 'classnames';
+
+class Toggle extends React.Component {
+ id = uuid();
+
+ render() {
+ const { checked, onChange, children, disabled } = this.props;
+ return (
+
+ );
+ }
+}
+
+Toggle.propTypes = {
+ disabled: PropTypes.bool,
+ checked: PropTypes.bool,
+ onChange: PropTypes.func,
+ children: PropTypes.node,
+};
+
+export default Toggle;
diff --git a/plugins/talk-plugin-notifications/client/api/components/index.js b/plugins/talk-plugin-notifications/client/api/components/index.js
new file mode 100644
index 000000000..81e73b58b
--- /dev/null
+++ b/plugins/talk-plugin-notifications/client/api/components/index.js
@@ -0,0 +1 @@
+export { default as Toggle } from './Toggle';
diff --git a/plugins/talk-plugin-notifications/client/api/factories/createSettingsToggle.js b/plugins/talk-plugin-notifications/client/api/factories/createSettingsToggle.js
new file mode 100644
index 000000000..95b7789cb
--- /dev/null
+++ b/plugins/talk-plugin-notifications/client/api/factories/createSettingsToggle.js
@@ -0,0 +1,22 @@
+import React from 'react';
+import Toggle from '../components/Toggle';
+import withSettingsToggle from '../hocs/withSettingsToggle';
+
+/**
+ * createSettingsToggle will add a boolean setting with the
+ * name `settingsName` to notification settings and return
+ * a full Toggle Component.
+ *
+ * You must provide a `label` either as a string or as a callback.
+ * E.g. to provide translations you could do:
+ *
+ * `const SettingsToggle = createSettingsToggle('onReply', () => t('translate'));`
+ */
+const createSettingsToggle = (settingsName, label) => {
+ const SettingsToggle = props => (
+ {typeof label === 'function' ? label() : label}
+ );
+ return withSettingsToggle(settingsName)(SettingsToggle);
+};
+
+export default createSettingsToggle;
diff --git a/plugins/talk-plugin-notifications/client/api/factories/index.js b/plugins/talk-plugin-notifications/client/api/factories/index.js
new file mode 100644
index 000000000..b18ad7679
--- /dev/null
+++ b/plugins/talk-plugin-notifications/client/api/factories/index.js
@@ -0,0 +1 @@
+export { default as createSettingsToggle } from './createSettingsToggle';
diff --git a/plugins/talk-plugin-notifications/client/api/hocs/index.js b/plugins/talk-plugin-notifications/client/api/hocs/index.js
new file mode 100644
index 000000000..c55d371bc
--- /dev/null
+++ b/plugins/talk-plugin-notifications/client/api/hocs/index.js
@@ -0,0 +1 @@
+export { default as withSettingsToggle } from './withSettingsToggle';
diff --git a/plugins/talk-plugin-notifications/client/api/hocs/withSettingsToggle.js b/plugins/talk-plugin-notifications/client/api/hocs/withSettingsToggle.js
new file mode 100644
index 000000000..fc7b1bac6
--- /dev/null
+++ b/plugins/talk-plugin-notifications/client/api/hocs/withSettingsToggle.js
@@ -0,0 +1,121 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { compose, gql } from 'react-apollo';
+import {
+ withFragments,
+ withGraphQLExtension,
+} from 'plugin-api/beta/client/hocs';
+
+const createHOC = settingsName => WrappedComponent => {
+ class WithSettingsToggle extends React.Component {
+ constructor(props) {
+ super(props);
+ props.setTurnOffInputFragment({ [settingsName]: false });
+
+ if (this.isChecked()) {
+ props.indicateOn();
+ }
+ }
+
+ componentWillReceiveProps(nextProps) {
+ const prevSetting = this.isChecked(this.props);
+ const nextSetting = this.isChecked(nextProps);
+ if (prevSetting && !nextSetting) {
+ nextProps.indicateOff();
+ } else if (!prevSetting && nextSetting) {
+ nextProps.indicateOn();
+ }
+ }
+
+ isChecked = (props = this.props) =>
+ props.root.me.notificationSettings[settingsName];
+
+ toggle = () => {
+ this.props.updateNotificationSettings({
+ [settingsName]: !this.isChecked(),
+ });
+ };
+
+ render() {
+ return (
+
+ );
+ }
+ }
+
+ WithSettingsToggle.propTypes = {
+ root: PropTypes.object,
+ indicateOn: PropTypes.func.isRequired,
+ indicateOff: PropTypes.func.isRequired,
+ setTurnOffInputFragment: PropTypes.func.isRequired,
+ updateNotificationSettings: PropTypes.func.isRequired,
+ disabled: PropTypes.bool.isRequired,
+ };
+
+ return WithSettingsToggle;
+};
+
+/**
+ * withSettingsToggle will add a boolean setting with the
+ * name `settingsName` to notification settings and provide
+ * the folliwng props:
+ *
+ * `checked: boolean` Whether setting is on or off
+ * `onChange: () => void` Calling this will toggle the setting
+ * `disabled: boolean` Whether setting is disabled
+ */
+const withSettingsToggle = settingsName => {
+ const extension = {
+ mutations: {
+ UpdateNotificationSettings: ({
+ variables: { input },
+ state: { auth: { user: { id } } },
+ }) => ({
+ update: proxy => {
+ if (input[settingsName] === undefined) {
+ return;
+ }
+
+ const fragment = gql`
+ fragment TalkNotifications_Toggle_${settingsName}_Fragment on User {
+ notificationSettings {
+ ${settingsName}
+ }
+ }
+ `;
+ const fragmentId = `User_${id}`;
+ const data = {
+ __typename: 'User',
+ notificationSettings: {
+ __typename: 'NotificationSettings',
+ [settingsName]: input[settingsName],
+ },
+ };
+ proxy.writeFragment({ fragment, id: fragmentId, data });
+ },
+ }),
+ },
+ };
+
+ return compose(
+ withFragments({
+ root: gql`
+ fragment TalkNotifications_Toggle_${settingsName}_root on RootQuery {
+ me {
+ notificationSettings {
+ ${settingsName}
+ }
+ }
+ }
+ `,
+ }),
+ withGraphQLExtension(extension),
+ createHOC(settingsName)
+ );
+};
+
+export default withSettingsToggle;