Implemented notification frontend functionality

This commit is contained in:
Chi Vinh Le
2018-02-21 18:03:46 +01:00
parent 284009df55
commit 6935330536
10 changed files with 193 additions and 7 deletions
+1
View File
@@ -6,6 +6,7 @@ export {
withEmit,
excludeIf,
withFragments,
withMutation,
withForgotPassword,
withSignIn,
withSignUp,
@@ -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 (
<div className={styles.toggle}>
<div className={styles.description}>
{t('talk-plugin-notifications-category-reply.toggle_description')}
<Checkbox checked={checked} />
<Checkbox checked={checked} onChange={onChange} />
</div>
</div>
);
@@ -20,6 +20,7 @@ class Toggle extends React.Component {
Toggle.propTypes = {
checked: PropTypes.bool,
onChange: PropTypes.func,
};
export default Toggle;
@@ -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 <Toggle checked={this.props.root.me.notificationSettings.onReply} />;
return <Toggle checked={this.getOnReplySetting()} onChange={this.toggle} />;
}
}
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(
@@ -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 });
},
}),
},
};
@@ -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,
};
@@ -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 (
<IfSlotIsNotEmpty slot="notificationSettings" queryData={{ root }}>
<div>
@@ -16,7 +33,17 @@ class Settings extends React.Component {
{t('talk-plugin-notifications.settings_subtitle')}
</h4>
<div className={styles.innerSettings}>
<Slot fill="notificationSettings" queryData={{ root }} />
<Slot
fill="notificationSettings"
queryData={{ root }}
childFactory={this.childFactory}
setTurnOffInputFragment={setTurnOffInputFragment}
updateNotificationSettings={updateNotificationSettings}
/>
<BareButton onClick={turnOffAll} disabled={turnOffButtonDisabled}>
{' '}
Turn Off All{' '}
</BareButton>
</div>
</div>
</IfSlotIsNotEmpty>
@@ -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;
@@ -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 <Settings data={this.props.data} root={this.props.root} />;
return (
<Settings
data={this.props.data}
root={this.props.root}
indicateOn={this.indicateOn}
indicateOff={this.indicateOff}
setTurnOffInputFragment={this.setTurnOffInputFragment}
updateNotificationSettings={this.props.updateNotificationSettings}
turnOffAll={this.turnOffAll}
turnOffButtonDisabled={this.state.hasNotifications.length === 0}
/>
);
}
}
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);
@@ -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,
},
},
}),
},
};
@@ -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,
};
@@ -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,
},
});
},
}),
}
);