mirror of
https://github.com/wassname/talk.git
synced 2026-07-09 19:09:30 +08:00
replaced eslint:recommended with prettier
This commit is contained in:
@@ -1,2 +1,5 @@
|
||||
export {addTag, removeTag} from 'talk-plugin-commentbox/actions';
|
||||
export {addCommentClassName, removeCommentClassName} from 'coral-embed-stream/src/actions/stream';
|
||||
export { addTag, removeTag } from 'talk-plugin-commentbox/actions';
|
||||
export {
|
||||
addCommentClassName,
|
||||
removeCommentClassName,
|
||||
} from 'coral-embed-stream/src/actions/stream';
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export const commentBoxTagsSelector = (state) => state.commentBox.tags;
|
||||
export const commentClassNamesSelector = (state) => state.stream.commentClassNames;
|
||||
export const commentBoxTagsSelector = state => state.commentBox.tags;
|
||||
export const commentClassNamesSelector = state =>
|
||||
state.stream.commentClassNames;
|
||||
|
||||
@@ -1 +1 @@
|
||||
export {viewUserDetail} from 'coral-admin/src/actions/userDetail';
|
||||
export { viewUserDetail } from 'coral-admin/src/actions/userDetail';
|
||||
|
||||
@@ -1 +1 @@
|
||||
export {notify} from 'coral-framework/actions/notification';
|
||||
export { notify } from 'coral-framework/actions/notification';
|
||||
|
||||
@@ -1 +1 @@
|
||||
export {setSort} from 'coral-embed-stream/src/actions/stream';
|
||||
export { setSort } from 'coral-embed-stream/src/actions/stream';
|
||||
|
||||
@@ -19,7 +19,6 @@ export default class SortOption extends React.Component {
|
||||
}
|
||||
|
||||
SortOption.propTypes = {
|
||||
|
||||
// A simple callback to be called when clicking on this sort option.
|
||||
setSort: PropTypes.func.isRequired,
|
||||
|
||||
|
||||
@@ -1,10 +1,28 @@
|
||||
export {Slot} from 'coral-framework/components';
|
||||
export {default as ClickOutside} from 'coral-framework/components/ClickOutside';
|
||||
export {default as IfSlotIsEmpty} from 'coral-framework/components/IfSlotIsEmpty';
|
||||
export {default as IfSlotIsNotEmpty} from 'coral-framework/components/IfSlotIsNotEmpty';
|
||||
export {default as CommentAuthorName} from 'coral-framework/components/CommentAuthorName';
|
||||
export {default as CommentTimestamp} from 'coral-framework/components/CommentTimestamp';
|
||||
export {default as CommentDetail} from 'coral-framework/components/CommentDetail';
|
||||
export {default as CommentContent} from 'coral-framework/components/CommentContent';
|
||||
export {default as ConfigureCard} from 'coral-framework/components/ConfigureCard';
|
||||
export {default as StreamConfiguration} from 'coral-framework/components/StreamConfiguration';
|
||||
export { Slot } from 'coral-framework/components';
|
||||
export {
|
||||
default as ClickOutside,
|
||||
} from 'coral-framework/components/ClickOutside';
|
||||
export {
|
||||
default as IfSlotIsEmpty,
|
||||
} from 'coral-framework/components/IfSlotIsEmpty';
|
||||
export {
|
||||
default as IfSlotIsNotEmpty,
|
||||
} from 'coral-framework/components/IfSlotIsNotEmpty';
|
||||
export {
|
||||
default as CommentAuthorName,
|
||||
} from 'coral-framework/components/CommentAuthorName';
|
||||
export {
|
||||
default as CommentTimestamp,
|
||||
} from 'coral-framework/components/CommentTimestamp';
|
||||
export {
|
||||
default as CommentDetail,
|
||||
} from 'coral-framework/components/CommentDetail';
|
||||
export {
|
||||
default as CommentContent,
|
||||
} from 'coral-framework/components/CommentContent';
|
||||
export {
|
||||
default as ConfigureCard,
|
||||
} from 'coral-framework/components/ConfigureCard';
|
||||
export {
|
||||
default as StreamConfiguration,
|
||||
} from 'coral-framework/components/StreamConfiguration';
|
||||
|
||||
@@ -9,4 +9,5 @@ import SortOption from '../components/SortOption';
|
||||
* @param {string} sort.sortOrder
|
||||
* @return {Object} Component
|
||||
*/
|
||||
export const createSortOption = (label, sort) => withSortOption({...sort, label})(SortOption);
|
||||
export const createSortOption = (label, sort) =>
|
||||
withSortOption({ ...sort, label })(SortOption);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
export {default as withReaction} from './withReaction';
|
||||
export {default as withTags} from './withTags';
|
||||
export {default as withSortOption} from './withSortOption';
|
||||
export {default as withFragments} from 'coral-framework/hocs/withFragments';
|
||||
export {default as excludeIf} from 'coral-framework/hocs/excludeIf';
|
||||
export {default as connect} from 'coral-framework/hocs/connect';
|
||||
export {default as withEmit} from 'coral-framework/hocs/withEmit';
|
||||
export { default as withReaction } from './withReaction';
|
||||
export { default as withTags } from './withTags';
|
||||
export { default as withSortOption } from './withSortOption';
|
||||
export { default as withFragments } from 'coral-framework/hocs/withFragments';
|
||||
export { default as excludeIf } from 'coral-framework/hocs/excludeIf';
|
||||
export { default as connect } from 'coral-framework/hocs/connect';
|
||||
export { default as withEmit } from 'coral-framework/hocs/withEmit';
|
||||
export {
|
||||
withIgnoreUser,
|
||||
withBanUser,
|
||||
|
||||
@@ -1,22 +1,26 @@
|
||||
import React from 'react';
|
||||
import get from 'lodash/get';
|
||||
import uuid from 'uuid/v4';
|
||||
import {connect} from 'plugin-api/beta/client/hocs';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {getDisplayName} from 'coral-framework/helpers/hoc';
|
||||
import {compose, gql} from 'react-apollo';
|
||||
import { connect } from 'plugin-api/beta/client/hocs';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { getDisplayName } from 'coral-framework/helpers/hoc';
|
||||
import { compose, gql } from 'react-apollo';
|
||||
import withFragments from 'coral-framework/hocs/withFragments';
|
||||
import withMutation from 'coral-framework/hocs/withMutation';
|
||||
import {notify} from 'coral-framework/actions/notification';
|
||||
import {capitalize} from 'coral-framework/helpers/strings';
|
||||
import {getMyActionSummary, getTotalActionCount, getErrorMessages} from 'coral-framework/utils';
|
||||
import { notify } from 'coral-framework/actions/notification';
|
||||
import { capitalize } from 'coral-framework/helpers/strings';
|
||||
import {
|
||||
getMyActionSummary,
|
||||
getTotalActionCount,
|
||||
getErrorMessages,
|
||||
} from 'coral-framework/utils';
|
||||
import hoistStatics from 'recompose/hoistStatics';
|
||||
import * as PropTypes from 'prop-types';
|
||||
import {getDefinitionName} from '../utils';
|
||||
import {t, can} from 'plugin-api/beta/client/services';
|
||||
import { getDefinitionName } from '../utils';
|
||||
import { t, can } from 'plugin-api/beta/client/services';
|
||||
|
||||
// TODO: Auth logic needs refactoring.
|
||||
import {showSignInDialog} from 'coral-embed-stream/src/actions/auth';
|
||||
import { showSignInDialog } from 'coral-embed-stream/src/actions/auth';
|
||||
|
||||
/*
|
||||
* Disable false-positive warning below, as it doesn't work well with how we currently
|
||||
@@ -28,26 +32,27 @@ import {showSignInDialog} from 'coral-embed-stream/src/actions/auth';
|
||||
*/
|
||||
gql.disableFragmentWarnings();
|
||||
|
||||
export default (reaction, options = {}) => hoistStatics((WrappedComponent) => {
|
||||
if (typeof reaction !== 'string') {
|
||||
console.error('Reaction must be a valid string');
|
||||
return null;
|
||||
}
|
||||
export default (reaction, options = {}) =>
|
||||
hoistStatics(WrappedComponent => {
|
||||
if (typeof reaction !== 'string') {
|
||||
console.error('Reaction must be a valid string');
|
||||
return null;
|
||||
}
|
||||
|
||||
// fragments allow the extension of the fragments defined in this HOC.
|
||||
const {fragments = {}} = options;
|
||||
// fragments allow the extension of the fragments defined in this HOC.
|
||||
const { fragments = {} } = options;
|
||||
|
||||
// Global instance counter for each `reaction` type.
|
||||
let instances = 0;
|
||||
// Global instance counter for each `reaction` type.
|
||||
let instances = 0;
|
||||
|
||||
// Track current subscriptions.
|
||||
let createdSubscription = null;
|
||||
let deletedSubscription = null;
|
||||
// Track current subscriptions.
|
||||
let createdSubscription = null;
|
||||
let deletedSubscription = null;
|
||||
|
||||
reaction = reaction.toLowerCase();
|
||||
const Reaction = capitalize(reaction);
|
||||
reaction = reaction.toLowerCase();
|
||||
const Reaction = capitalize(reaction);
|
||||
|
||||
const COMMENT_FRAGMENT = gql`
|
||||
const COMMENT_FRAGMENT = gql`
|
||||
fragment ${Reaction}Button_updateFragment on Comment {
|
||||
action_summaries {
|
||||
... on ${Reaction}ActionSummary {
|
||||
@@ -60,99 +65,98 @@ export default (reaction, options = {}) => hoistStatics((WrappedComponent) => {
|
||||
}
|
||||
`;
|
||||
|
||||
const isReaction = (a) =>
|
||||
a.__typename === `${Reaction}ActionSummary`;
|
||||
const isReaction = a => a.__typename === `${Reaction}ActionSummary`;
|
||||
|
||||
const addReactionToStore = (proxy, {action, self}) => {
|
||||
const fragmentId = `Comment_${action.item_id}`;
|
||||
const addReactionToStore = (proxy, { action, self }) => {
|
||||
const fragmentId = `Comment_${action.item_id}`;
|
||||
|
||||
// Read the data from our cache for this query.
|
||||
const data = proxy.readFragment({
|
||||
fragment: COMMENT_FRAGMENT,
|
||||
id: fragmentId
|
||||
});
|
||||
|
||||
if (!data) {
|
||||
if (self) {
|
||||
throw new Error(`Comment ${action.item_id} was not found`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Add our comment from the mutation to the end.
|
||||
let idx = data.action_summaries.findIndex(isReaction);
|
||||
|
||||
// Check whether we already reactioned this comment.
|
||||
if (self && idx >= 0 && data.action_summaries[idx].current_user) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0) {
|
||||
|
||||
// Add initial action when it doesn't exist.
|
||||
data.action_summaries.push({
|
||||
__typename: `${Reaction}ActionSummary`,
|
||||
count: 0,
|
||||
current_user: null
|
||||
// Read the data from our cache for this query.
|
||||
const data = proxy.readFragment({
|
||||
fragment: COMMENT_FRAGMENT,
|
||||
id: fragmentId,
|
||||
});
|
||||
idx = data.action_summaries.length - 1;
|
||||
}
|
||||
|
||||
data.action_summaries[idx] = {
|
||||
...data.action_summaries[idx],
|
||||
count: data.action_summaries[idx].count + 1,
|
||||
current_user: self ? action : data.action_summaries[idx].current_user
|
||||
};
|
||||
|
||||
// Write our data back to the cache.
|
||||
proxy.writeFragment({
|
||||
fragment: COMMENT_FRAGMENT,
|
||||
id: fragmentId,
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
const deleteReactionFromStore = (proxy, {action, self}) => {
|
||||
const fragmentId = `Comment_${action.item_id}`;
|
||||
|
||||
// Read the data from our cache for this query.
|
||||
const data = proxy.readFragment({
|
||||
fragment: COMMENT_FRAGMENT,
|
||||
id: fragmentId
|
||||
});
|
||||
|
||||
if (!data) {
|
||||
if (self) {
|
||||
throw new Error(`Comment ${action.item_id} was not found`);
|
||||
if (!data) {
|
||||
if (self) {
|
||||
throw new Error(`Comment ${action.item_id} was not found`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check whether we liked this comment.
|
||||
const idx = data.action_summaries.findIndex(isReaction);
|
||||
// Add our comment from the mutation to the end.
|
||||
let idx = data.action_summaries.findIndex(isReaction);
|
||||
|
||||
if (
|
||||
self &&
|
||||
(idx < 0 || get(data.action_summaries[idx], 'current_user.id') !== action.id)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// Check whether we already reactioned this comment.
|
||||
if (self && idx >= 0 && data.action_summaries[idx].current_user) {
|
||||
return;
|
||||
}
|
||||
|
||||
data.action_summaries[idx] = {
|
||||
...data.action_summaries[idx],
|
||||
count: data.action_summaries[idx].count - 1,
|
||||
current_user: self ? null : data.action_summaries[idx].current_user,
|
||||
if (idx < 0) {
|
||||
// Add initial action when it doesn't exist.
|
||||
data.action_summaries.push({
|
||||
__typename: `${Reaction}ActionSummary`,
|
||||
count: 0,
|
||||
current_user: null,
|
||||
});
|
||||
idx = data.action_summaries.length - 1;
|
||||
}
|
||||
|
||||
data.action_summaries[idx] = {
|
||||
...data.action_summaries[idx],
|
||||
count: data.action_summaries[idx].count + 1,
|
||||
current_user: self ? action : data.action_summaries[idx].current_user,
|
||||
};
|
||||
|
||||
// Write our data back to the cache.
|
||||
proxy.writeFragment({
|
||||
fragment: COMMENT_FRAGMENT,
|
||||
id: fragmentId,
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
// Write our data back to the cache.
|
||||
proxy.writeFragment({
|
||||
fragment: COMMENT_FRAGMENT,
|
||||
id: fragmentId,
|
||||
data
|
||||
});
|
||||
};
|
||||
const deleteReactionFromStore = (proxy, { action, self }) => {
|
||||
const fragmentId = `Comment_${action.item_id}`;
|
||||
|
||||
const REACTION_CREATED_SUBSCRIPTION = gql`
|
||||
// Read the data from our cache for this query.
|
||||
const data = proxy.readFragment({
|
||||
fragment: COMMENT_FRAGMENT,
|
||||
id: fragmentId,
|
||||
});
|
||||
|
||||
if (!data) {
|
||||
if (self) {
|
||||
throw new Error(`Comment ${action.item_id} was not found`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check whether we liked this comment.
|
||||
const idx = data.action_summaries.findIndex(isReaction);
|
||||
|
||||
if (
|
||||
self &&
|
||||
(idx < 0 ||
|
||||
get(data.action_summaries[idx], 'current_user.id') !== action.id)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
data.action_summaries[idx] = {
|
||||
...data.action_summaries[idx],
|
||||
count: data.action_summaries[idx].count - 1,
|
||||
current_user: self ? null : data.action_summaries[idx].current_user,
|
||||
};
|
||||
|
||||
// Write our data back to the cache.
|
||||
proxy.writeFragment({
|
||||
fragment: COMMENT_FRAGMENT,
|
||||
id: fragmentId,
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
const REACTION_CREATED_SUBSCRIPTION = gql`
|
||||
subscription ${Reaction}ActionCreated($assetId: ID!) {
|
||||
${reaction}ActionCreated(asset_id: $assetId) {
|
||||
id
|
||||
@@ -164,7 +168,7 @@ export default (reaction, options = {}) => hoistStatics((WrappedComponent) => {
|
||||
}
|
||||
`;
|
||||
|
||||
const REACTION_DELETED_SUBSCRIPTION = gql`
|
||||
const REACTION_DELETED_SUBSCRIPTION = gql`
|
||||
subscription ${Reaction}ActionDeleted($assetId: ID!) {
|
||||
${reaction}ActionDeleted(asset_id: $assetId) {
|
||||
id
|
||||
@@ -176,156 +180,171 @@ export default (reaction, options = {}) => hoistStatics((WrappedComponent) => {
|
||||
}
|
||||
`;
|
||||
|
||||
class WithReactions extends React.Component {
|
||||
class WithReactions extends React.Component {
|
||||
static contextTypes = {
|
||||
client: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
client: PropTypes.object.isRequired,
|
||||
};
|
||||
// Whether or not a mutation is currently active.
|
||||
duringMutation = false;
|
||||
|
||||
// Whether or not a mutation is currently active.
|
||||
duringMutation = false;
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
// Start subscriptions when it is first needed.
|
||||
if (instances === 0) {
|
||||
createdSubscription = context.client
|
||||
.subscribe({
|
||||
query: REACTION_CREATED_SUBSCRIPTION,
|
||||
variables: {
|
||||
assetId: this.props.asset.id,
|
||||
},
|
||||
})
|
||||
.subscribe({
|
||||
next: this.onReactionCreated,
|
||||
error(err) {
|
||||
console.error('err', err);
|
||||
},
|
||||
});
|
||||
|
||||
// Start subscriptions when it is first needed.
|
||||
if (instances === 0) {
|
||||
createdSubscription = context.client.subscribe({
|
||||
query: REACTION_CREATED_SUBSCRIPTION,
|
||||
variables: {
|
||||
assetId: this.props.asset.id,
|
||||
},
|
||||
}).subscribe({
|
||||
next: this.onReactionCreated,
|
||||
error(err) { console.error('err', err); },
|
||||
});
|
||||
|
||||
deletedSubscription = context.client.subscribe({
|
||||
query: REACTION_DELETED_SUBSCRIPTION,
|
||||
variables: {
|
||||
assetId: this.props.asset.id,
|
||||
},
|
||||
}).subscribe({
|
||||
next: this.onReactionDeleted,
|
||||
error(err) { console.error('err', err); },
|
||||
});
|
||||
}
|
||||
instances++;
|
||||
}
|
||||
|
||||
// onReactionCreated handles live updates through the subscriptions.
|
||||
onReactionCreated = ({[`${reaction}ActionCreated`]: action}) => {
|
||||
if (this.props.user && action.user && this.props.user.id === action.user.id) {
|
||||
return;
|
||||
}
|
||||
addReactionToStore(this.context.client, {action, self: false});
|
||||
};
|
||||
|
||||
// onReactionDeleted handles live updates through the subscriptions.
|
||||
onReactionDeleted = ({[`${reaction}ActionDeleted`]: action}) => {
|
||||
if (this.props.user && action.user && this.props.user.id === action.user.id) {
|
||||
return;
|
||||
}
|
||||
deleteReactionFromStore(this.context.client, {action, self: false});
|
||||
};
|
||||
|
||||
componentWillUnmount() {
|
||||
instances--;
|
||||
|
||||
// End subscriptions when last component will be unmounted.
|
||||
if (instances === 0) {
|
||||
try {
|
||||
createdSubscription.unsubscribe();
|
||||
deletedSubscription.unsubscribe();
|
||||
deletedSubscription = context.client
|
||||
.subscribe({
|
||||
query: REACTION_DELETED_SUBSCRIPTION,
|
||||
variables: {
|
||||
assetId: this.props.asset.id,
|
||||
},
|
||||
})
|
||||
.subscribe({
|
||||
next: this.onReactionDeleted,
|
||||
error(err) {
|
||||
console.error('err', err);
|
||||
},
|
||||
});
|
||||
}
|
||||
catch(e) {
|
||||
console.warn(e);
|
||||
instances++;
|
||||
}
|
||||
|
||||
// onReactionCreated handles live updates through the subscriptions.
|
||||
onReactionCreated = ({ [`${reaction}ActionCreated`]: action }) => {
|
||||
if (
|
||||
this.props.user &&
|
||||
action.user &&
|
||||
this.props.user.id === action.user.id
|
||||
) {
|
||||
return;
|
||||
}
|
||||
addReactionToStore(this.context.client, { action, self: false });
|
||||
};
|
||||
|
||||
// onReactionDeleted handles live updates through the subscriptions.
|
||||
onReactionDeleted = ({ [`${reaction}ActionDeleted`]: action }) => {
|
||||
if (
|
||||
this.props.user &&
|
||||
action.user &&
|
||||
this.props.user.id === action.user.id
|
||||
) {
|
||||
return;
|
||||
}
|
||||
deleteReactionFromStore(this.context.client, { action, self: false });
|
||||
};
|
||||
|
||||
componentWillUnmount() {
|
||||
instances--;
|
||||
|
||||
// End subscriptions when last component will be unmounted.
|
||||
if (instances === 0) {
|
||||
try {
|
||||
createdSubscription.unsubscribe();
|
||||
deletedSubscription.unsubscribe();
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
postReaction = () => {
|
||||
if (this.duringMutation) {
|
||||
return;
|
||||
}
|
||||
this.duringMutation = true;
|
||||
|
||||
// If the current user is suspended, do nothing.
|
||||
if (!can(this.props.user, 'INTERACT_WITH_COMMUNITY')) {
|
||||
notify('error', t('error.NOT_AUTHORIZED'));
|
||||
return;
|
||||
}
|
||||
|
||||
return this.props
|
||||
.postReaction(this.props.comment)
|
||||
.then(result => {
|
||||
this.duringMutation = false;
|
||||
return result;
|
||||
})
|
||||
.catch(err => {
|
||||
this.duringMutation = false;
|
||||
this.props.notify('error', getErrorMessages(err));
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
|
||||
deleteReaction = () => {
|
||||
if (this.duringMutation) {
|
||||
return;
|
||||
}
|
||||
this.duringMutation = true;
|
||||
|
||||
// If the current user is suspended, do nothing.
|
||||
if (!can(this.props.user, 'INTERACT_WITH_COMMUNITY')) {
|
||||
notify('error', t('error.NOT_AUTHORIZED'));
|
||||
return;
|
||||
}
|
||||
|
||||
return this.props
|
||||
.deleteReaction(this.props.comment)
|
||||
.then(result => {
|
||||
this.duringMutation = false;
|
||||
return result;
|
||||
})
|
||||
.catch(err => {
|
||||
this.duringMutation = false;
|
||||
this.props.notify('error', getErrorMessages(err));
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { root, asset, comment } = this.props;
|
||||
|
||||
const reactionSummary = getMyActionSummary(
|
||||
`${Reaction}ActionSummary`,
|
||||
comment
|
||||
);
|
||||
|
||||
const count = getTotalActionCount(`${Reaction}ActionSummary`, comment);
|
||||
|
||||
const alreadyReacted = !!reactionSummary;
|
||||
|
||||
return (
|
||||
<WrappedComponent
|
||||
root={root}
|
||||
asset={asset}
|
||||
comment={comment}
|
||||
showSignInDialog={this.props.showSignInDialog}
|
||||
notify={this.props.notify}
|
||||
user={this.props.user}
|
||||
reactionSummary={reactionSummary}
|
||||
count={count}
|
||||
alreadyReacted={alreadyReacted}
|
||||
postReaction={this.postReaction}
|
||||
deleteReaction={this.deleteReaction}
|
||||
config={this.props.config}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
postReaction = () => {
|
||||
if (this.duringMutation) {
|
||||
return;
|
||||
}
|
||||
this.duringMutation = true;
|
||||
|
||||
// If the current user is suspended, do nothing.
|
||||
if (!can(this.props.user, 'INTERACT_WITH_COMMUNITY')) {
|
||||
notify('error', t('error.NOT_AUTHORIZED'));
|
||||
return;
|
||||
}
|
||||
|
||||
return this.props.postReaction(this.props.comment)
|
||||
.then((result) => {
|
||||
this.duringMutation = false;
|
||||
return result;
|
||||
})
|
||||
.catch((err) => {
|
||||
this.duringMutation = false;
|
||||
this.props.notify('error', getErrorMessages(err));
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
deleteReaction = () => {
|
||||
if (this.duringMutation) {
|
||||
return;
|
||||
}
|
||||
this.duringMutation = true;
|
||||
|
||||
// If the current user is suspended, do nothing.
|
||||
if (!can(this.props.user, 'INTERACT_WITH_COMMUNITY')) {
|
||||
notify('error', t('error.NOT_AUTHORIZED'));
|
||||
return;
|
||||
}
|
||||
|
||||
return this.props.deleteReaction(this.props.comment)
|
||||
.then((result) => {
|
||||
this.duringMutation = false;
|
||||
return result;
|
||||
})
|
||||
.catch((err) => {
|
||||
this.duringMutation = false;
|
||||
this.props.notify('error', getErrorMessages(err));
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {root, asset, comment} = this.props;
|
||||
|
||||
const reactionSummary = getMyActionSummary(
|
||||
`${Reaction}ActionSummary`,
|
||||
comment
|
||||
);
|
||||
|
||||
const count = getTotalActionCount(
|
||||
`${Reaction}ActionSummary`,
|
||||
comment
|
||||
);
|
||||
|
||||
const alreadyReacted = !!reactionSummary;
|
||||
|
||||
return <WrappedComponent
|
||||
root={root}
|
||||
asset={asset}
|
||||
comment={comment}
|
||||
showSignInDialog={this.props.showSignInDialog}
|
||||
notify={this.props.notify}
|
||||
user={this.props.user}
|
||||
reactionSummary={reactionSummary}
|
||||
count={count}
|
||||
alreadyReacted={alreadyReacted}
|
||||
postReaction={this.postReaction}
|
||||
deleteReaction={this.deleteReaction}
|
||||
config={this.props.config}
|
||||
/>;
|
||||
}
|
||||
}
|
||||
|
||||
const withDeleteReaction = withMutation(
|
||||
gql`
|
||||
const withDeleteReaction = withMutation(
|
||||
gql`
|
||||
mutation Delete${Reaction}Action($input: Delete${Reaction}ActionInput!) {
|
||||
delete${Reaction}Action(input: $input) {
|
||||
errors {
|
||||
@@ -334,38 +353,40 @@ export default (reaction, options = {}) => hoistStatics((WrappedComponent) => {
|
||||
}
|
||||
}
|
||||
`,
|
||||
{
|
||||
props: ({mutate}) => ({
|
||||
deleteReaction: (comment) => {
|
||||
{
|
||||
props: ({ mutate }) => ({
|
||||
deleteReaction: comment => {
|
||||
const reactionSummary = getMyActionSummary(
|
||||
`${Reaction}ActionSummary`,
|
||||
comment
|
||||
);
|
||||
|
||||
const reactionSummary = getMyActionSummary(
|
||||
`${Reaction}ActionSummary`,
|
||||
comment
|
||||
);
|
||||
const id = reactionSummary.current_user.id;
|
||||
const item_id = comment.id;
|
||||
|
||||
const id = reactionSummary.current_user.id;
|
||||
const item_id = comment.id;
|
||||
const input = { id };
|
||||
return mutate({
|
||||
variables: { input },
|
||||
optimisticResponse: {
|
||||
[`delete${Reaction}Action`]: {
|
||||
__typename: `Delete${Reaction}ActionResponse`,
|
||||
errors: null,
|
||||
},
|
||||
},
|
||||
update: proxy => {
|
||||
deleteReactionFromStore(proxy, {
|
||||
action: { item_id, id },
|
||||
self: true,
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
const input = {id};
|
||||
return mutate({
|
||||
variables: {input},
|
||||
optimisticResponse: {
|
||||
[`delete${Reaction}Action`]: {
|
||||
__typename: `Delete${Reaction}ActionResponse`,
|
||||
errors: null
|
||||
}
|
||||
},
|
||||
update: (proxy) => {
|
||||
deleteReactionFromStore(proxy, {action: {item_id, id}, self: true});
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
const withPostReaction = withMutation(
|
||||
gql`
|
||||
const withPostReaction = withMutation(
|
||||
gql`
|
||||
mutation Create${Reaction}Action($input: Create${Reaction}ActionInput!) {
|
||||
create${Reaction}Action(input: $input) {
|
||||
${reaction} {
|
||||
@@ -377,57 +398,61 @@ export default (reaction, options = {}) => hoistStatics((WrappedComponent) => {
|
||||
}
|
||||
}
|
||||
`,
|
||||
{
|
||||
props: ({mutate}) => ({
|
||||
postReaction: (comment) => {
|
||||
{
|
||||
props: ({ mutate }) => ({
|
||||
postReaction: comment => {
|
||||
const input = {
|
||||
item_id: comment.id,
|
||||
};
|
||||
|
||||
const input = {
|
||||
item_id: comment.id,
|
||||
};
|
||||
|
||||
return mutate({
|
||||
variables: {input},
|
||||
optimisticResponse: {
|
||||
[`create${Reaction}Action`]: {
|
||||
__typename: `Create${Reaction}ActionResponse`,
|
||||
errors: null,
|
||||
[reaction]: {
|
||||
__typename: `${Reaction}Action`,
|
||||
id: uuid()
|
||||
return mutate({
|
||||
variables: { input },
|
||||
optimisticResponse: {
|
||||
[`create${Reaction}Action`]: {
|
||||
__typename: `Create${Reaction}ActionResponse`,
|
||||
errors: null,
|
||||
[reaction]: {
|
||||
__typename: `${Reaction}Action`,
|
||||
id: uuid(),
|
||||
},
|
||||
},
|
||||
},
|
||||
update: (
|
||||
proxy,
|
||||
{
|
||||
data: { [`create${Reaction}Action`]: { [reaction]: action } },
|
||||
}
|
||||
}
|
||||
},
|
||||
update: (proxy, {data: {[`create${Reaction}Action`]: {[reaction]: action}}}) => {
|
||||
const a = {
|
||||
...action,
|
||||
item_id: input.item_id,
|
||||
};
|
||||
addReactionToStore(proxy, {action: a, self: true});
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
);
|
||||
) => {
|
||||
const a = {
|
||||
...action,
|
||||
item_id: input.item_id,
|
||||
};
|
||||
addReactionToStore(proxy, { action: a, self: true });
|
||||
},
|
||||
});
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
user: state.auth.user,
|
||||
});
|
||||
const mapStateToProps = state => ({
|
||||
user: state.auth.user,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) =>
|
||||
bindActionCreators({showSignInDialog, notify}, dispatch);
|
||||
const mapDispatchToProps = dispatch =>
|
||||
bindActionCreators({ showSignInDialog, notify }, dispatch);
|
||||
|
||||
const enhance = compose(
|
||||
withFragments({
|
||||
...fragments,
|
||||
asset: gql`
|
||||
const enhance = compose(
|
||||
withFragments({
|
||||
...fragments,
|
||||
asset: gql`
|
||||
fragment ${Reaction}Button_asset on Asset {
|
||||
id
|
||||
${fragments.asset ? `...${getDefinitionName(fragments.asset)}` : ''}
|
||||
}
|
||||
${fragments.asset ? fragments.asset : ''}
|
||||
`,
|
||||
comment: gql`
|
||||
comment: gql`
|
||||
fragment ${Reaction}Button_comment on Comment {
|
||||
id
|
||||
action_summaries {
|
||||
@@ -439,17 +464,23 @@ export default (reaction, options = {}) => hoistStatics((WrappedComponent) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
${fragments.comment ? `...${getDefinitionName(fragments.comment)}` : ''}
|
||||
${
|
||||
fragments.comment
|
||||
? `...${getDefinitionName(fragments.comment)}`
|
||||
: ''
|
||||
}
|
||||
}
|
||||
${fragments.comment ? fragments.comment : ''}
|
||||
`
|
||||
}),
|
||||
connect(mapStateToProps, mapDispatchToProps),
|
||||
withDeleteReaction,
|
||||
withPostReaction
|
||||
);
|
||||
`,
|
||||
}),
|
||||
connect(mapStateToProps, mapDispatchToProps),
|
||||
withDeleteReaction,
|
||||
withPostReaction
|
||||
);
|
||||
|
||||
WithReactions.displayName = `WithReactions(${getDisplayName(WrappedComponent)})`;
|
||||
WithReactions.displayName = `WithReactions(${getDisplayName(
|
||||
WrappedComponent
|
||||
)})`;
|
||||
|
||||
return enhance(WithReactions);
|
||||
});
|
||||
return enhance(WithReactions);
|
||||
});
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
import React from 'react';
|
||||
import {connect} from 'plugin-api/beta/client/hocs';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {sortOrderSelector, sortBySelector} from 'plugin-api/beta/client/selectors/stream';
|
||||
import {setSort} from 'plugin-api/beta/client/actions/stream';
|
||||
import { connect } from 'plugin-api/beta/client/hocs';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import {
|
||||
sortOrderSelector,
|
||||
sortBySelector,
|
||||
} from 'plugin-api/beta/client/selectors/stream';
|
||||
import { setSort } from 'plugin-api/beta/client/actions/stream';
|
||||
import hoistStatics from 'recompose/hoistStatics';
|
||||
import {closeMenu} from 'plugins/talk-plugin-viewing-options/client/actions';
|
||||
import { closeMenu } from 'plugins/talk-plugin-viewing-options/client/actions';
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
const mapStateToProps = state => ({
|
||||
sortOrder: sortOrderSelector(state),
|
||||
sortBy: sortBySelector(state),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) =>
|
||||
const mapDispatchToProps = dispatch =>
|
||||
bindActionCreators(
|
||||
{
|
||||
setSort,
|
||||
@@ -28,24 +31,26 @@ const mapDispatchToProps = (dispatch) =>
|
||||
* @param {string} sort.sortOrder
|
||||
* @return {Object} HOC
|
||||
*/
|
||||
export default ({sortBy = 'created_at', sortOrder = 'DESC', label}) => hoistStatics((WrappedComponent) => {
|
||||
class WithSortOption extends React.Component {
|
||||
setSort = () => {
|
||||
this.props.closeMenu();
|
||||
this.props.setSort({sortBy, sortOrder});
|
||||
}
|
||||
export default ({ sortBy = 'created_at', sortOrder = 'DESC', label }) =>
|
||||
hoistStatics(WrappedComponent => {
|
||||
class WithSortOption extends React.Component {
|
||||
setSort = () => {
|
||||
this.props.closeMenu();
|
||||
this.props.setSort({ sortBy, sortOrder });
|
||||
};
|
||||
|
||||
render() {
|
||||
const active = this.props.sortOrder === sortOrder && this.props.sortBy === sortBy;
|
||||
const resolvedLabel = typeof label === 'function' ? label() : label;
|
||||
return (
|
||||
<WrappedComponent
|
||||
active={active}
|
||||
setSort={this.setSort}
|
||||
label={resolvedLabel}
|
||||
/>
|
||||
);
|
||||
render() {
|
||||
const active =
|
||||
this.props.sortOrder === sortOrder && this.props.sortBy === sortBy;
|
||||
const resolvedLabel = typeof label === 'function' ? label() : label;
|
||||
return (
|
||||
<WrappedComponent
|
||||
active={active}
|
||||
setSort={this.setSort}
|
||||
label={resolvedLabel}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return connect(mapStateToProps, mapDispatchToProps)(WithSortOption);
|
||||
});
|
||||
return connect(mapStateToProps, mapDispatchToProps)(WithSortOption);
|
||||
});
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import React from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {compose, gql} from 'react-apollo';
|
||||
import {getDisplayName} from 'coral-framework/helpers/hoc';
|
||||
import {capitalize} from 'coral-framework/helpers/strings';
|
||||
import {withAddTag, withRemoveTag} from 'coral-framework/graphql/mutations';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { compose, gql } from 'react-apollo';
|
||||
import { getDisplayName } from 'coral-framework/helpers/hoc';
|
||||
import { capitalize } from 'coral-framework/helpers/strings';
|
||||
import { withAddTag, withRemoveTag } from 'coral-framework/graphql/mutations';
|
||||
import withFragments from 'coral-framework/hocs/withFragments';
|
||||
import {notify} from 'coral-framework/actions/notification';
|
||||
import {getErrorMessages, isTagged} from 'coral-framework/utils';
|
||||
import { notify } from 'coral-framework/actions/notification';
|
||||
import { getErrorMessages, isTagged } from 'coral-framework/utils';
|
||||
import hoistStatics from 'recompose/hoistStatics';
|
||||
import {getDefinitionName} from '../utils';
|
||||
import { getDefinitionName } from '../utils';
|
||||
|
||||
/*
|
||||
* Disable false-positive warning below, as it doesn't work well with how we currently
|
||||
@@ -21,108 +21,113 @@ import {getDefinitionName} from '../utils';
|
||||
*/
|
||||
gql.disableFragmentWarnings();
|
||||
|
||||
export default (tag, options = {}) => hoistStatics((WrappedComponent) => {
|
||||
if (typeof tag !== 'string') {
|
||||
console.error('Tag must be a valid string');
|
||||
return null;
|
||||
}
|
||||
export default (tag, options = {}) =>
|
||||
hoistStatics(WrappedComponent => {
|
||||
if (typeof tag !== 'string') {
|
||||
console.error('Tag must be a valid string');
|
||||
return null;
|
||||
}
|
||||
|
||||
// fragments allow the extension of the fragments defined in this HOC.
|
||||
const {fragments = {}} = options;
|
||||
// fragments allow the extension of the fragments defined in this HOC.
|
||||
const { fragments = {} } = options;
|
||||
|
||||
const Tag = capitalize(tag);
|
||||
const TAG = tag.toUpperCase();
|
||||
const Tag = capitalize(tag);
|
||||
const TAG = tag.toUpperCase();
|
||||
|
||||
class WithTags extends React.Component {
|
||||
loading = false;
|
||||
class WithTags extends React.Component {
|
||||
loading = false;
|
||||
|
||||
postTag = () => {
|
||||
const {comment, asset, notify} = this.props;
|
||||
postTag = () => {
|
||||
const { comment, asset, notify } = this.props;
|
||||
|
||||
if (this.loading) {
|
||||
return;
|
||||
if (this.loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.loading = true;
|
||||
|
||||
return this.props
|
||||
.addTag({
|
||||
id: comment.id,
|
||||
name: TAG,
|
||||
assetId: asset.id,
|
||||
itemType: 'COMMENTS',
|
||||
})
|
||||
.then(result => {
|
||||
this.loading = false;
|
||||
return result;
|
||||
})
|
||||
.catch(err => {
|
||||
this.loading = false;
|
||||
notify('error', getErrorMessages(err));
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
|
||||
deleteTag = () => {
|
||||
const { comment, asset, notify } = this.props;
|
||||
|
||||
if (this.loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.props
|
||||
.removeTag({
|
||||
id: comment.id,
|
||||
name: TAG,
|
||||
assetId: asset.id,
|
||||
itemType: 'COMMENTS',
|
||||
})
|
||||
.then(result => {
|
||||
this.loading = false;
|
||||
return result;
|
||||
})
|
||||
.catch(err => {
|
||||
this.loading = false;
|
||||
notify('error', getErrorMessages(err));
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { root, asset, comment, user, config, ...rest } = this.props;
|
||||
|
||||
const alreadyTagged = isTagged(comment.tags, TAG);
|
||||
|
||||
return (
|
||||
<WrappedComponent
|
||||
{...rest}
|
||||
root={root}
|
||||
asset={asset}
|
||||
comment={comment}
|
||||
user={user}
|
||||
alreadyTagged={alreadyTagged}
|
||||
postTag={this.postTag}
|
||||
deleteTag={this.deleteTag}
|
||||
config={config}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
this.loading = true;
|
||||
|
||||
return this.props.addTag({
|
||||
id: comment.id,
|
||||
name: TAG,
|
||||
assetId: asset.id,
|
||||
itemType: 'COMMENTS',
|
||||
})
|
||||
.then((result) => {
|
||||
this.loading = false;
|
||||
return result;
|
||||
})
|
||||
.catch((err) => {
|
||||
this.loading = false;
|
||||
notify('error', getErrorMessages(err));
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
deleteTag = () => {
|
||||
const {comment, asset, notify} = this.props;
|
||||
const mapStateToProps = state => ({
|
||||
user: state.auth.user,
|
||||
});
|
||||
|
||||
if (this.loading) {
|
||||
return;
|
||||
}
|
||||
const mapDispatchToProps = dispatch =>
|
||||
bindActionCreators({ notify }, dispatch);
|
||||
|
||||
this.props.removeTag({
|
||||
id: comment.id,
|
||||
name: TAG,
|
||||
assetId: asset.id,
|
||||
itemType: 'COMMENTS',
|
||||
})
|
||||
.then((result) => {
|
||||
this.loading = false;
|
||||
return result;
|
||||
})
|
||||
.catch((err) => {
|
||||
this.loading = false;
|
||||
notify('error', getErrorMessages(err));
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {root, asset, comment, user, config, ...rest} = this.props;
|
||||
|
||||
const alreadyTagged = isTagged(comment.tags, TAG);
|
||||
|
||||
return <WrappedComponent
|
||||
{...rest}
|
||||
root={root}
|
||||
asset={asset}
|
||||
comment={comment}
|
||||
user={user}
|
||||
alreadyTagged={alreadyTagged}
|
||||
postTag={this.postTag}
|
||||
deleteTag={this.deleteTag}
|
||||
config={config}
|
||||
/>;
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
user: state.auth.user,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) =>
|
||||
bindActionCreators({notify}, dispatch);
|
||||
|
||||
const enhance = compose(
|
||||
withFragments({
|
||||
...fragments,
|
||||
asset: gql`
|
||||
const enhance = compose(
|
||||
withFragments({
|
||||
...fragments,
|
||||
asset: gql`
|
||||
fragment ${Tag}Button_asset on Asset {
|
||||
id
|
||||
${fragments.asset ? `...${getDefinitionName(fragments.asset)}` : ''}
|
||||
}
|
||||
${fragments.asset ? fragments.asset : ''}
|
||||
`,
|
||||
comment: gql`
|
||||
comment: gql`
|
||||
fragment ${Tag}Button_comment on Comment {
|
||||
id
|
||||
tags {
|
||||
@@ -130,17 +135,21 @@ export default (tag, options = {}) => hoistStatics((WrappedComponent) => {
|
||||
name
|
||||
}
|
||||
}
|
||||
${fragments.comment ? `...${getDefinitionName(fragments.comment)}` : ''}
|
||||
${
|
||||
fragments.comment
|
||||
? `...${getDefinitionName(fragments.comment)}`
|
||||
: ''
|
||||
}
|
||||
}
|
||||
${fragments.comment ? fragments.comment : ''}
|
||||
`
|
||||
}),
|
||||
withAddTag,
|
||||
withRemoveTag,
|
||||
connect(mapStateToProps, mapDispatchToProps),
|
||||
);
|
||||
`,
|
||||
}),
|
||||
withAddTag,
|
||||
withRemoveTag,
|
||||
connect(mapStateToProps, mapDispatchToProps)
|
||||
);
|
||||
|
||||
WithTags.displayName = `WithTags(${getDisplayName(WrappedComponent)})`;
|
||||
WithTags.displayName = `WithTags(${getDisplayName(WrappedComponent)})`;
|
||||
|
||||
return enhance(WithTags);
|
||||
});
|
||||
return enhance(WithTags);
|
||||
});
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const pluginConfigSelector = (state) => state.config.pluginConfig;
|
||||
export const pluginConfigSelector = state => state.config.pluginConfig;
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export const sortOrderSelector = (state) => state.stream.sortOrder;
|
||||
export const sortBySelector = (state) => state.stream.sortBy;
|
||||
export const sortOrderSelector = state => state.stream.sortOrder;
|
||||
export const sortBySelector = state => state.stream.sortBy;
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
export {t, timeago} from 'coral-framework/services/i18n';
|
||||
export {can} from 'coral-framework/services/perms';
|
||||
|
||||
export { t, timeago } from 'coral-framework/services/i18n';
|
||||
export { can } from 'coral-framework/services/perms';
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
const {SEARCH_OTHER_USERS} = require('../../../perms/constants');
|
||||
const { SEARCH_OTHER_USERS } = require('../../../perms/constants');
|
||||
const errors = require('../../../errors');
|
||||
const pluralize = require('pluralize');
|
||||
const sc = require('snake-case');
|
||||
const CommentModel = require('../../../models/comment');
|
||||
const {CREATE_MONGO_INDEXES} = require('../../../config');
|
||||
const { CREATE_MONGO_INDEXES } = require('../../../config');
|
||||
|
||||
function getReactionConfig(reaction) {
|
||||
reaction = reaction.toLowerCase();
|
||||
|
||||
if (CREATE_MONGO_INDEXES) {
|
||||
|
||||
// Create the index on the comment model based on the reaction config.
|
||||
CommentModel.collection.createIndex({
|
||||
created_at: 1,
|
||||
[`action_counts.${sc(reaction)}`]: 1
|
||||
}, {
|
||||
background: true,
|
||||
});
|
||||
CommentModel.collection.createIndex(
|
||||
{
|
||||
created_at: 1,
|
||||
[`action_counts.${sc(reaction)}`]: 1,
|
||||
},
|
||||
{
|
||||
background: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const reactionPlural = pluralize(reaction);
|
||||
@@ -126,32 +128,39 @@ function getReactionConfig(reaction) {
|
||||
|
||||
return {
|
||||
typeDefs,
|
||||
schemas: ({CommentSchema}) => {
|
||||
CommentSchema.index({
|
||||
'created_at': 1,
|
||||
[`action_counts.${sc(reaction)}`]: 1,
|
||||
}, {
|
||||
background: true,
|
||||
});
|
||||
schemas: ({ CommentSchema }) => {
|
||||
CommentSchema.index(
|
||||
{
|
||||
created_at: 1,
|
||||
[`action_counts.${sc(reaction)}`]: 1,
|
||||
},
|
||||
{
|
||||
background: true,
|
||||
}
|
||||
);
|
||||
},
|
||||
context: {
|
||||
Sort: () => ({
|
||||
Comments: {
|
||||
[reactionPlural]: {
|
||||
startCursor(ctx, nodes, {cursor}) {
|
||||
|
||||
startCursor(ctx, nodes, { cursor }) {
|
||||
// The cursor is the start! This is using numeric pagination.
|
||||
return cursor != null ? cursor : 0;
|
||||
},
|
||||
endCursor(ctx, nodes, {cursor}) {
|
||||
return nodes.length ? (cursor != null ? cursor : 0) + nodes.length : null;
|
||||
endCursor(ctx, nodes, { cursor }) {
|
||||
return nodes.length
|
||||
? (cursor != null ? cursor : 0) + nodes.length
|
||||
: null;
|
||||
},
|
||||
sort(ctx, query, {cursor, sortOrder}) {
|
||||
sort(ctx, query, { cursor, sortOrder }) {
|
||||
if (cursor) {
|
||||
query = query.skip(cursor);
|
||||
}
|
||||
|
||||
return query.sort({[`action_counts.${reaction}`]: sortOrder === 'DESC' ? -1 : 1, created_at: sortOrder === 'DESC' ? -1 : 1});
|
||||
return query.sort({
|
||||
[`action_counts.${reaction}`]: sortOrder === 'DESC' ? -1 : 1,
|
||||
created_at: sortOrder === 'DESC' ? -1 : 1,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -159,37 +168,43 @@ function getReactionConfig(reaction) {
|
||||
},
|
||||
resolvers: {
|
||||
Subscription: {
|
||||
[`${reaction}ActionCreated`]: ({action}) => {
|
||||
[`${reaction}ActionCreated`]: ({ action }) => {
|
||||
return action;
|
||||
},
|
||||
[`${reaction}ActionDeleted`]: ({action}) => {
|
||||
[`${reaction}ActionDeleted`]: ({ action }) => {
|
||||
return action;
|
||||
},
|
||||
},
|
||||
[`${Reaction}Action`]: {
|
||||
|
||||
// This will load the user for the specific action. We'll limit this to the
|
||||
// admin users only or the current logged in user.
|
||||
user({user_id}, _, {loaders: {Users}, user}) {
|
||||
user({ user_id }, _, { loaders: { Users }, user }) {
|
||||
if (user && (user.can(SEARCH_OTHER_USERS) || user_id === user.id)) {
|
||||
return Users.getByID.load(user_id);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
RootMutation: {
|
||||
[`create${Reaction}Action`]: async (_, {input: {item_id}}, {mutators: {Action}, pubsub, loaders: {Comments}}) => {
|
||||
[`create${Reaction}Action`]: async (
|
||||
_,
|
||||
{ input: { item_id } },
|
||||
{ mutators: { Action }, pubsub, loaders: { Comments } }
|
||||
) => {
|
||||
const comment = await Comments.get.load(item_id);
|
||||
if (!comment) {
|
||||
throw errors.ErrNotFound;
|
||||
}
|
||||
|
||||
try {
|
||||
const action = await Action.create({item_id, item_type: 'COMMENTS', action_type: REACTION});
|
||||
const action = await Action.create({
|
||||
item_id,
|
||||
item_type: 'COMMENTS',
|
||||
action_type: REACTION,
|
||||
});
|
||||
|
||||
if (pubsub) {
|
||||
|
||||
// The comment is needed to allow better filtering e.g. by asset_id.
|
||||
pubsub.publish(`${reaction}ActionCreated`, {action, comment});
|
||||
pubsub.publish(`${reaction}ActionCreated`, { action, comment });
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -203,17 +218,20 @@ function getReactionConfig(reaction) {
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
[`delete${Reaction}Action`]: async (_, {input: {id}}, {mutators: {Action}, pubsub, loaders: {Comments}}) => {
|
||||
const action = await Action.delete({id});
|
||||
[`delete${Reaction}Action`]: async (
|
||||
_,
|
||||
{ input: { id } },
|
||||
{ mutators: { Action }, pubsub, loaders: { Comments } }
|
||||
) => {
|
||||
const action = await Action.delete({ id });
|
||||
if (!action) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const comment = await Comments.get.load(action.item_id);
|
||||
if (pubsub) {
|
||||
|
||||
// The comment is needed to allow better filtering e.g. by asset_id.
|
||||
pubsub.publish(`${reaction}ActionDeleted`, {action, comment});
|
||||
pubsub.publish(`${reaction}ActionDeleted`, { action, comment });
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -221,34 +239,38 @@ function getReactionConfig(reaction) {
|
||||
hooks: {
|
||||
Action: {
|
||||
__resolveType: {
|
||||
post({action_type}) {
|
||||
post({ action_type }) {
|
||||
switch (action_type) {
|
||||
case REACTION:
|
||||
return `${Reaction}Action`;
|
||||
case REACTION:
|
||||
return `${Reaction}Action`;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
ActionSummary: {
|
||||
__resolveType: {
|
||||
post({action_type}) {
|
||||
post({ action_type }) {
|
||||
switch (action_type) {
|
||||
case REACTION:
|
||||
return `${Reaction}ActionSummary`;
|
||||
case REACTION:
|
||||
return `${Reaction}ActionSummary`;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
setupFunctions: {
|
||||
[`${reaction}ActionCreated`]: (options, args) => ({
|
||||
[`${reaction}ActionCreated`]: {
|
||||
filter: ({comment}) => comment.asset_id === args.asset_id,
|
||||
filter: ({ comment }) => comment.asset_id === args.asset_id,
|
||||
},
|
||||
}),
|
||||
[`${reaction}ActionDeleted`]: (options, args) => ({
|
||||
[`${reaction}ActionDeleted`]: {
|
||||
filter: ({comment}) => comment.asset_id === args.asset_id,
|
||||
filter: ({ comment }) => comment.asset_id === args.asset_id,
|
||||
},
|
||||
}),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user