adminCommentMoreFlagDetails slot and more

This commit is contained in:
Chi Vinh Le
2017-09-29 23:34:40 +07:00
parent 9bd55b267e
commit 7d41421526
16 changed files with 83 additions and 129 deletions
@@ -1,5 +1,4 @@
.root {
margin-left: 16px;
}
.headerContainer {
@@ -25,6 +24,10 @@
.details {
padding: 0 20px 16px;
font-size: 12px;
&:empty {
display: none;
}
}
.icon {
@@ -1,6 +1,6 @@
.root {
margin-top: 10px;
padding-top: 10px;
min-height: 24px;
padding: 0 16px;
}
.moreDetail {
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import styles from './CommentDetails.css';
import t from 'coral-framework/services/i18n';
import Slot from 'coral-framework/components/Slot';
import IfSlotIsNotEmpty from 'coral-framework/components/IfSlotIsNotEmpty';
class CommentDetails extends Component {
state = {
@@ -32,13 +33,25 @@ class CommentDetails extends Component {
return (
<div className={styles.root}>
<a onClick={this.toggleDetail} className={styles.moreDetail}>{showDetail ? t('modqueue.less_detail') : t('modqueue.more_detail')}</a>
<IfSlotIsNotEmpty
queryData={queryData}
slot={['adminCommentMoreDetails', 'adminCommentMoreFlagDetails']}
>
<a onClick={this.toggleDetail} className={styles.moreDetail}>
{showDetail ? t('modqueue.less_detail') : t('modqueue.more_detail')}
</a>
</IfSlotIsNotEmpty>
<Slot
fill="adminCommentDetailArea"
data={data}
queryData={queryData}
more={showDetail}
/>
{showDetail && <Slot
fill="adminCommentMoreDetails"
data={data}
queryData={queryData}
/>}
</div>
);
}
@@ -1,43 +0,0 @@
.info {
vertical-align: middle;
list-style: none;
display: inline-block;
padding: 0;
font-size: 12px;
}
.detail {
padding: 0;
list-style: none;
font-size: 12px;
font-weight: 500;
}
.subDetail {
margin-left:10px;
padding: 0;
list-style: none;
font-size: 12px;
font-weight: normal;
color: #888;
}
.lessDetail {
display: inline-block;
margin-right: 10px;
}
.username {
color: #393B44;
text-decoration: none;
cursor: pointer;
font-weight: 600;
padding: 2px 5px;
border-radius: 2px;
margin-left: -5px;
transition: background-color 200ms ease;
&:hover {
background-color: #E0E0E0;
}
}
@@ -1,75 +0,0 @@
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import styles from './FlagDetails.css';
import t from 'coral-framework/services/i18n';
import CommentDetail from './CommentDetail';
class FlagDetails extends Component {
render() {
const {actions, viewUserDetail, more} = this.props;
const summaries = actions.reduce((sum, action) => {
if (!(action.reason in sum)) {
sum[action.reason] = {count: 0, userFlagged: false, actions: []};
}
sum[action.reason].count++;
if (action.user) {
sum[action.reason].userFlagged = true;
}
sum[action.reason].actions.push(action);
return sum;
}, {});
const userFlagReasons = Object.keys(summaries).filter((reason) => summaries[reason].userFlagged);
return (
<CommentDetail
icon={'flag'}
header={`${t('community.flags')} (${Object.keys(summaries).length})`}
info={
<ul className={styles.info}>
{Object.keys(summaries).map((reason) =>
<li key={reason} className={styles.lessDetail}>
{reason} {summaries[reason].userFlagged && `(${summaries[reason].count})`}
</li>
)}
</ul>
}>
{more && userFlagReasons.length > 0 && (
<ul className={styles.detail}>
{userFlagReasons
.map((reason) => (
<li key={reason}>
{reason} ({summaries[reason].count})
<ul className={styles.subDetail}>
{summaries[reason].actions.map((action) =>
<li key={action.user.id}>
{action.user &&
<a className={styles.username} onClick={() => viewUserDetail(action.user.id)}>
{action.user.username}
</a>
}
{action.message}
</li>
)}
</ul>
</li>
))
}
</ul>
)}
</CommentDetail>
);
}
}
FlagDetails.propTypes = {
more: PropTypes.bool,
actions: PropTypes.arrayOf(PropTypes.shape({
message: PropTypes.string,
user: PropTypes.shape({username: PropTypes.string})
})).isRequired,
viewUserDetail: PropTypes.func.isRequired,
};
export default FlagDetails;
@@ -1,4 +1,5 @@
.root {
position: relative;
display: block;
margin: 0;
border-bottom: 1px solid #e0e0e0;
@@ -70,7 +70,7 @@ class UserDetailComment extends React.Component {
</div>
<CommentAnimatedEdit body={comment.body}>
<div className={styles.bodyContainer}>
<p className={styles.body}>
<div className={styles.body}>
<CommentBodyHighlighter
suspectWords={suspectWords}
bannedWords={bannedWords}
@@ -84,7 +84,7 @@ class UserDetailComment extends React.Component {
>
<Icon name="open_in_new" /> {t('comment.view_context')}
</a>
</p>
</div>
<div className={styles.sideActions}>
<IfHasLink text={comment.body}>
<span className={styles.hasLinks}>
@@ -5,6 +5,7 @@ import withFragments from 'coral-framework/hocs/withFragments';
const slots = [
'adminCommentDetailArea',
'adminCommentMoreDetails',
];
export default withFragments({
@@ -58,6 +58,7 @@
font-size: 14px;
line-height: 1.5;
font-weight: 300;
margin-bottom: 8px;
}
.body {
@@ -5,9 +5,11 @@
display: inline-block;
padding: 0;
font-size: 12px;
margin: 0;
}
.detail {
margin: 0;
padding: 0;
list-style: none;
font-size: 12px;
@@ -3,11 +3,12 @@ import PropTypes from 'prop-types';
import styles from './FlagDetails.css';
import {t} from 'plugin-api/beta/client/services';
import CommentDetail from 'coral-admin/src/components/CommentDetail';
import {Slot, IfSlotIsNotEmpty} from 'plugin-api/beta/client/components';
class FlagDetails extends Component {
render() {
const {comment: {actions}, viewUserDetail, more} = this.props;
const {comment: {actions}, viewUserDetail, more, data, root, comment} = this.props;
const flagActions = actions && actions.filter((a) => a.__typename === 'FlagAction');
const summaries = flagActions.reduce((sum, action) => {
@@ -24,6 +25,11 @@ class FlagDetails extends Component {
const userFlagReasons = Object.keys(summaries).filter((reason) => summaries[reason].userFlagged);
const queryData = {
root,
comment,
};
return (
<CommentDetail
icon={'flag'}
@@ -60,6 +66,18 @@ class FlagDetails extends Component {
}
</ul>
)}
{more && (
<IfSlotIsNotEmpty
slot="adminCommentMoreFlagDetails"
queryData={queryData}
>
<Slot
fill="adminCommentMoreFlagDetails"
data={data}
queryData={queryData}
/>
</IfSlotIsNotEmpty>
)}
</CommentDetail>
);
}
@@ -4,6 +4,11 @@ import {bindActionCreators} from 'redux';
import {withFragments, excludeIf} from 'plugin-api/beta/client/hocs';
import {viewUserDetail} from 'coral-admin/src/actions/userDetail';
import {connect} from 'react-redux';
import {getSlotFragmentSpreads} from 'plugin-api/beta/client/utils';
const slots = [
'adminCommentMoreFlagDetails',
];
const mapDispatchToProps = (dispatch) => ({
...bindActionCreators({
@@ -14,6 +19,12 @@ const mapDispatchToProps = (dispatch) => ({
const enhance = compose(
connect(null, mapDispatchToProps),
withFragments({
root: gql`
fragment CoralAdmin_FlagDetails_root on RootQuery {
__typename
${getSlotFragmentSpreads(slots, 'root')}
}
`,
comment: gql`
fragment CoralAdmin_FlagDetails_comment on Comment {
actions {
@@ -28,6 +39,7 @@ const enhance = compose(
}
}
}
${getSlotFragmentSpreads(slots, 'comment')}
}
`
}),
@@ -0,0 +1,10 @@
import {compose} from 'react-apollo';
import {excludeIf} from 'plugin-api/beta/client/hocs';
import ToxicDetail from './ToxicDetail';
import {isToxic} from '../utils';
const enhance = compose(
excludeIf(({comment: {toxicity, actions}}) => toxicity === null || isToxic(actions)),
);
export default enhance(ToxicDetail);
@@ -0,0 +1,10 @@
import {compose} from 'react-apollo';
import {excludeIf} from 'plugin-api/beta/client/hocs';
import ToxicDetail from './ToxicDetail';
import {isToxic} from '../utils';
const enhance = compose(
excludeIf(({comment: {toxicity, actions}}) => toxicity === null || !isToxic(actions)),
);
export default enhance(ToxicDetail);
@@ -1,5 +1,5 @@
import {compose, gql} from 'react-apollo';
import {withFragments, excludeIf} from 'plugin-api/beta/client/hocs';
import {withFragments} from 'plugin-api/beta/client/hocs';
import ToxicDetail from '../components/ToxicDetail';
const enhance = compose(
@@ -15,7 +15,6 @@ const enhance = compose(
}
}`,
}),
excludeIf(({comment: {toxicity}, more}) => !more || toxicity === null),
);
export default enhance(ToxicDetail);
@@ -1,13 +1,15 @@
import translations from './translations.yml';
import CheckToxicityHook from './containers/CheckToxicityHook';
import ToxicLabel from './containers/ToxicLabel';
import ToxicDetail from './containers/ToxicDetail';
import ToxicCommentDetail from './containers/ToxicCommentDetail';
import ToxicCommentFlagDetail from './containers/ToxicCommentFlagDetail';
export default {
translations,
slots: {
commentInputDetailArea: [CheckToxicityHook],
adminCommentLabels: [ToxicLabel],
adminCommentDetailArea: [ToxicDetail],
adminCommentMoreDetails: [ToxicCommentDetail],
adminCommentMoreFlagDetails: [ToxicCommentFlagDetail],
},
};