Refactor state updater

This commit is contained in:
Chi Vinh Le
2017-06-15 18:28:08 +07:00
parent 3658a804b0
commit 5ecdfe94cc
2 changed files with 128 additions and 74 deletions
+99 -50
View File
@@ -1,62 +1,111 @@
import update from 'immutability-helper';
import * as notification from 'coral-admin/src/services/notification';
export function findCommentInModQueues(root, id, queues = ['all', 'premod', 'flagged', 'accepted', 'rejected']) {
return queues.reduce((comment, queue) => {
return comment ? comment : root[queue].nodes.find((c) => c.id === id);
}, null);
const queues = ['all', 'premod', 'flagged', 'accepted', 'rejected'];
const ascending = (a, b) => {
const dateA = new Date(a.created_at);
const dateB = new Date(b.created_at);
if (dateA < dateB) { return -1; }
if (dateA > dateB) { return 1; }
return 0;
};
const descending = (a, b) => -ascending(a, b);
function truncate(s, length = 10) {
return (s.length > length) ? `${s.substring(0, length)}...` : s;
}
export function handleCommentStatusChange(root, {id, status}, previousStatus) {
const comment = findCommentInModQueues(root, id);
if (!previousStatus && comment) {
previousStatus = comment.status;
}
function queueHasComment(root, queue, id) {
return root[queue].nodes.find((c) => c.id === id);
}
if (status === previousStatus) {
function removeCommentFromQueue(root, queue, id) {
if (!queueHasComment(root, queue, id)) {
return root;
}
let acceptedNodes = root.accepted.nodes;
let acceptedCount = root.acceptedCount;
let rejectedNodes = root.rejected.nodes;
let rejectedCount = root.rejectedCount;
if (status === 'ACCEPTED') {
acceptedCount++;
if (comment) {
acceptedNodes = [{...comment, status}, ...acceptedNodes];
}
}
else if (status === 'REJECTED') {
rejectedCount++;
if (comment) {
rejectedNodes = [{...comment, status}, ...rejectedNodes];
}
}
const premodNodes = root.premod.nodes.filter((c) => c.id !== id);
const flaggedNodes = root.flagged.nodes.filter((c) => c.id !== id);
const premodCount = premodNodes.length < root.premod.nodes.length ? root.premodCount - 1 : root.premodCount;
const flaggedCount = flaggedNodes.length < root.flagged.nodes.length ? root.flaggedCount - 1 : root.flaggedCount;
if (status === 'REJECTED') {
acceptedNodes = root.accepted.nodes.filter((c) => c.id !== id);
acceptedCount = acceptedNodes.length < root.accepted.nodes.length ? root.acceptedCount - 1 : root.acceptedCount;
}
else if (status === 'ACCEPTED') {
rejectedNodes = root.rejected.nodes.filter((c) => c.id !== id);
rejectedCount = rejectedNodes.length < root.rejected.nodes.length ? root.rejectedCount - 1 : root.rejectedCount;
}
return update(root, {
premodCount: {$set: Math.max(0, premodCount)},
flaggedCount: {$set: Math.max(0, flaggedCount)},
acceptedCount: {$set: Math.max(0, acceptedCount)},
rejectedCount: {$set: Math.max(0, rejectedCount)},
premod: {nodes: {$set: premodNodes}},
flagged: {nodes: {$set: flaggedNodes}},
accepted: {nodes: {$set: acceptedNodes}},
rejected: {nodes: {$set: rejectedNodes}},
[`${queue}Count`]: {$set: root[`${queue}Count`] - 1},
[queue]: {
nodes: {$apply: (nodes) => nodes.filter((c) => c.id !== id)},
},
});
}
function isCommentInCursor(root, queue, comment, sort) {
const cursor = new Date(root[queue].endCursor);
return sort === 'CHRONOLOGICAL'
? new Date(comment.created_at) <= cursor
: new Date(comment.created_at) >= cursor;
}
function addCommentToQueue(root, queue, comment, sort) {
if (queueHasComment(root, queue, comment.id)) {
return root;
}
const sortAlgo = sort === 'CHRONOLOGICAL' ? ascending : descending;
const changes = {
[`${queue}Count`]: {$set: root[`${queue}Count`] + 1},
};
if (isCommentInCursor(root, queue, comment, sort)) {
changes[queue] = {
nodes: {$apply: (nodes) => nodes.concat(comment).sort(sortAlgo)},
};
}
return update(root, changes);
}
function getCommentQueues(comment) {
const queues = ['all'];
if (comment.status === 'ACCEPTED') {
queues.push('accepted');
}
else if (comment.status === 'REJECTED') {
queues.push('rejected');
}
else if (comment.status === 'PREMOD') {
queues.push('premod');
}
if (
['NONE', 'PREMOD'].indexOf(comment.status) >= 0
&& comment.actions && comment.actions.some((a) => a.__typename === 'FlagAction')
) {
queues.push('flagged');
}
return queues;
}
function showNotification(queue, comment, user) {
const text = `${user.username} ${comment.status.toLowerCase()} comment "${truncate(comment.body, 50)}"`;
notification.info(text);
}
export function handleCommentStatusChange(root, comment, {sort, notify, user, activeQueue}) {
let next = root;
const nextQueues = getCommentQueues(comment);
queues.forEach((queue) => {
if (nextQueues.indexOf(queue) >= 0 && !queueHasComment(next, queue, comment.id)) {
next = addCommentToQueue(next, queue, comment, sort);
if (notify && activeQueue === queue && isCommentInCursor(next, queue, comment, sort)) {
showNotification(queue, comment, user);
}
} else if(queueHasComment(next, queue, comment.id)){
next = removeCommentFromQueue(next, queue, comment.id);
if (notify && activeQueue === queue) {
showNotification(queue, comment, user);
}
}
// TODO: All notification
// TODO: Flagged notification
// TODO: Edited notification
});
return next;
}
@@ -10,7 +10,7 @@ import t, {timeago} from 'coral-framework/services/i18n';
import update from 'immutability-helper';
import {withSetUserStatus, withSuspendUser, withSetCommentStatus} from 'coral-framework/graphql/mutations';
import {handleCommentStatusChange, findCommentInModQueues} from '../../../graphql/utils';
import {handleCommentStatusChange} from '../../../graphql/utils';
import {fetchSettings} from 'actions/settings';
import {updateAssets} from 'actions/assets';
@@ -31,10 +31,6 @@ import {Spinner} from 'coral-ui';
import Moderation from '../components/Moderation';
import Comment from './Comment';
function truncate(s, length = 10) {
return (s.length > length) ? `${s.substring(0, length)}...` : s;
}
class ModerationContainer extends Component {
unsubscribe = null;
@@ -47,25 +43,18 @@ class ModerationContainer extends Component {
asset_id: this.props.data.variables.asset_id,
},
updateQuery: (prev, {subscriptionData: {data: {commentStatusChanged: {user, comment, previous}}}}) => {
const activeTab = this.activeTab;
// Status changed was caused by a different user.
if (user && user.id !== this.props.auth.user.id) {
if (findCommentInModQueues(prev, comment.id) && (
activeTab === 'all' && findCommentInModQueues(prev, comment.id, ['all'])
|| activeTab === 'premod' && previous.status === 'PREMOD'
|| activeTab === 'flagged' && findCommentInModQueues(prev, comment.id, ['flagged'])
|| comment.status === 'ACCEPTED' && activeTab === 'accepted'
|| comment.status !== 'ACCEPTED' && previous.status === 'ACCEPTED' && activeTab === 'accepted'
|| comment.status === 'REJECTED' && activeTab === 'rejected'
|| comment.status !== 'REJECTED' && previous.status === 'REJECTED' && activeTab === 'rejected'
)
) {
const text = `${user.username} ${comment.status.toLowerCase()} comment "${truncate(comment.body, 50)}"`;
notification.info(text);
}
}
return handleCommentStatusChange(prev, comment, previous.status, user);
const extraParams = this.props.auth.user.id === user.id
? {}
: {
notify: true,
user,
activeQueue: this.activeTab,
previous,
};
return handleCommentStatusChange(prev, comment, {
sort: this.props.moderation.sortOrder,
...extraParams,
});
},
});
}
@@ -218,6 +207,22 @@ const STATUS_CHANGED_SUBSCRIPTION = gql`
id
status
body
created_at
action_summaries {
count
... on FlagActionSummary {
reason
}
}
actions {
... on FlagAction {
reason
message
user {
username
}
}
}
}
previous {
status