mirror of
https://github.com/wassname/talk.git
synced 2026-06-28 22:21:45 +08:00
Implement user flag details as slot component
This commit is contained in:
@@ -7,23 +7,21 @@ import {Slot, IfSlotIsNotEmpty, CommentDetail} from 'plugin-api/beta/client/comp
|
||||
class FlagDetails extends Component {
|
||||
|
||||
render() {
|
||||
const {comment: {actions}, viewUserDetail, more, data, root, comment} = this.props;
|
||||
const {comment: {actions}, more, data, root, comment} = this.props;
|
||||
|
||||
const flagActions = actions && actions.filter((a) => a.__typename === 'FlagAction');
|
||||
const summaries = flagActions.reduce((sum, action) => {
|
||||
if (!(action.reason in sum)) {
|
||||
sum[action.reason] = {count: 0, userFlagged: false, actions: []};
|
||||
sum[action.reason] = {count: 0, 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);
|
||||
|
||||
const reasons = Object.keys(summaries);
|
||||
const queryData = {
|
||||
root,
|
||||
comment,
|
||||
@@ -35,36 +33,13 @@ class FlagDetails extends Component {
|
||||
header={`${t('community.flags')} (${Object.keys(summaries).length})`}
|
||||
info={
|
||||
<ul className={styles.info}>
|
||||
{Object.keys(summaries).map((reason) =>
|
||||
{reasons.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>
|
||||
)}
|
||||
{more && (
|
||||
<IfSlotIsNotEmpty
|
||||
slot="adminCommentMoreFlagDetails"
|
||||
@@ -84,13 +59,14 @@ class FlagDetails extends Component {
|
||||
|
||||
FlagDetails.propTypes = {
|
||||
more: PropTypes.bool,
|
||||
data: PropTypes.object,
|
||||
root: PropTypes.object,
|
||||
comment: PropTypes.shape({
|
||||
actions: PropTypes.arrayOf(PropTypes.shape({
|
||||
message: PropTypes.string,
|
||||
user: PropTypes.shape({username: PropTypes.string})
|
||||
})).isRequired,
|
||||
}).isRequired,
|
||||
viewUserDetail: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default FlagDetails;
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
.info {
|
||||
vertical-align: middle;
|
||||
list-style: none;
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
font-size: 12px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.detail {
|
||||
margin: 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import React, {Component} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styles from './UserFlagDetails.css';
|
||||
|
||||
class UserFlagDetails extends Component {
|
||||
|
||||
render() {
|
||||
const {comment: {actions}, viewUserDetail} = this.props;
|
||||
|
||||
const flagActions = actions && actions.filter((a) => a.__typename === 'FlagAction');
|
||||
const summaries = flagActions.reduce((sum, action) => {
|
||||
if (!action.user) {
|
||||
return sum;
|
||||
}
|
||||
if (!(action.reason in sum)) {
|
||||
sum[action.reason] = {count: 0, actions: []};
|
||||
}
|
||||
sum[action.reason].count++;
|
||||
sum[action.reason].actions.push(action);
|
||||
return sum;
|
||||
}, {});
|
||||
|
||||
return (
|
||||
<ul className={styles.detail}>
|
||||
{Object.keys(summaries)
|
||||
.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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
UserFlagDetails.propTypes = {
|
||||
comment: PropTypes.shape({
|
||||
actions: PropTypes.arrayOf(PropTypes.shape({
|
||||
message: PropTypes.string,
|
||||
user: PropTypes.shape({username: PropTypes.string})
|
||||
})).isRequired,
|
||||
}).isRequired,
|
||||
viewUserDetail: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default UserFlagDetails;
|
||||
@@ -1,23 +1,13 @@
|
||||
import {compose, gql} from 'react-apollo';
|
||||
import FlagDetails from '../components/FlagDetails';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {withFragments, excludeIf} from 'plugin-api/beta/client/hocs';
|
||||
import {viewUserDetail} from 'plugin-api/beta/client/actions/admin';
|
||||
import {connect} from 'react-redux';
|
||||
import {getSlotFragmentSpreads} from 'plugin-api/beta/client/utils';
|
||||
|
||||
const slots = [
|
||||
'adminCommentMoreFlagDetails',
|
||||
];
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
...bindActionCreators({
|
||||
viewUserDetail,
|
||||
}, dispatch)
|
||||
});
|
||||
|
||||
const enhance = compose(
|
||||
connect(null, mapDispatchToProps),
|
||||
withFragments({
|
||||
root: gql`
|
||||
fragment CoralAdmin_FlagDetails_root on RootQuery {
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import {compose, gql} from 'react-apollo';
|
||||
import UserFlagDetails from '../components/UserFlagDetails';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {withFragments, excludeIf} from 'plugin-api/beta/client/hocs';
|
||||
import {viewUserDetail} from 'plugin-api/beta/client/actions/admin';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
...bindActionCreators({
|
||||
viewUserDetail,
|
||||
}, dispatch)
|
||||
});
|
||||
|
||||
const enhance = compose(
|
||||
connect(null, mapDispatchToProps),
|
||||
withFragments({
|
||||
comment: gql`
|
||||
fragment CoralAdmin_UserFlagDetails_comment on Comment {
|
||||
actions {
|
||||
__typename
|
||||
... on FlagAction {
|
||||
id
|
||||
reason
|
||||
message
|
||||
user {
|
||||
id
|
||||
username
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
}),
|
||||
excludeIf(({comment: {actions}}) =>
|
||||
!actions.some((action) => action.__typename === 'FlagAction' && action.user
|
||||
)),
|
||||
);
|
||||
|
||||
export default enhance(UserFlagDetails);
|
||||
@@ -1,9 +1,11 @@
|
||||
import FlagDetails from './containers/FlagDetails';
|
||||
import UserFlagDetails from './containers/UserFlagDetails';
|
||||
import translations from './translations.yml';
|
||||
|
||||
export default {
|
||||
translations,
|
||||
slots: {
|
||||
adminCommentDetailArea: [FlagDetails],
|
||||
adminCommentMoreFlagDetails: [UserFlagDetails],
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user