Merge branch 'master' into default-resolve-type

This commit is contained in:
Kiwi
2017-04-20 16:55:04 +07:00
committed by GitHub
9 changed files with 117 additions and 31 deletions
@@ -116,7 +116,7 @@ class ModerationContainer extends Component {
let asset;
if (data.loading) {
if (!('premodCount' in data)) {
return <div><Spinner/></div>;
}
@@ -17,25 +17,27 @@ import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations.json';
const lang = new I18n(translations);
const Comment = ({actions = [], ...props}) => {
const links = linkify.getMatches(props.comment.body);
const Comment = ({actions = [], comment, ...props}) => {
const links = linkify.getMatches(comment.body);
const linkText = links ? links.map(link => link.raw) : [];
const actionSummaries = props.comment.action_summaries;
const actionSummaries = comment.action_summaries.filter(a => a.__typename === 'FlagActionSummary');
const flagActions = comment.actions.filter(a => a.__typename === 'FlagAction');
return (
<li tabIndex={props.index} className={`mdl-card ${props.selected ? 'mdl-shadow--8dp' : 'mdl-shadow--2dp'} ${styles.Comment} ${styles.listItem}`}>
<div className={styles.container}>
<div className={styles.itemHeader}>
<div className={styles.author}>
<span>
{props.comment.user.name}
{comment.user.name}
</span>
<span className={styles.created}>
{timeago().format(props.comment.created_at || (Date.now() - props.index * 60 * 1000), lang.getLocale().replace('-', '_'))}
{timeago().format(comment.created_at || (Date.now() - props.index * 60 * 1000), lang.getLocale().replace('-', '_'))}
</span>
<BanUserButton user={props.comment.user} onClick={() => props.showBanUserDialog(props.comment.user, props.comment.id, props.comment.status !== 'REJECTED')} />
<BanUserButton user={comment.user} onClick={() => props.showBanUserDialog(comment.user, comment.id, comment.status !== 'REJECTED')} />
<CommentType type={props.commentType} />
</div>
{props.comment.user.status === 'banned' ?
{comment.user.status === 'banned' ?
<span className={styles.banned}>
<Icon name='error_outline'/>
{lang.t('comment.banned_user')}
@@ -43,16 +45,16 @@ const Comment = ({actions = [], ...props}) => {
: null}
</div>
<div className={styles.moderateArticle}>
Story: {props.comment.asset.title}
Story: {comment.asset.title}
{!props.currentAsset && (
<Link to={`/admin/moderate/${props.comment.asset.id}`}>Moderate &rarr;</Link>
<Link to={`/admin/moderate/${comment.asset.id}`}>Moderate </Link>
)}
</div>
<div className={styles.itemBody}>
<p className={styles.body}>
<Highlighter
searchWords={[...props.suspectWords, ...props.bannedWords, ...linkText]}
textToHighlight={props.comment.body} />
textToHighlight={comment.body} />
</p>
<div className={styles.sideActions}>
{links ? <span className={styles.hasLinks}><Icon name='error_outline'/> Contains Link</span> : null}
@@ -60,16 +62,16 @@ const Comment = ({actions = [], ...props}) => {
{actions.map((action, i) =>
<ActionButton key={i}
type={action}
user={props.comment.user}
acceptComment={() => props.acceptComment({commentId: props.comment.id})}
rejectComment={() => props.rejectComment({commentId: props.comment.id})}
user={comment.user}
acceptComment={() => props.acceptComment({commentId: comment.id})}
rejectComment={() => props.rejectComment({commentId: comment.id})}
/>
)}
</div>
</div>
</div>
</div>
{actionSummaries && <FlagBox actionSummaries={actionSummaries} />}
{flagActions && <FlagBox actions={flagActions} actionSummaries={actionSummaries} />}
</li>
);
};
@@ -83,6 +85,7 @@ Comment.propTypes = {
comment: PropTypes.shape({
body: PropTypes.string.isRequired,
action_summaries: PropTypes.array,
actions: PropTypes.array,
created_at: PropTypes.string.isRequired,
user: PropTypes.shape({
status: PropTypes.string
@@ -53,3 +53,17 @@
font-size: 12px;
}
}
.lessDetail {
display: inline-block;
margin-right: 10px;
}
.subDetail {
font-weight: normal;
color: #888;
span {
color: black;
}
}
@@ -1,6 +1,17 @@
import React, {Component, PropTypes} from 'react';
import {Icon} from 'coral-ui';
import styles from './FlagBox.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations.json';
const lang = new I18n(translations);
const shortReasons = {
'This comment is offensive': lang.t('modqueue.offensive'),
'This looks like an ad/marketing': lang.t('modqueue.spam/ads'),
'This user is impersonating': lang.t('modqueue.impersonating'),
'I don\'t like this username': lang.t('modqueue.dont-like-username'),
'Other': lang.t('modqueue.other')
};
class FlagBox extends Component {
constructor () {
@@ -16,27 +27,50 @@ class FlagBox extends Component {
}));
}
reasonMap = (reason) => {
const shortReason = shortReasons[reason];
// if the short reason isn't found, just return the long one.
return shortReason ? shortReason : reason;
}
render() {
const {props} = this;
const {actionSummaries, actions} = this.props;
const {showDetail} = this.state;
return (
<div className={styles.flagBox}>
<div className={styles.container}>
<div className={styles.header}>
<Icon name='flag'/><h3>Flags ({props.actionSummaries.length}):</h3>
<Icon name='flag'/><h3>Flags ({actionSummaries.length}):</h3>
<ul>
{props.actionSummaries.map((action, i) =>
<li key={i}>{!action.reason ? <i>No reason provided</i> : action.reason} (<strong>{action.count}</strong>)</li>
{actionSummaries.map((action, i) =>
<li key={i} className={styles.lessDetail}>{this.reasonMap(action.reason)} (<strong>{action.count}</strong>)</li>
)}
</ul>
{/* <a onClick={this.toggleDetail} className={styles.moreDetail}>More detail</a>*/}
<a onClick={this.toggleDetail} className={styles.moreDetail}>{showDetail ? lang.t('modqueue.less-detail') : lang.t('modqueue.more-detail')}</a>
</div>
{this.state.showDetail && (<div className={styles.detail}>
<ul>
{props.actionSummaries.map((action, i) =>
<li key={i}>{!action.reason ? <i>No reason provided</i> : action.reason} (<strong>{action.count}</strong>)</li>
)}
</ul>
</div>)}
{showDetail && (
<div className={styles.detail}>
<ul>
{actionSummaries.map((summary, i) => {
const actionList = actions.filter(a => a.reason === summary.reason);
return (
<li key={i}>
{this.reasonMap(summary.reason)} (<strong>{summary.count}</strong>)
<ul>
{
actionList.map((action, j) => <li key={`${i}_${j}`} className={styles.subDetail}><span>{action.user.username}</span> {action.message}</li>)
}
</ul>
</li>
);
})}
</ul>
</div>
)}
</div>
</div>
);
@@ -44,7 +78,14 @@ class FlagBox extends Component {
}
FlagBox.propTypes = {
actionSummaries: PropTypes.array.isRequired
actionSummaries: PropTypes.arrayOf(PropTypes.shape({
reason: PropTypes.string,
count: PropTypes.number
})).isRequired,
actions: PropTypes.arrayOf(PropTypes.shape({
message: PropTypes.string,
user: PropTypes.shape({username: PropTypes.string})
})).isRequired
};
export default FlagBox;
@@ -12,4 +12,13 @@ fragment commentView on Comment {
id
title
}
actions {
... on FlagAction {
reason
message
user {
username
}
}
}
}
@@ -55,7 +55,7 @@ export const loadMore = (fetchMore) => ({limit, cursor, sort, tab, asset_id}) =>
statuses,
asset_id
},
updateQuery: (oldData, {fetchMoreResult:{data:{comments}}}) => {
updateQuery: (oldData, {fetchMoreResult:{comments}}) => {
return {
...oldData,
[tab]: [
+16 -2
View File
@@ -51,7 +51,14 @@
"singleview": "Toggle single comment edit view",
"thismenu": "Open this menu",
"emptyqueue": "No more comments to moderate! You're all caught up. Go have some ☕️",
"showshortcuts": "Show Shortcuts"
"showshortcuts": "Show Shortcuts",
"more-detail": "More detail",
"less-detail": "Less detail",
"dont-like-username": "Don't like username",
"impersonating": "Impersonating",
"offensive": "Offensive",
"spam/ads": "Spam/Ads",
"other": "Other"
},
"comment": {
"flagged": "flagged",
@@ -221,7 +228,14 @@
"shortcuts": "Atajos de teclado",
"close": "Cerrar",
"emptyqueue": "No se encontro ningún usuario. Están escondidos.",
"showshortcuts": "Mostrar atajos"
"showshortcuts": "Mostrar atajos",
"more-detail": "Mas detalle",
"less-detail": "Menos detalle",
"dont-like-username": "No me gusta ese nombre de usuario",
"impersonating": "Suplantación",
"offensive": "Ofensivo",
"spam/ads": "Spam/Propaganda",
"other": "Otros"
},
"comment": {
"flagged": "marcado",
@@ -1,9 +1,12 @@
import pym from '../services/PymConnection';
import * as actions from '../constants/notification';
export const addNotification = (notifType, text) => {
pym.sendMessage('coral-alert', `${notifType}|${text}`);
return {type: actions.ADD_NOTIFICATION, notifType, text};
};
export const clearNotification = () => {
pym.sendMessage('coral-clear-notification');
return {type: actions.CLEAR_NOTIFICATION};
};
@@ -0,0 +1,2 @@
export const ADD_NOTIFICATION = 'ADD_NOTIFICATION';
export const CLEAR_NOTIFICATION = 'CLEAR_NOTIFICATION';