mirror of
https://github.com/wassname/talk.git
synced 2026-07-17 11:33:39 +08:00
Styling, refactor and instant update after banning and unbanning from community
This commit is contained in:
@@ -44,6 +44,7 @@
|
||||
}
|
||||
&:hover, &:active, &:focus {
|
||||
background-color: #e2e2e2;
|
||||
border-color: #616161;
|
||||
}
|
||||
&[disabled], &[disabled]:hover, &[disabled]:focus, &[disabled]:active {
|
||||
background-color: #262626;
|
||||
|
||||
@@ -9,14 +9,13 @@ import ApproveButton from './ApproveButton';
|
||||
import AccountHistory from './AccountHistory';
|
||||
import {Slot} from 'coral-framework/components';
|
||||
import UserDetailCommentList from '../components/UserDetailCommentList';
|
||||
import {getReliability} from 'coral-framework/utils/user';
|
||||
import {getReliability, isSuspended, isBanned} from 'coral-framework/utils/user';
|
||||
import ButtonCopyToClipboard from './ButtonCopyToClipboard';
|
||||
import ClickOutside from 'coral-framework/components/ClickOutside';
|
||||
import {Icon, Drawer, Spinner, TabBar, Tab, TabContent, TabPane} from 'coral-ui';
|
||||
import ActionsMenu from 'coral-admin/src/components/ActionsMenu';
|
||||
import ActionsMenuItem from 'coral-admin/src/components/ActionsMenuItem';
|
||||
import UserInfoTooltip from './UserInfoTooltip';
|
||||
import get from 'lodash/get';
|
||||
|
||||
class UserDetail extends React.Component {
|
||||
|
||||
@@ -91,12 +90,9 @@ class UserDetail extends React.Component {
|
||||
getActionMenuLabel() {
|
||||
const {root: {user}} = this.props;
|
||||
|
||||
const banned = get(user, 'state.status.banned.status');
|
||||
const suspensionUntil = get(user, 'state.status.suspension.until');
|
||||
|
||||
if (banned) {
|
||||
if (isBanned(user)) {
|
||||
return 'Banned';
|
||||
} else if (suspensionUntil && new Date(suspensionUntil) > new Date()) {
|
||||
} else if (isSuspended(user)) {
|
||||
return 'Suspended';
|
||||
}
|
||||
|
||||
@@ -132,13 +128,8 @@ class UserDetail extends React.Component {
|
||||
rejectedPercent = 0;
|
||||
}
|
||||
|
||||
const banned = get(user, 'state.status.banned.status');
|
||||
const suspensionUntil = get(user, 'state.status.suspension.until');
|
||||
|
||||
const suspended =
|
||||
user &&
|
||||
suspensionUntil &&
|
||||
new Date(suspensionUntil) > new Date();
|
||||
const banned = isBanned(user);
|
||||
const suspended = isSuspended(user);
|
||||
|
||||
return (
|
||||
<ClickOutside onClickOutside={hideUserDetail}>
|
||||
|
||||
@@ -3,8 +3,48 @@ import {mapLeaves} from 'coral-framework/utils';
|
||||
|
||||
export default {
|
||||
mutations: {
|
||||
BanUser: ({variables: {input: {id: userId}}}) => ({
|
||||
updateQueries: {
|
||||
TalkAdmin_Community: (prev) => {
|
||||
|
||||
const updated = update(prev, {
|
||||
users: {
|
||||
nodes: {
|
||||
$apply: (nodes) => nodes.map((node) => {
|
||||
if (node.id === userId) {
|
||||
node.state.status.banned.status = true;
|
||||
}
|
||||
|
||||
return node;
|
||||
})
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return updated;
|
||||
}
|
||||
}
|
||||
}),
|
||||
UnBanUser: ({variables: {input: {id: userId}}}) => ({
|
||||
updateQueries: {
|
||||
TalkAdmin_Community: (prev) => {
|
||||
|
||||
const updated = update(prev, {
|
||||
users: {
|
||||
nodes: {
|
||||
$apply: (nodes) => nodes.map((node) => {
|
||||
if (node.id === userId) {
|
||||
node.state.status.banned.status = false;
|
||||
}
|
||||
|
||||
return node;
|
||||
})
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return updated;
|
||||
},
|
||||
CoralAdmin_Moderation: (prev) => {
|
||||
|
||||
const updated = update(prev, {
|
||||
|
||||
@@ -12,7 +12,11 @@ class Community extends Component {
|
||||
const activeTab = route.path === ':id' ? 'flagged' : route.path;
|
||||
|
||||
if (activeTab === 'people') {
|
||||
return <People community={community} />;
|
||||
return <People
|
||||
community={community}
|
||||
data={this.props.data}
|
||||
root={this.props.root}
|
||||
/>;
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,27 +1,60 @@
|
||||
import React from 'react';
|
||||
import cn from 'classnames';
|
||||
import styles from './styles.css';
|
||||
import Table from './Table';
|
||||
import {Icon} from 'coral-ui';
|
||||
import {Icon, Dropdown, Option} from 'coral-ui';
|
||||
import EmptyCard from '../../../components/EmptyCard';
|
||||
import t from 'coral-framework/services/i18n';
|
||||
|
||||
import LoadMore from '../../../components/LoadMore';
|
||||
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 moment from 'moment';
|
||||
|
||||
const headers = [
|
||||
{
|
||||
title: t('community.username_and_email'),
|
||||
field: 'username'
|
||||
},
|
||||
{
|
||||
title: t('community.account_creation_date'),
|
||||
field: 'created_at'
|
||||
},
|
||||
{
|
||||
title: t('community.status'),
|
||||
field: 'status'
|
||||
},
|
||||
{
|
||||
title: t('community.newsroom_role'),
|
||||
field: 'role'
|
||||
}
|
||||
];
|
||||
|
||||
const getActionMenuLabel = (user) => {
|
||||
|
||||
if (isBanned(user)) {
|
||||
return 'Banned';
|
||||
} else if (isSuspended(user)) {
|
||||
return 'Suspended';
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
|
||||
const People = (props) => {
|
||||
const {
|
||||
users = [],
|
||||
searchValue,
|
||||
onSearchChange,
|
||||
onHeaderClickHandler,
|
||||
onPageChange,
|
||||
totalPages,
|
||||
page,
|
||||
users = [],
|
||||
setUserRole,
|
||||
viewUserDetail,
|
||||
loadMore,
|
||||
unSuspendUser,
|
||||
unBanUser,
|
||||
showSuspendUserDialog,
|
||||
showBanUserDialog,
|
||||
} = props;
|
||||
|
||||
const hasResults = !!users.length;
|
||||
const hasResults = !!users.nodes.length;
|
||||
|
||||
return (
|
||||
<div className={cn(styles.container, 'talk-admin-community-people-container')}>
|
||||
@@ -32,7 +65,7 @@ const People = (props) => {
|
||||
id="commenters-search"
|
||||
type="text"
|
||||
className={styles.searchBoxInput}
|
||||
value={searchValue}
|
||||
defaultValue=''
|
||||
onChange={onSearchChange}
|
||||
placeholder={t('streams.search')}
|
||||
/>
|
||||
@@ -41,19 +74,88 @@ const People = (props) => {
|
||||
<div className={styles.mainContent}>
|
||||
{
|
||||
hasResults
|
||||
? <Table
|
||||
users={users}
|
||||
setUserRole={setUserRole}
|
||||
viewUserDetail={viewUserDetail}
|
||||
onHeaderClickHandler={onHeaderClickHandler}
|
||||
pageCount={totalPages}
|
||||
onPageChange={onPageChange}
|
||||
page={page}
|
||||
unBanUser={props.unBanUser}
|
||||
unSuspendUser={props.unSuspendUser}
|
||||
showSuspendUserDialog={props.showSuspendUserDialog}
|
||||
showBanUserDialog={props.showBanUserDialog}
|
||||
/>
|
||||
? <div>
|
||||
<div>
|
||||
<table className={`mdl-data-table ${styles.dataTable}`}>
|
||||
<thead>
|
||||
<tr>
|
||||
{headers.map((header, i) =>(
|
||||
<th
|
||||
key={i}
|
||||
className={cn('mdl-data-table__cell--non-numeric', styles.header)}
|
||||
scope="col" >
|
||||
{header.title}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{users.nodes.map((user, i)=> (
|
||||
<tr key={i} className="talk-admin-community-people-row">
|
||||
<td className="mdl-data-table__cell--non-numeric">
|
||||
<button onClick={() => {viewUserDetail(user.id);}} className={cn(styles.username, styles.button)}>{user.username}</button>
|
||||
<span className={styles.email}>{user.profiles.map(({id}) => id)}</span>
|
||||
</td>
|
||||
<td className="mdl-data-table__cell--non-numeric">
|
||||
{moment(new Date(user.created_at)).format('MMMM Do YYYY, h:mm:ss a')}
|
||||
</td>
|
||||
<td className="mdl-data-table__cell--non-numeric">
|
||||
|
||||
<ActionsMenu
|
||||
icon="person"
|
||||
className={cn(styles.actionsMenu, 'talk-admin-community-people-dd-status')}
|
||||
buttonClassNames={cn(styles.actionsMenuButton, {
|
||||
[styles.actionsMenuSuspended]: isSuspended(user),
|
||||
[styles.actionsMenuBanned]: isBanned(user),
|
||||
}, 'talk-admin-user-detail-actions-button')}
|
||||
label={getActionMenuLabel(user)} >
|
||||
|
||||
{isSuspended(user) ? <ActionsMenuItem
|
||||
onClick={() => unSuspendUser({id: user.id})}>
|
||||
Remove Suspension
|
||||
</ActionsMenuItem> : <ActionsMenuItem
|
||||
onClick={() => showSuspendUserDialog({
|
||||
userId: user.id,
|
||||
username: user.username,
|
||||
})}>
|
||||
Suspend User
|
||||
</ActionsMenuItem>}
|
||||
|
||||
{isBanned(user) ? <ActionsMenuItem
|
||||
onClick={() => unBanUser({id: user.id})}>
|
||||
Remove Ban
|
||||
</ActionsMenuItem> : <ActionsMenuItem
|
||||
onClick={() => showBanUserDialog({
|
||||
userId: user.id,
|
||||
username: user.username,
|
||||
})}>
|
||||
Ban User
|
||||
</ActionsMenuItem>}
|
||||
|
||||
</ActionsMenu>
|
||||
</td>
|
||||
<td className="mdl-data-table__cell--non-numeric">
|
||||
<Dropdown
|
||||
containerClassName="talk-admin-community-people-dd-role"
|
||||
value={user.role}
|
||||
placeholder={t('community.role')}
|
||||
onChange={(role) => setUserRole(user.id, role)}>
|
||||
<Option value={'COMMENTER'} label={t('community.commenter')} />
|
||||
<Option value={'STAFF'} label={t('community.staff')} />
|
||||
<Option value={'MODERATOR'} label={t('community.moderator')} />
|
||||
<Option value={'ADMIN'} label={t('community.admin')} />
|
||||
</Dropdown>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<LoadMore
|
||||
loadMore={loadMore}
|
||||
showLoadMore={users.hasNextPage}
|
||||
/>
|
||||
</div>
|
||||
: <EmptyCard>{t('community.no_results')}</EmptyCard>
|
||||
}
|
||||
</div>
|
||||
@@ -62,19 +164,15 @@ const People = (props) => {
|
||||
};
|
||||
|
||||
People.propTypes = {
|
||||
onHeaderClickHandler: PropTypes.func,
|
||||
users: PropTypes.array,
|
||||
page: PropTypes.number.isRequired,
|
||||
searchValue: PropTypes.string,
|
||||
onSearchChange: PropTypes.func,
|
||||
totalPages: PropTypes.number,
|
||||
onPageChange: PropTypes.func,
|
||||
users: PropTypes.object.isRequired,
|
||||
onSearchChange: PropTypes.func.isRequired,
|
||||
setUserRole: PropTypes.func.isRequired,
|
||||
viewUserDetail: PropTypes.func.isRequired,
|
||||
unBanUser: PropTypes.func.isRequired,
|
||||
unSuspendUser: PropTypes.func.isRequired,
|
||||
showSuspendUserDialog: PropTypes.func,
|
||||
showBanUserDialog: PropTypes.func,
|
||||
loadMore: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default People;
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
.dataTable {
|
||||
width: 100%;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
th.header {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
th.header:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
th.header:nth-child(2), th.header:nth-child(3) {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.button {
|
||||
composes: buttonReset from 'coral-framework/styles/reset.css';
|
||||
&:hover {
|
||||
background-color: #D0D0D0;
|
||||
}
|
||||
}
|
||||
|
||||
.username, .email {
|
||||
max-width: 215px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.email {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.selectField {
|
||||
position: relative;
|
||||
width: 150px;
|
||||
height: 36px;
|
||||
background: #2c2c2c;
|
||||
padding: 10px 15px;
|
||||
box-sizing: border-box;
|
||||
color: white;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12);
|
||||
|
||||
> div {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
i {
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
right: 7px;
|
||||
}
|
||||
|
||||
input {
|
||||
padding: 0;
|
||||
font-size: 13px;
|
||||
letter-spacing: 0.7px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
import React from 'react';
|
||||
import styles from './Table.css';
|
||||
import t from 'coral-framework/services/i18n';
|
||||
import PropTypes from 'prop-types';
|
||||
import {Paginate, Dropdown, Option} from 'coral-ui';
|
||||
import cn from 'classnames';
|
||||
import ActionsMenu from 'coral-admin/src/components/ActionsMenu';
|
||||
import ActionsMenuItem from 'coral-admin/src/components/ActionsMenuItem';
|
||||
import {isSuspended, isBanned} from 'coral-framework/utils/user';
|
||||
|
||||
const headers = [
|
||||
{
|
||||
title: t('community.username_and_email'),
|
||||
field: 'username'
|
||||
},
|
||||
{
|
||||
title: t('community.account_creation_date'),
|
||||
field: 'created_at'
|
||||
},
|
||||
{
|
||||
title: t('community.status'),
|
||||
field: 'status'
|
||||
},
|
||||
{
|
||||
title: t('community.newsroom_role'),
|
||||
field: 'role'
|
||||
}
|
||||
];
|
||||
|
||||
const Table = (props) => {
|
||||
|
||||
const {
|
||||
users,
|
||||
setUserRole,
|
||||
onHeaderClickHandler,
|
||||
viewUserDetail,
|
||||
pageCount,
|
||||
page,
|
||||
onPageChange,
|
||||
unSuspendUser,
|
||||
unBanUser,
|
||||
showSuspendUserDialog,
|
||||
showBanUserDialog,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<table className={`mdl-data-table ${styles.dataTable}`}>
|
||||
<thead>
|
||||
<tr>
|
||||
{headers.map((header, i) =>(
|
||||
<th
|
||||
key={i}
|
||||
className={cn('mdl-data-table__cell--non-numeric', styles.header)}
|
||||
scope="col"
|
||||
onClick={() => onHeaderClickHandler({field: header.field})}>
|
||||
{header.title}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{users.map((user, i)=> (
|
||||
<tr key={i} className="talk-admin-community-people-row">
|
||||
<td className="mdl-data-table__cell--non-numeric">
|
||||
<button onClick={() => {viewUserDetail(user.id);}} className={cn(styles.username, styles.button)}>{user.username}</button>
|
||||
<span className={styles.email}>{user.profiles.map(({id}) => id)}</span>
|
||||
</td>
|
||||
<td className="mdl-data-table__cell--non-numeric">
|
||||
{user.created_at}
|
||||
</td>
|
||||
<td className="mdl-data-table__cell--non-numeric">
|
||||
|
||||
<ActionsMenu
|
||||
icon="person"
|
||||
className={cn(styles.actionsMenu, 'talk-admin-community-people-dd-status')}
|
||||
buttonClassNames={cn({
|
||||
[styles.actionsMenuSuspended]: isSuspended(user),
|
||||
[styles.actionsMenuBanned]: isBanned(user),
|
||||
}, 'talk-admin-user-detail-actions-button')} >
|
||||
|
||||
{isSuspended(user) ? <ActionsMenuItem
|
||||
onClick={() => unSuspendUser({id: user.id})}>
|
||||
Remove Suspension
|
||||
</ActionsMenuItem> : <ActionsMenuItem
|
||||
onClick={() => showSuspendUserDialog({
|
||||
userId: user.id,
|
||||
username: user.username,
|
||||
})}>
|
||||
Suspend User
|
||||
</ActionsMenuItem>}
|
||||
|
||||
{isBanned(user) ? <ActionsMenuItem
|
||||
onClick={() => unBanUser({id: user.id})}>
|
||||
Remove Ban
|
||||
</ActionsMenuItem> : <ActionsMenuItem
|
||||
onClick={() => showBanUserDialog({
|
||||
userId: user.id,
|
||||
username: user.username,
|
||||
})}>
|
||||
Ban User
|
||||
</ActionsMenuItem>}
|
||||
|
||||
</ActionsMenu>
|
||||
</td>
|
||||
<td className="mdl-data-table__cell--non-numeric">
|
||||
<Dropdown
|
||||
containerClassName="talk-admin-community-people-dd-role"
|
||||
value={user.role}
|
||||
placeholder={t('community.role')}
|
||||
onChange={(role) => setUserRole(user.id, role)}>
|
||||
<Option value={'COMMENTER'} label={t('community.commenter')} />
|
||||
<Option value={'STAFF'} label={t('community.staff')} />
|
||||
<Option value={'MODERATOR'} label={t('community.moderator')} />
|
||||
<Option value={'ADMIN'} label={t('community.admin')} />
|
||||
</Dropdown>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
<Paginate
|
||||
pageCount={pageCount}
|
||||
page={page - 1}
|
||||
onPageChange={onPageChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Table.propTypes = {
|
||||
users: PropTypes.array,
|
||||
onHeaderClickHandler: PropTypes.func.isRequired,
|
||||
setUserRole: PropTypes.func.isRequired,
|
||||
viewUserDetail: PropTypes.func.isRequired,
|
||||
pageCount: PropTypes.number.isRequired,
|
||||
page: PropTypes.number.isRequired,
|
||||
onPageChange: PropTypes.func.isRequired,
|
||||
showSuspendUserDialog: PropTypes.func,
|
||||
showBanUserDialog: PropTypes.func,
|
||||
unBanUser: PropTypes.func.isRequired,
|
||||
unSuspendUser: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default Table;
|
||||
@@ -240,3 +240,97 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================================================== */
|
||||
/* TABLE */
|
||||
/* ========================================================================== */
|
||||
|
||||
.dataTable {
|
||||
width: 100%;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
th.header {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
th.header:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
th.header:nth-child(2), th.header:nth-child(3) {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.button {
|
||||
composes: buttonReset from 'coral-framework/styles/reset.css';
|
||||
&:hover {
|
||||
background-color: #D0D0D0;
|
||||
}
|
||||
}
|
||||
|
||||
.username, .email {
|
||||
max-width: 215px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.email {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.selectField {
|
||||
position: relative;
|
||||
width: 150px;
|
||||
height: 36px;
|
||||
background: #2c2c2c;
|
||||
padding: 10px 15px;
|
||||
box-sizing: border-box;
|
||||
color: white;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12);
|
||||
|
||||
> div {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
i {
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
right: 7px;
|
||||
}
|
||||
|
||||
input {
|
||||
padding: 0;
|
||||
font-size: 13px;
|
||||
letter-spacing: 0.7px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.actionsMenu {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.actionsMenu .actionsMenuButton {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1);
|
||||
font-size: 0.98em;
|
||||
}
|
||||
|
||||
.actionsMenuSuspended {
|
||||
background-color: #F29336;
|
||||
border-color: #F29336;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.actionsMenuBanned {
|
||||
background-color: #E45241;
|
||||
border-color: #E45241;
|
||||
color: white;
|
||||
}
|
||||
|
||||
@@ -39,9 +39,9 @@ const withData = withQuery(gql`
|
||||
__typename
|
||||
}
|
||||
}
|
||||
${People.fragments.root}
|
||||
${FlaggedAccounts.fragments.root}
|
||||
${FlaggedUser.fragments.root}
|
||||
${People.fragments.root}
|
||||
${FlaggedUser.fragments.me}
|
||||
`, {
|
||||
options: {
|
||||
|
||||
@@ -9,59 +9,29 @@ import {withUnBanUser, withUnSuspendUser, withSetUserRole} from 'coral-framework
|
||||
import {showBanUserDialog} from 'actions/banUserDialog';
|
||||
import {showSuspendUserDialog} from 'actions/suspendUserDialog';
|
||||
import {viewUserDetail} from '../../../actions/userDetail';
|
||||
|
||||
import {
|
||||
fetchUsers,
|
||||
updateSorting,
|
||||
setPage,
|
||||
hideRejectUsernameDialog,
|
||||
setSearchValue,
|
||||
} from '../../../actions/community';
|
||||
import {appendNewNodes} from 'plugin-api/beta/client/utils';
|
||||
import update from 'immutability-helper';
|
||||
import {Spinner} from 'coral-ui';
|
||||
|
||||
class PeopleContainer extends React.Component {
|
||||
timer = null;
|
||||
|
||||
fetchUsers = (query = {}) => {
|
||||
const {community} = this.props;
|
||||
|
||||
this.props.fetchUsers({
|
||||
value: community.searchValue,
|
||||
field: community.fieldPeople,
|
||||
asc: community.ascPeople,
|
||||
...query
|
||||
});
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.fetchUsers();
|
||||
}
|
||||
|
||||
onKeyDownHandler = (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
this.fetchUsers();
|
||||
// this.fetchUsers();
|
||||
}
|
||||
}
|
||||
|
||||
onSearchChange = (e) => {
|
||||
const value = e.target.value;
|
||||
console.log(value);
|
||||
|
||||
this.props.setSearchValue(value);
|
||||
clearTimeout(this.timer);
|
||||
this.timer = setTimeout(() => {
|
||||
this.fetchUsers({value});
|
||||
}, 350);
|
||||
}
|
||||
// clearTimeout(this.timer);
|
||||
|
||||
onHeaderClickHandler = (sort) => {
|
||||
this.props.updateSorting(sort);
|
||||
this.fetchUsers();
|
||||
}
|
||||
|
||||
onPageChange = ({selected}) => {
|
||||
const page = selected + 1;
|
||||
this.props.setPage(page);
|
||||
this.fetchUsers({page});
|
||||
// this.timer = setTimeout(() => {
|
||||
// // this.fetchUsers({value});
|
||||
// }, 350);
|
||||
}
|
||||
|
||||
setUserRole = async (id, role) => {
|
||||
@@ -69,51 +39,92 @@ class PeopleContainer extends React.Component {
|
||||
await this.fetchUsers();
|
||||
}
|
||||
|
||||
loadMore = () => {
|
||||
return this.props.data.fetchMore({
|
||||
query: LOAD_MORE_QUERY,
|
||||
variables: {
|
||||
limit: 5,
|
||||
cursor: this.props.root.users.endCursor,
|
||||
},
|
||||
updateQuery: (previous, {fetchMoreResult:{users}}) => {
|
||||
const updated = update(previous, {
|
||||
flaggedUsers: {
|
||||
nodes: {
|
||||
$apply: (nodes) => appendNewNodes(nodes, users.nodes),
|
||||
},
|
||||
hasNextPage: {$set: users.hasNextPage},
|
||||
endCursor: {$set: users.endCursor},
|
||||
},
|
||||
});
|
||||
return updated;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
|
||||
if (this.props.data.error) {
|
||||
return <div>{this.props.data.error.message}</div>;
|
||||
}
|
||||
|
||||
if (this.props.data.loading) {
|
||||
return <div><Spinner/></div>;
|
||||
}
|
||||
|
||||
return <People
|
||||
users={this.props.community.users}
|
||||
searchValue={this.props.community.searchValue}
|
||||
onSearchChange={this.onSearchChange}
|
||||
onHeaderClickHandler={this.onHeaderClickHandler}
|
||||
onPageChange={this.onPageChange}
|
||||
totalPages={this.props.community.totalPagesPeople}
|
||||
setUserRole={this.setUserRole}
|
||||
page={this.props.community.pagePeople}
|
||||
onSearchChange={this.onSearchChange}
|
||||
viewUserDetail={this.props.viewUserDetail}
|
||||
setUserRole={this.setUserRole}
|
||||
showSuspendUserDialog={this.props.showSuspendUserDialog}
|
||||
showBanUserDialog={this.props.showBanUserDialog}
|
||||
unBanUser={this.props.unBanUser}
|
||||
unSuspendUser={this.props.unBanUser}
|
||||
data={this.props.data}
|
||||
root={this.props.root}
|
||||
users={this.props.root.users}
|
||||
loadMore={this.loadMore}
|
||||
/>;
|
||||
}
|
||||
}
|
||||
|
||||
PeopleContainer.propTypes = {
|
||||
setPage: PropTypes.func,
|
||||
fetchUsers: PropTypes.func,
|
||||
updateSorting: PropTypes.func,
|
||||
community: PropTypes.object,
|
||||
setUserRole: PropTypes.func.isRequired,
|
||||
unBanUser: PropTypes.func.isRequired,
|
||||
unSuspendUser: PropTypes.func.isRequired,
|
||||
setSearchValue: PropTypes.func.isRequired,
|
||||
viewUserDetail: PropTypes.func.isRequired,
|
||||
community: PropTypes.object,
|
||||
showSuspendUserDialog: PropTypes.func,
|
||||
showBanUserDialog: PropTypes.func,
|
||||
data: PropTypes.object,
|
||||
root: PropTypes.object,
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) =>
|
||||
bindActionCreators({
|
||||
setPage,
|
||||
fetchUsers,
|
||||
updateSorting,
|
||||
hideRejectUsernameDialog,
|
||||
viewUserDetail,
|
||||
setSearchValue,
|
||||
showSuspendUserDialog,
|
||||
showBanUserDialog,
|
||||
}, dispatch);
|
||||
|
||||
const LOAD_MORE_QUERY = gql`
|
||||
query TalkAdminCommunity_People_LoadMoreUsers($limit: Int, $cursor: Cursor) {
|
||||
users(query: {}){
|
||||
hasNextPage
|
||||
endCursor
|
||||
nodes {
|
||||
__typename
|
||||
id
|
||||
username
|
||||
created_at
|
||||
profiles {
|
||||
id
|
||||
provider
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default compose(
|
||||
connect(null, mapDispatchToProps),
|
||||
withSetUserRole,
|
||||
@@ -128,10 +139,26 @@ export default compose(
|
||||
nodes {
|
||||
__typename
|
||||
id
|
||||
username
|
||||
role
|
||||
created_at
|
||||
profiles {
|
||||
id
|
||||
provider
|
||||
}
|
||||
state {
|
||||
status {
|
||||
banned {
|
||||
status
|
||||
}
|
||||
suspension {
|
||||
until
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
`,
|
||||
}),
|
||||
)(PeopleContainer);
|
||||
|
||||
@@ -150,6 +150,7 @@
|
||||
box-shadow: none;
|
||||
color: white;
|
||||
background-color: #616161;
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
> .icon {
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
.dropdown {
|
||||
position: relative;
|
||||
width: 150px;
|
||||
height: 36px;
|
||||
height: 34px;
|
||||
background: #2c2c2c;
|
||||
box-sizing: border-box;
|
||||
color: white;
|
||||
border-radius: 2px;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12);
|
||||
|
||||
line-height: 1.4;
|
||||
font-size: 13px;
|
||||
font-size: 0.98em;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.toggle {
|
||||
padding: 10px 15px;
|
||||
padding: 8px 15px;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
|
||||
@@ -58,5 +58,5 @@
|
||||
right: 15px;
|
||||
font-size: 1.2rem;
|
||||
vertical-align: middle;
|
||||
top: 13px;
|
||||
top: 11px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user