mirror of
https://github.com/wassname/talk.git
synced 2026-08-04 13:23:35 +08:00
added featured notifications
This commit is contained in:
@@ -40,6 +40,7 @@ plugins/*
|
||||
!plugins/talk-plugin-mod
|
||||
!plugins/talk-plugin-moderation-actions
|
||||
!plugins/talk-plugin-notifications
|
||||
!plugins/talk-plugin-notifications-category-featured
|
||||
!plugins/talk-plugin-notifications-category-reply
|
||||
!plugins/talk-plugin-offtopic
|
||||
!plugins/talk-plugin-permalink
|
||||
|
||||
@@ -149,3 +149,11 @@ Source: [plugins/talk-plugin-notifications-category-reply](https://github.com/co
|
||||
|
||||
Replies made to each user will trigger an email to be sent with the notification
|
||||
details if enabled.
|
||||
|
||||
### talk-plugin-notifications-category-featured
|
||||
{:.param}
|
||||
|
||||
Source: [plugins/talk-plugin-notifications-category-featured](https://github.com/coralproject/talk/tree/master/plugins/talk-plugin-notifications-category-featured){:target="_blank"}
|
||||
|
||||
When a comment is featured (via the `talk-plugin-featured-comments` plugin), the
|
||||
user will receive a notification email.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "@coralproject/eslint-config-talk/client"
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
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 (
|
||||
<Toggle checked={this.getOnFeaturedSetting()} onChange={this.toggle}>
|
||||
{t('talk-plugin-notifications-category-reply.toggle_description')}
|
||||
</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(
|
||||
withFragments({
|
||||
root: gql`
|
||||
fragment TalkNotificationsCategoryFeatured_Toggle_root on RootQuery {
|
||||
me {
|
||||
notificationSettings {
|
||||
onFeatured
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
})
|
||||
);
|
||||
|
||||
export default enhance(ToggleContainer);
|
||||
@@ -0,0 +1,33 @@
|
||||
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 });
|
||||
},
|
||||
}),
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
import Toggle from './containers/Toggle';
|
||||
import translations from './translations.yml';
|
||||
import graphql from './graphql';
|
||||
|
||||
export default {
|
||||
slots: {
|
||||
notificationSettings: [Toggle],
|
||||
},
|
||||
translations,
|
||||
...graphql,
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
en:
|
||||
talk-plugin-notifications-category-featured:
|
||||
toggle_description: My comment is featured
|
||||
@@ -0,0 +1,118 @@
|
||||
const { graphql } = require('graphql');
|
||||
const { get } = require('lodash');
|
||||
const path = require('path');
|
||||
|
||||
const handle = async (ctx, { comment }) => {
|
||||
const { connectors: { graph: { schema } } } = ctx;
|
||||
|
||||
// Check to see if this is a reply to an existing comment.
|
||||
const commentID = get(comment, 'id', null);
|
||||
if (commentID === null) {
|
||||
ctx.log.debug('could not get comment id');
|
||||
return;
|
||||
}
|
||||
|
||||
// Execute the graph request.
|
||||
const reply = await graphql(
|
||||
schema,
|
||||
`
|
||||
query GetAuthorUserMetadata($comment_id: ID!) {
|
||||
comment(id: $comment_id) {
|
||||
id
|
||||
user {
|
||||
id
|
||||
notificationSettings {
|
||||
onFeatured
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
{},
|
||||
ctx,
|
||||
{ comment_id: commentID }
|
||||
);
|
||||
if (reply.errors) {
|
||||
ctx.log.error({ err: reply.errors }, 'could not query for author metadata');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the user has notifications enabled.
|
||||
const enabled = get(
|
||||
reply,
|
||||
'data.comment.user.notificationSettings.onFeatured',
|
||||
false
|
||||
);
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const userID = get(reply, 'data.comment.user.id', null);
|
||||
if (!userID) {
|
||||
ctx.log.debug('could not get comment user id');
|
||||
return;
|
||||
}
|
||||
|
||||
// The user does have notifications for featured comments enabled, queue the
|
||||
// notification to be sent.
|
||||
return { userID, date: comment.created_at, context: comment.id };
|
||||
};
|
||||
|
||||
const hydrate = async (ctx, category, context) => {
|
||||
const { connectors: { graph: { schema } } } = ctx;
|
||||
|
||||
const reply = await graphql(
|
||||
schema,
|
||||
`
|
||||
query GetNotificationData($context: ID!) {
|
||||
comment(id: $context) {
|
||||
id
|
||||
asset {
|
||||
title
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
{},
|
||||
ctx,
|
||||
{ context }
|
||||
);
|
||||
if (reply.errors) {
|
||||
throw reply.errors;
|
||||
}
|
||||
|
||||
const comment = get(reply, 'data.comment');
|
||||
const headline = get(comment, 'asset.title', null);
|
||||
const assetURL = get(comment, 'asset.url', null);
|
||||
const permalink = `${assetURL}?commentId=${comment.id}`;
|
||||
|
||||
return [headline, permalink];
|
||||
};
|
||||
|
||||
const handler = {
|
||||
handle,
|
||||
category: 'featured',
|
||||
event: 'commentFeatured',
|
||||
hydrate,
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
typeDefs: `
|
||||
type NotificationSettings {
|
||||
onFeatured: Boolean!
|
||||
}
|
||||
|
||||
input NotificationSettingsInput {
|
||||
onFeatured: Boolean
|
||||
}
|
||||
`,
|
||||
resolvers: {
|
||||
NotificationSettings: {
|
||||
// onFeatured returns false by default if not specified.
|
||||
onFeatured: settings => get(settings, 'onFeatured', false),
|
||||
},
|
||||
},
|
||||
translations: path.join(__dirname, 'translations.yml'),
|
||||
notifications: [handler],
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
en:
|
||||
talk-plugin-notifications:
|
||||
categories:
|
||||
featured:
|
||||
subject: "One of your comments was featured on [{0}]"
|
||||
body: "{0}\nA member of our team has selected this comment to be featured for other readers: {1}"
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"extends": "@coralproject/eslint-config-talk"
|
||||
}
|
||||
@@ -37,7 +37,7 @@ class ToggleContainer extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<Toggle checked={this.getOnReplySetting()} onChange={this.toggle}>
|
||||
{t('talk-plugin-notifications-category-reply.toggle_description')}
|
||||
{t('talk-plugin-notifications-category-featured.toggle_description')}
|
||||
</Toggle>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@ en:
|
||||
talk-plugin-notifications:
|
||||
categories:
|
||||
reply:
|
||||
subject: "Some has replied to your comment on [{0}]"
|
||||
subject: "Someone has replied to your comment on [{0}]"
|
||||
body: "{0}\n{1} replied to your comment: {2}"
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"extends": "@coralproject/eslint-config-talk"
|
||||
}
|
||||
@@ -23,9 +23,9 @@ class SettingsContainer extends React.Component {
|
||||
hasNotifications: this.state.hasNotifications.filter(i => i !== plugin),
|
||||
});
|
||||
setTurnOffInputFragment = fragment =>
|
||||
this.setState({
|
||||
turnOffInput: { ...this.state.turnOffInput, ...fragment },
|
||||
});
|
||||
this.setState(state => ({
|
||||
turnOffInput: { ...state.turnOffInput, ...fragment },
|
||||
}));
|
||||
|
||||
turnOffAll = () => {
|
||||
this.props.updateNotificationSettings(this.state.turnOffInput);
|
||||
|
||||
Reference in New Issue
Block a user