Implement activity tracking for flagged accounts

This commit is contained in:
Chi Vinh Le
2018-01-24 23:31:31 +01:00
parent d101989ebd
commit 1fc07e8649
9 changed files with 217 additions and 27 deletions
@@ -11,6 +11,7 @@ import {
HIDE_BANUSER_DIALOG,
SHOW_REJECT_USERNAME_DIALOG,
HIDE_REJECT_USERNAME_DIALOG,
SET_INDICATOR_TRACK,
} from '../constants/community';
import t from 'coral-framework/services/i18n';
@@ -68,3 +69,8 @@ export const showRejectUsernameDialog = user => ({
export const hideRejectUsernameDialog = () => ({
type: HIDE_REJECT_USERNAME_DIALOG,
});
export const setIndicatorTrack = track => ({
type: SET_INDICATOR_TRACK,
track,
});
+4 -2
View File
@@ -15,6 +15,7 @@ const CoralHeader = ({
showShortcuts = () => {},
auth,
root,
data,
}) => {
return (
<div className={styles.headerWrapper}>
@@ -31,7 +32,7 @@ const CoralHeader = ({
activeClassName={styles.active}
>
{t('configure.moderate')}
<ModerationIndicator root={root} />
<ModerationIndicator root={root} data={data} />
</IndexLink>
)}
<Link
@@ -50,7 +51,7 @@ const CoralHeader = ({
activeClassName={styles.active}
>
{t('configure.community')}
<CommunityIndicator root={root} />
<CommunityIndicator root={root} data={data} />
</Link>
{can(auth.user, 'UPDATE_CONFIG') && (
@@ -119,6 +120,7 @@ CoralHeader.propTypes = {
showShortcuts: PropTypes.func,
handleLogout: PropTypes.func.isRequired,
root: PropTypes.object.isRequired,
data: PropTypes.object.isRequired,
};
export default CoralHeader;
@@ -18,3 +18,5 @@ export const SHOW_REJECT_USERNAME_DIALOG = `${prefix}_SHOW_REJECT_USERNAME_DIALO
export const HIDE_REJECT_USERNAME_DIALOG = `${prefix}_HIDE_REJECT_USERNAME_DIALOG`;
export const SET_SEARCH_VALUE = `${prefix}_SET_SEARCH_VALUE`;
export const SET_INDICATOR_TRACK = `${prefix}_SET_INDICATOR_TRACK`;
+1 -6
View File
@@ -13,10 +13,5 @@ export default withQuery(
}
${ModerationIndicator.fragments.root}
${CommunityIndicator.fragments.root}
`,
{
options: {
pollInterval: 10000,
},
}
`
)(Header);
+12 -4
View File
@@ -173,13 +173,17 @@ export default {
},
updateQueries: {
TalkAdmin_Community_FlaggedAccounts: (prev, { mutationResult }) => {
const decrement = {
flaggedUsernamesCount: { $apply: count => count - 1 },
};
// Remove from list after the mutation was "really" completed.
if (get(mutationResult, 'data.approveUsername.isOptimistic')) {
return prev;
return update(prev, decrement);
}
const updated = update(prev, {
flaggedUsernamesCount: { $apply: count => count - 1 },
...decrement,
flaggedUsers: {
nodes: { $apply: nodes => nodes.filter(node => node.id !== id) },
},
@@ -227,13 +231,17 @@ export default {
},
updateQueries: {
TalkAdmin_Community_FlaggedAccounts: (prev, { mutationResult }) => {
const decrement = {
flaggedUsernamesCount: { $apply: count => count - 1 },
};
// Remove from list after the mutation was "really" completed.
if (get(mutationResult, 'data.rejectUsername.isOptimistic')) {
return prev;
return update(prev, decrement);
}
const updated = update(prev, {
flaggedUsernamesCount: { $apply: count => count - 1 },
...decrement,
flaggedUsers: {
nodes: {
$apply: nodes => nodes.filter(node => node.id !== id),
@@ -9,6 +9,7 @@ import {
HIDE_BANUSER_DIALOG,
SHOW_REJECT_USERNAME_DIALOG,
HIDE_REJECT_USERNAME_DIALOG,
SET_INDICATOR_TRACK,
} from '../constants/community';
const initialState = {
@@ -24,6 +25,10 @@ const initialState = {
user: {},
banDialog: false,
rejectUsernameDialog: false,
// If true the activity indicator will track flagged account changes
// in order to determine the current queue count. Set this to false
// if the queue count is determined by other means.
indicatorTrack: true,
};
export default function community(state = initialState, action) {
@@ -91,6 +96,11 @@ export default function community(state = initialState, action) {
...state,
searchValue: action.value,
};
case SET_INDICATOR_TRACK:
return {
...state,
indicatorTrack: action.track,
};
default:
return state;
}
@@ -6,12 +6,15 @@ import withQuery from 'coral-framework/hocs/withQuery';
import { Spinner } from 'coral-ui';
import PropTypes from 'prop-types';
import { withApproveUsername } from 'coral-framework/graphql/mutations';
import { showRejectUsernameDialog } from '../../../actions/community';
import {
showRejectUsernameDialog,
setIndicatorTrack,
} from '../../../actions/community';
import { viewUserDetail } from '../../../actions/userDetail';
import { getDefinitionName } from 'coral-framework/utils';
import { appendNewNodes } from 'plugin-api/beta/client/utils';
import update from 'immutability-helper';
import { handleFlaggedUsernameChange } from '../graphql';
import { handleFlaggedAccountsChange } from '../graphql';
import { notify } from 'coral-framework/actions/notification';
import { isFlaggedUserDangling } from '../utils';
import t from 'coral-framework/services/i18n';
@@ -50,7 +53,7 @@ class FlaggedAccountsContainer extends Component {
prev,
{ subscriptionData: { data: { usernameFlagged: user } } }
) => {
return handleFlaggedUsernameChange(prev, user, () => {
return handleFlaggedAccountsChange(prev, user, () => {
const msg = t(
'flagged_usernames.notify_flagged',
whoFlagged(user),
@@ -66,7 +69,7 @@ class FlaggedAccountsContainer extends Component {
prev,
{ subscriptionData: { data: { usernameApproved: user } } }
) => {
return handleFlaggedUsernameChange(prev, user, () => {
return handleFlaggedAccountsChange(prev, user, () => {
const msg = t(
'flagged_usernames.notify_approved',
whoChangedTheStatus(user.state.status.username),
@@ -82,7 +85,7 @@ class FlaggedAccountsContainer extends Component {
prev,
{ subscriptionData: { data: { usernameRejected: user } } }
) => {
return handleFlaggedUsernameChange(prev, user, () => {
return handleFlaggedAccountsChange(prev, user, () => {
const msg = t(
'flagged_usernames.notify_rejected',
whoChangedTheStatus(user.state.status.username),
@@ -102,7 +105,7 @@ class FlaggedAccountsContainer extends Component {
},
}
) => {
return handleFlaggedUsernameChange(prev, user, () => {
return handleFlaggedAccountsChange(prev, user, () => {
const msg = t(
'flagged_usernames.notify_changed',
previousUsername,
@@ -125,10 +128,14 @@ class FlaggedAccountsContainer extends Component {
}
componentWillMount() {
// Stop activity indicator tracking, as we'll handle it here.
this.props.setIndicatorTrack(false);
this.subscribeToUpdates();
}
componentWillUnmount() {
// Restart activity indicator tracking.
this.props.setIndicatorTrack(true);
this.unsubscribe();
}
@@ -197,6 +204,7 @@ FlaggedAccountsContainer.propTypes = {
approveUsername: PropTypes.func,
data: PropTypes.object,
root: PropTypes.object,
setIndicatorTrack: PropTypes.func,
};
const LOAD_MORE_QUERY = gql`
@@ -288,6 +296,7 @@ const mapDispatchToProps = dispatch =>
showRejectUsernameDialog,
viewUserDetail,
notify,
setIndicatorTrack,
},
dispatch
);
@@ -1,24 +1,164 @@
import React, { Component } from 'react';
import { compose, gql } from 'react-apollo';
import Indicator from '../../../components/Indicator';
import { withFragments } from 'plugin-api/beta/client/hocs';
import { branch, renderNothing } from 'recompose';
import { handleIndicatorChange } from '../graphql';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
const hideIfNoData = hasNoData => branch(hasNoData, renderNothing);
class IndicatorContainer extends Component {
subscriptions = [];
subscribeToUpdates() {
const parameters = [
{
document: USERNAME_FLAGGED_SUBSCRIPTION,
updateQuery: (
prev,
{ subscriptionData: { data: { usernameFlagged: user } } }
) => {
return handleIndicatorChange(prev, user);
},
},
{
document: USERNAME_APPROVED_SUBSCRIPTION,
updateQuery: (
prev,
{ subscriptionData: { data: { usernameApproved: user } } }
) => {
return handleIndicatorChange(prev, user);
},
},
{
document: USERNAME_REJECTED_SUBSCRIPTION,
updateQuery: (
prev,
{ subscriptionData: { data: { usernameRejected: user } } }
) => {
return handleIndicatorChange(prev, user);
},
},
{
document: USERNAME_CHANGED_SUBSCRIPTION,
updateQuery: (
prev,
{ subscriptionData: { data: { usernameChanged: { user } } } }
) => {
return handleIndicatorChange(prev, user);
},
},
];
this.subscriptions = parameters.map(param =>
this.props.data.subscribeToMore(param)
);
}
unsubscribe() {
this.subscriptions.forEach(unsubscribe => unsubscribe());
this.subscriptions = [];
}
componentWillMount() {
if (this.props.track) {
this.subscribeToUpdates();
}
}
componentWillUnmount() {
this.unsubscribe();
}
componentWillReceiveProps(nextProps) {
if (!this.props.track && nextProps.track) {
this.subscribeToUpdates();
}
if (this.props.track && !nextProps.track) {
this.unsubscribe();
}
}
render() {
if (!this.props.root || !this.props.root.flaggedUsernamesCount) {
return null;
}
return <Indicator />;
}
}
IndicatorContainer.propTypes = {
data: PropTypes.object,
root: PropTypes.object,
track: PropTypes.bool,
};
const fields = `
state {
status {
username {
status
}
}
}
`;
const USERNAME_FLAGGED_SUBSCRIPTION = gql`
subscription TalkAdmin_CommunityIndicator_UsernameFlagged {
usernameFlagged {
${fields}
}
}
`;
const USERNAME_APPROVED_SUBSCRIPTION = gql`
subscription TalkAdmin_ComunityIndicator_UsernameApproved {
usernameApproved {
${fields}
}
}
`;
const USERNAME_REJECTED_SUBSCRIPTION = gql`
subscription TalkAdmin_CommunityIndicator_UsernameRejected {
usernameRejected {
${fields}
}
}
`;
const USERNAME_CHANGED_SUBSCRIPTION = gql`
subscription TalkAdmin_ComunityIndicator_UsernameChanged {
usernameChanged {
previousUsername
user {
${fields}
}
}
}
`;
const mapStateToProps = state => ({
track: state.community.indicatorTrack,
});
const enhance = compose(
connect(mapStateToProps),
withFragments({
root: gql`
fragment TalkAdmin_Community_Indicator_root on RootQuery {
fragment TalkAdmin_CommunityIndicator_root on RootQuery {
flaggedUsernamesCount: userCount(
query: {
action_type: FLAG
state: { status: { username: [SET, CHANGED] } }
}
)
me {
id
}
}
`,
}),
hideIfNoData(props => !props.root.flaggedUsernamesCount)
})
);
export default enhance(Indicator);
export default enhance(IndicatorContainer);
@@ -49,13 +49,13 @@ function decrementFlaggedUserCount(root) {
}
/**
* Assimilate flagged user changes into current store.
* Assimilate flagged acount changes into current store.
* @param {Object} root current state of the store
* @param {Object} user user that was changed
* @param {function} notify callback to show notification
* @return {Object} next state of the store
*/
export function handleFlaggedUsernameChange(root, user, notify) {
export function handleFlaggedAccountsChange(root, user, notify) {
if (user.state.status.username.status !== 'SET') {
// Check if change came from current user, if so ignore it.
const lastChange =
@@ -87,7 +87,7 @@ export function handleFlaggedUsernameChange(root, user, notify) {
break;
case 'APPROVED':
case 'REJECTED':
return root;
return decrementFlaggedUserCount(root);
default:
}
}
@@ -105,3 +105,21 @@ export function handleFlaggedUsernameChange(root, user, notify) {
}
}
}
/**
* Track indicator status
* @param {Object} root current state of the store
* @param {Object} user user that was changed
* @return {Object} next state of the store
*/
export function handleIndicatorChange(root, user) {
switch (user.state.status.username.status) {
case 'SET':
case 'CHANGED':
return incrementFlaggedUserCount(root);
case 'APPROVED':
case 'REJECTED':
return decrementFlaggedUserCount(root);
default:
}
}