Merge branch 'master' into onbuild

This commit is contained in:
Wyatt Johnson
2017-10-23 12:33:56 -06:00
committed by GitHub
7 changed files with 123 additions and 49 deletions
@@ -20,3 +20,9 @@ export const toggleSelectCommentInUserDetail = (id, active) => {
};
};
export const toggleSelectAllCommentInUserDetail = (ids, active) => {
return {
type: active ? actions.SELECT_ALL_USER_DETAIL_COMMENT : actions.CLEAR_USER_DETAIL_SELECTIONS,
ids
};
};
@@ -39,7 +39,8 @@
margin-right: 0px;
}
.statItem, .statReportResult {
.statItem,
.statReportResult {
padding: 3px 5px;
background-color: #D8D8D8;
border-radius: 3px;
@@ -48,7 +49,7 @@
font-size: 0.9em;
line-height: normal;
letter-spacing: 0.4px;
min-width: 60px;
min-width: 60px;
}
.statResult {
@@ -94,12 +95,11 @@
}
.commentStatuses {
padding: 10px 0 0 0;
padding: 0 0 0 10px;
margin: 0;
height: 52px;
align-self: center;
list-style: none;
box-sizing: border-box;
li {
display: inline-block;
margin-right: 10px;
@@ -116,11 +116,11 @@
.bulkActionGroup {
height: 52px;
background-color: #efefef;
padding: 0 0 0 10px;
display: flex;
i {
margin-right: 0;
}
.bulkAction {
display: inline-block;
width: 48px;
@@ -128,17 +128,39 @@
transform: scale(.7);
min-width: 0;
}
.bulkAction:last-child {
margin-left: -10px;
}
}
.loadMore > button {
background-color: #696969;
.selectedCommentsInfo {
align-self: center;
font-weight: 500;
margin-left: 15px;
}
.loadMore>button {
background-color: #696969;
&:hover {
background-color: #404040;
color: white;
}
}
.toggleAll {
padding: 0 10px 0 0;
align-self: center;
}
.commentList {
clear: both;
}
.bulkActionHeader {
display: flex;
justify-content: space-between;
height: 52px;
&.selected {
background-color: #efefef;
}
}
+73 -37
View File
@@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import Comment from '../containers/UserDetailComment';
import styles from './UserDetail.css';
import {Icon, Button, Drawer, Spinner} from 'coral-ui';
import {Icon, Drawer, Spinner} from 'coral-ui';
import {Slot} from 'coral-framework/components';
import ButtonCopyToClipboard from './ButtonCopyToClipboard';
import ClickOutside from 'coral-framework/components/ClickOutside';
@@ -10,6 +10,9 @@ import LoadMore from '../components/LoadMore';
import cn from 'classnames';
import capitalize from 'lodash/capitalize';
import {getReliability} from 'coral-framework/utils/user';
import ApproveButton from './ApproveButton';
import RejectButton from './RejectButton';
import {getErrorMessages} from 'coral-framework/utils';
export default class UserDetail extends React.Component {
@@ -23,6 +26,7 @@ export default class UserDetail extends React.Component {
toggleSelect: PropTypes.func.isRequired,
bulkAccept: PropTypes.func.isRequired,
bulkReject: PropTypes.func.isRequired,
toggleSelectAll: PropTypes.func.isRequired,
loading: PropTypes.bool.isRequired,
data: PropTypes.shape({
refetch: PropTypes.func.isRequired,
@@ -30,7 +34,8 @@ export default class UserDetail extends React.Component {
activeTab: PropTypes.string.isRequired,
selectedCommentIds: PropTypes.array.isRequired,
viewUserDetail: PropTypes.any.isRequired,
loadMore: PropTypes.any.isRequired
loadMore: PropTypes.any.isRequired,
notify: PropTypes.func.isRequired
}
rejectThenReload = async (info) => {
@@ -41,6 +46,7 @@ export default class UserDetail extends React.Component {
// TODO: handle error.
console.error(err);
this.props.notify('error', getErrorMessages(err));
}
}
@@ -52,6 +58,31 @@ export default class UserDetail extends React.Component {
// TODO: handle error.
console.error(err);
this.props.notify('error', getErrorMessages(err));
}
}
bulkAcceptThenReload = async () => {
try {
await this.props.bulkAccept();
this.props.data.refetch();
} catch (err) {
// TODO: handle error.
console.error(err);
this.props.notify('error', getErrorMessages(err));
}
}
bulkRejectThenReload = async () => {
try {
await this.props.bulkReject();
this.props.data.refetch();
} catch (err) {
// TODO: handle error.
console.error(err);
this.props.notify('error', getErrorMessages(err));
}
}
@@ -86,11 +117,10 @@ export default class UserDetail extends React.Component {
activeTab,
selectedCommentIds,
toggleSelect,
bulkAccept,
bulkReject,
hideUserDetail,
viewUserDetail,
loadMore,
toggleSelectAll
} = this.props;
let rejectedPercent = (rejectedComments / totalComments) * 100;
@@ -108,14 +138,14 @@ export default class UserDetail extends React.Component {
<div>
<ul className={styles.userDetailList}>
<li>
<Icon name="assignment_ind"/>
<Icon name="assignment_ind" />
<span className={styles.userDetailItem}>Member Since:</span>
{new Date(user.created_at).toLocaleString()}
</li>
{user.profiles.map(({id}) =>
<li key={id}>
<Icon name="email"/>
<Icon name="email" />
<span className={styles.userDetailItem}>Email:</span>
{id} <ButtonCopyToClipboard className={styles.copyButton} icon="content_copy" copyText={id} />
</li>
@@ -147,36 +177,42 @@ export default class UserDetail extends React.Component {
data={this.props.data}
queryData={{root, user}}
/>
<hr/>
{
selectedCommentIds.length === 0
? (
<ul className={styles.commentStatuses}>
<li className={activeTab === 'all' ? styles.active : ''} onClick={this.showAll}>All</li>
<li className={activeTab === 'rejected' ? styles.active : ''} onClick={this.showRejected}>Rejected</li>
</ul>
)
: (
<div className={styles.bulkActionGroup}>
<Button
onClick={bulkAccept}
className={styles.bulkAction}
cStyle='approve'
icon='done'>
</Button>
<Button
onClick={bulkReject}
className={styles.bulkAction}
cStyle='reject'
icon='close'>
</Button>
{selectedCommentIds.length} comments selected
</div>
)
}
<div>
<hr />
<div className={(selectedCommentIds.length > 0) ? cn(styles.bulkActionHeader, styles.selected) : styles.bulkActionHeader}>
{
selectedCommentIds.length === 0
? (
<ul className={styles.commentStatuses}>
<li className={activeTab === 'all' ? styles.active : ''} onClick={this.showAll}>All</li>
<li className={activeTab === 'rejected' ? styles.active : ''} onClick={this.showRejected}>Rejected</li>
</ul>
)
: (
<div className={styles.bulkActionGroup}>
<ApproveButton
onClick={this.bulkAcceptThenReload}
minimal
/>
<RejectButton
onClick={this.bulkRejectThenReload}
minimal
/>
<span className={styles.selectedCommentsInfo}> {selectedCommentIds.length} comments selected</span>
</div>
)
}
<div className={styles.toggleAll}>
<input
type='checkbox'
id='toogleAll'
checked={selectedCommentIds.length > 0 && selectedCommentIds.length === nodes.length}
onChange={(e) => {
toggleSelectAll(nodes.map((comment) => comment.id), e.target.checked);
}} />
<label htmlFor='toogleAll'>Select all</label>
</div>
</div>
<div className={styles.commentList}>
{
nodes.map((comment) => {
const selected = selectedCommentIds.indexOf(comment.id) !== -1;
@@ -205,7 +241,7 @@ export default class UserDetail extends React.Component {
);
}
render () {
render() {
if (this.props.loading) {
return this.renderLoading();
}
@@ -4,4 +4,4 @@ export const CHANGE_USER_DETAIL_STATUSES = 'CHANGE_USER_DETAIL_STATUSES';
export const SELECT_USER_DETAIL_COMMENT = 'SELECT_USER_DETAIL_COMMENT';
export const UNSELECT_USER_DETAIL_COMMENT = 'UNSELECT_USER_DETAIL_COMMENT';
export const CLEAR_USER_DETAIL_SELECTIONS = 'CLEAR_USER_DETAIL_SELECTIONS';
export const SELECT_ALL_USER_DETAIL_COMMENT = 'SELECT_ALL_USER_DETAIL_COMMENT';
@@ -11,10 +11,12 @@ import {
changeUserDetailStatuses,
clearUserDetailSelections,
toggleSelectCommentInUserDetail,
toggleSelectAllCommentInUserDetail
} from 'coral-admin/src/actions/userDetail';
import {withSetCommentStatus} from 'coral-framework/graphql/mutations';
import UserDetailComment from './UserDetailComment';
import update from 'immutability-helper';
import {notify} from 'coral-framework/actions/notification';
const commentConnectionFragment = gql`
fragment CoralAdmin_Moderation_CommentConnection on CommentConnection {
@@ -120,6 +122,7 @@ class UserDetailContainer extends React.Component {
bulkAccept={this.bulkAccept}
changeStatus={this.props.changeUserDetailStatuses}
toggleSelect={this.props.toggleSelectCommentInUserDetail}
toggleSelectAll={this.props.toggleSelectAllCommentInUserDetail}
acceptComment={this.acceptComment}
rejectComment={this.rejectComment}
loading={loading}
@@ -188,6 +191,8 @@ const mapDispatchToProps = (dispatch) => ({
toggleSelectCommentInUserDetail,
viewUserDetail,
hideUserDetail,
toggleSelectAllCommentInUserDetail,
notify
}, dispatch)
});
@@ -41,6 +41,11 @@ export default function banUserDialog(state = initialState, action) {
...state,
selectedCommentIds: state.selectedCommentIds.filter((id) => id !== action.id),
};
case actions.SELECT_ALL_USER_DETAIL_COMMENT:
return {
...state,
selectedCommentIds: action.ids
};
default:
return state;
}
+1 -1
View File
@@ -119,7 +119,7 @@ const CONFIG = {
//------------------------------------------------------------------------------
// Port to bind to.
PORT: process.env.TALK_PORT || process.env.PORT || process.env.NODE_ENV === 'test' ? '3001' : '3000',
PORT: process.env.TALK_PORT || process.env.PORT || (process.env.NODE_ENV === 'test' ? '3001' : '3000'),
// The URL for this Talk Instance as viewable from the outside.
ROOT_URL: process.env.TALK_ROOT_URL || null,