diff --git a/client/coral-admin/src/actions/community.js b/client/coral-admin/src/actions/community.js
index d2b8f1a3f..82a74daf3 100644
--- a/client/coral-admin/src/actions/community.js
+++ b/client/coral-admin/src/actions/community.js
@@ -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,
+});
diff --git a/client/coral-admin/src/components/Header.js b/client/coral-admin/src/components/Header.js
index e6bd73f52..6b2274d27 100644
--- a/client/coral-admin/src/components/Header.js
+++ b/client/coral-admin/src/components/Header.js
@@ -15,6 +15,7 @@ const CoralHeader = ({
showShortcuts = () => {},
auth,
root,
+ data,
}) => {
return (
@@ -31,7 +32,7 @@ const CoralHeader = ({
activeClassName={styles.active}
>
{t('configure.moderate')}
-
+
)}
{t('configure.community')}
-
+
{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;
diff --git a/client/coral-admin/src/constants/community.js b/client/coral-admin/src/constants/community.js
index a9cc2f1e3..1ffe3f8d6 100644
--- a/client/coral-admin/src/constants/community.js
+++ b/client/coral-admin/src/constants/community.js
@@ -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`;
diff --git a/client/coral-admin/src/containers/Header.js b/client/coral-admin/src/containers/Header.js
index dae096517..dd16c17c6 100644
--- a/client/coral-admin/src/containers/Header.js
+++ b/client/coral-admin/src/containers/Header.js
@@ -13,10 +13,5 @@ export default withQuery(
}
${ModerationIndicator.fragments.root}
${CommunityIndicator.fragments.root}
- `,
- {
- options: {
- pollInterval: 10000,
- },
- }
+ `
)(Header);
diff --git a/client/coral-admin/src/graphql/index.js b/client/coral-admin/src/graphql/index.js
index 3a24702cd..95595c265 100644
--- a/client/coral-admin/src/graphql/index.js
+++ b/client/coral-admin/src/graphql/index.js
@@ -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),
diff --git a/client/coral-admin/src/reducers/community.js b/client/coral-admin/src/reducers/community.js
index 9fe17ad8f..68e471935 100644
--- a/client/coral-admin/src/reducers/community.js
+++ b/client/coral-admin/src/reducers/community.js
@@ -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;
}
diff --git a/client/coral-admin/src/routes/Community/containers/FlaggedAccounts.js b/client/coral-admin/src/routes/Community/containers/FlaggedAccounts.js
index 09240b8f3..f5fd36263 100644
--- a/client/coral-admin/src/routes/Community/containers/FlaggedAccounts.js
+++ b/client/coral-admin/src/routes/Community/containers/FlaggedAccounts.js
@@ -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
);
diff --git a/client/coral-admin/src/routes/Community/containers/Indicator.js b/client/coral-admin/src/routes/Community/containers/Indicator.js
index 04a351fb6..eeb5e20f7 100644
--- a/client/coral-admin/src/routes/Community/containers/Indicator.js
+++ b/client/coral-admin/src/routes/Community/containers/Indicator.js
@@ -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 ;
+ }
+}
+
+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);
diff --git a/client/coral-admin/src/routes/Community/graphql.js b/client/coral-admin/src/routes/Community/graphql.js
index af10c8e86..8d6941c41 100644
--- a/client/coral-admin/src/routes/Community/graphql.js
+++ b/client/coral-admin/src/routes/Community/graphql.js
@@ -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:
+ }
+}