From 67cca7d85d8d4f1baa8e75a0b1fa591d3e072b97 Mon Sep 17 00:00:00 2001 From: hovoodd Date: Wed, 3 Oct 2018 22:15:05 +0300 Subject: [PATCH] Add filters to list of people --- .../routes/Community/components/People.css | 15 +++ .../src/routes/Community/components/People.js | 43 ++++++- .../src/routes/Community/containers/People.js | 108 ++++++++++-------- graph/loaders/users.js | 6 +- graph/typeDefs.graphql | 1 + locales/en.yml | 4 + 6 files changed, 122 insertions(+), 55 deletions(-) diff --git a/client/coral-admin/src/routes/Community/components/People.css b/client/coral-admin/src/routes/Community/components/People.css index ac565c8f8..aea321cd7 100644 --- a/client/coral-admin/src/routes/Community/components/People.css +++ b/client/coral-admin/src/routes/Community/components/People.css @@ -34,6 +34,21 @@ } } +.filterHeader { + margin-top: 30px; + font-size: 16px; + font-weight: 900; +} + +.filterDetail { + margin-top: 15px; + font-size: 16px; +} + +.radioGroup { + margin: 5px 0; +} + .mainContent { width: calc(100% - 300px); padding: 34px 14px; diff --git a/client/coral-admin/src/routes/Community/components/People.js b/client/coral-admin/src/routes/Community/components/People.js index e0d699304..e40b6cca4 100644 --- a/client/coral-admin/src/routes/Community/components/People.js +++ b/client/coral-admin/src/routes/Community/components/People.js @@ -9,6 +9,7 @@ import PropTypes from 'prop-types'; import ActionsMenu from 'coral-admin/src/components/ActionsMenu'; import ActionsMenuItem from 'coral-admin/src/components/ActionsMenuItem'; import { isSuspended, isBanned } from 'coral-framework/utils/user'; +import { RadioGroup, Radio } from 'react-mdl'; import moment from 'moment'; import { ADMIN, @@ -64,11 +65,12 @@ class People extends React.Component { render() { const { - onSearchChange, + onFilterChange, users = [], setUserRole, viewUserDetail, loadMore, + filters, } = this.props; const hasResults = !!users.nodes.length; @@ -87,11 +89,43 @@ class People extends React.Component { id="commenters-search" type="text" className={styles.searchBoxInput} - defaultValue="" - onChange={onSearchChange} + value={filters.search} + onChange={onFilterChange('search')} placeholder={t('streams.search')} /> +
+ {t('community.filter_users')} +
+
{t('community.status')}
+ + {t('community.all')} + {t('community.active')} + {t('community.suspended')} + {t('community.banned')} + +
+ {t('community.filter_role')} +
+ + {t('community.all')} + {t('community.admin')} + {t('community.staff')} + {t('community.moderator')} + {t('community.commenter')} +
{hasResults ? ( @@ -254,7 +288,8 @@ class People extends React.Component { People.propTypes = { users: PropTypes.object.isRequired, - onSearchChange: PropTypes.func.isRequired, + filters: PropTypes.object.isRequired, + onFilterChange: PropTypes.func.isRequired, setUserRole: PropTypes.func.isRequired, viewUserDetail: PropTypes.func.isRequired, unbanUser: PropTypes.func.isRequired, diff --git a/client/coral-admin/src/routes/Community/containers/People.js b/client/coral-admin/src/routes/Community/containers/People.js index 63cd28833..7f47795b4 100644 --- a/client/coral-admin/src/routes/Community/containers/People.js +++ b/client/coral-admin/src/routes/Community/containers/People.js @@ -17,59 +17,65 @@ import update from 'immutability-helper'; import { Spinner } from 'coral-ui'; import withQuery from 'coral-framework/hocs/withQuery'; -class PeopleContainer extends React.Component { +class PeopleContainer extends React.PureComponent { timer = null; state = { - searchValue: '', + search: '', + role: '', + status: '', }; - onSearchChange = e => { - const { value } = e.target; - this.setState({ searchValue: value }, () => { + statusToQuery = { + active: { suspended: false, banned: false }, + suspended: { suspended: true }, + banned: { banned: true }, + }; + + onFilterChange = filter => e => + this.setState({ [filter]: e.target.value }, () => { clearTimeout(this.timer); - this.timer = setTimeout(() => { - this.search(value); - }, 350); + this.timer = setTimeout(this.filter, 350); }); + + getFilterState = () => { + const { role, status } = this.state; + + return { + status: this.statusToQuery[status] || null, + role: role || null, + }; }; - search = async value => { - return this.props.data.fetchMore({ - query: SEARCH_QUERY, + filter = () => + this.props.data.fetchMore({ + query: FILTER_QUERY, variables: { - value, + state: this.getFilterState(), + value: this.state.search, limit: 10, }, - updateQuery: (previous, { fetchMoreResult: { users } }) => { - const updated = update(previous, { + updateQuery: (previous, { fetchMoreResult: { users } }) => + update(previous, { users: { - nodes: { - $set: users.nodes, - }, + nodes: { $set: users.nodes }, hasNextPage: { $set: users.hasNextPage }, endCursor: { $set: users.endCursor }, }, - }); - return updated; - }, + }), }); - }; - setUserRole = async (id, role) => { - await this.props.setUserRole(id, role); - }; - - loadMore = () => { - return this.props.data.fetchMore({ + loadMore = () => + this.props.data.fetchMore({ query: LOAD_MORE_QUERY, variables: { - value: this.state.searchValue, - limit: 5, cursor: this.props.root.users.endCursor, + state: this.getFilterState(), + value: this.state.search, + limit: 5, }, - updateQuery: (previous, { fetchMoreResult: { users } }) => { - const updated = update(previous, { + updateQuery: (previous, { fetchMoreResult: { users } }) => + update(previous, { users: { nodes: { $apply: nodes => appendNewNodes(nodes, users.nodes), @@ -77,11 +83,8 @@ class PeopleContainer extends React.Component { hasNextPage: { $set: users.hasNextPage }, endCursor: { $set: users.endCursor }, }, - }); - return updated; - }, + }), }); - }; render() { if (this.props.data.error) { @@ -98,9 +101,9 @@ class PeopleContainer extends React.Component { return ( ); } @@ -125,16 +129,6 @@ PeopleContainer.propTypes = { root: PropTypes.object, }; -const mapDispatchToProps = dispatch => - bindActionCreators( - { - viewUserDetail, - showSuspendUserDialog, - showBanUserDialog, - }, - dispatch - ); - const LOAD_MORE_QUERY = gql` query TalkAdmin_Community_People_LoadMoreUsers( $limit: Int @@ -169,9 +163,13 @@ const LOAD_MORE_QUERY = gql` } `; -const SEARCH_QUERY = gql` - query TalkAdmin_Community_People_SearchUsers($value: String, $limit: Int) { - users(query: { value: $value, limit: $limit }) { +const FILTER_QUERY = gql` + query TalkAdmin_Community_People_FilterUsers( + $state: UserStateInput + $value: String + $limit: Int + ) { + users(query: { state: $state, value: $value, limit: $limit }) { hasNextPage endCursor nodes { @@ -199,6 +197,16 @@ const SEARCH_QUERY = gql` } `; +const mapDispatchToProps = dispatch => + bindActionCreators( + { + viewUserDetail, + showSuspendUserDialog, + showBanUserDialog, + }, + dispatch + ); + export default compose( connect( null, diff --git a/graph/loaders/users.js b/graph/loaders/users.js index d8e1927cb..11d35ac95 100644 --- a/graph/loaders/users.js +++ b/graph/loaders/users.js @@ -4,7 +4,11 @@ const { SEARCH_OTHER_USERS } = require('../../perms/constants'); const { escapeRegExp } = require('../../services/regex'); const mergeState = (query, state) => { - const { status } = state; + const { role, status } = state; + + if (role) { + query.merge({ role }); + } if (status) { const { username, banned, suspended } = status; diff --git a/graph/typeDefs.graphql b/graph/typeDefs.graphql index 1ca003de6..ebbf8203d 100644 --- a/graph/typeDefs.graphql +++ b/graph/typeDefs.graphql @@ -189,6 +189,7 @@ type UserStatus { } input UserStateInput { + role: USER_ROLES status: UserStatusInput } diff --git a/locales/en.yml b/locales/en.yml index c7b4ed926..e8b276fb2 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -62,6 +62,7 @@ en: active: Active admin: Administrator ads_marketing: 'This looks like an ad/marketing' + all: 'All' are_you_sure: 'Are you sure you would like to ban {0}?' ban_user: 'Ban User?' banned: Banned @@ -69,6 +70,8 @@ en: cancel: Cancel commenter: Commenter dont_like_username: 'Dislike username' + filter_users: 'Filter users' + filter_role: Role flaggedaccounts: 'Reported Usernames' flags: Flags impersonating: Impersonation @@ -85,6 +88,7 @@ en: spam_ads: Spam/Ads staff: Staff status: Status + suspended: Suspended username_and_email: 'Username and Email' yes_ban_user: 'Yes Ban User' configure: