From f9693c7154e4be66aebbea262d9a055669a3602d Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Fri, 29 Sep 2017 19:42:44 +0700 Subject: [PATCH] Refactor and pluginize comment details --- .eslintignore | 1 + .gitignore | 1 + .../src/components/ActionButton.css | 24 ------ .../src/components/ActionButton.js | 38 --------- .../src/components/ApproveButton.css | 44 +++++++++++ .../src/components/ApproveButton.js | 30 +++++++ .../src/components/CommentDetails.js | 23 +++--- .../src/components/RejectButton.css | 44 +++++++++++ .../src/components/RejectButton.js | 30 +++++++ .../coral-admin/src/components/UserDetail.js | 6 +- .../src/components/UserDetailComment.js | 66 +++++++--------- .../src/containers/CommentDetails.js | 23 ++++++ .../src/containers/CommentLabels.js | 6 ++ .../coral-admin/src/containers/UserDetail.js | 2 + .../src/containers/UserDetailComment.js | 25 +++--- .../Community/components/ActionButton.css | 4 - .../Community/components/ActionButton.js | 22 ------ .../Community/components/FlaggedAccounts.js | 1 - .../Community/components/FlaggedUser.js | 25 +++--- .../components/RejectUsernameDialog.js | 2 +- .../routes/Community/containers/Community.js | 6 +- .../routes/Moderation/components/Comment.js | 68 ++++++---------- .../Moderation/components/ModerationQueue.js | 5 -- .../routes/Moderation/containers/Comment.js | 29 ++----- .../Moderation/containers/Moderation.js | 2 + .../src/utils/moderationQueueActionsMap.js | 14 ---- client/coral-ui/components/Button.css | 53 ------------- .../talk-plugin-flag-details/.eslintrc.json | 3 + .../talk-plugin-flag-details/client/.babelrc | 14 ++++ .../client/.eslintrc.json | 3 + .../client/components/FlagDetails.css | 43 ++++++++++ .../client/components/FlagDetails.js | 79 +++++++++++++++++++ .../client/containers/FlagDetails.js | 37 +++++++++ .../talk-plugin-flag-details/client/index.js | 9 +++ .../client/translations.yml | 3 + plugins/talk-plugin-flag-details/index.js | 1 + .../client/containers/ToxicDetail.js | 2 +- 37 files changed, 486 insertions(+), 302 deletions(-) delete mode 100644 client/coral-admin/src/components/ActionButton.css delete mode 100644 client/coral-admin/src/components/ActionButton.js create mode 100644 client/coral-admin/src/components/ApproveButton.css create mode 100644 client/coral-admin/src/components/ApproveButton.js create mode 100644 client/coral-admin/src/components/RejectButton.css create mode 100644 client/coral-admin/src/components/RejectButton.js create mode 100644 client/coral-admin/src/containers/CommentDetails.js delete mode 100644 client/coral-admin/src/routes/Community/components/ActionButton.css delete mode 100644 client/coral-admin/src/routes/Community/components/ActionButton.js delete mode 100644 client/coral-admin/src/utils/moderationQueueActionsMap.js create mode 100644 plugins/talk-plugin-flag-details/.eslintrc.json create mode 100644 plugins/talk-plugin-flag-details/client/.babelrc create mode 100644 plugins/talk-plugin-flag-details/client/.eslintrc.json create mode 100644 plugins/talk-plugin-flag-details/client/components/FlagDetails.css create mode 100644 plugins/talk-plugin-flag-details/client/components/FlagDetails.js create mode 100644 plugins/talk-plugin-flag-details/client/containers/FlagDetails.js create mode 100644 plugins/talk-plugin-flag-details/client/index.js create mode 100644 plugins/talk-plugin-flag-details/client/translations.yml create mode 100644 plugins/talk-plugin-flag-details/index.js diff --git a/.eslintignore b/.eslintignore index fc0214dd2..22cf3d4b8 100644 --- a/.eslintignore +++ b/.eslintignore @@ -26,5 +26,6 @@ plugins/* !plugins/talk-plugin-toxic-comments !plugins/talk-plugin-remember-sort !plugins/talk-plugin-deep-reply-count +!plugins/talk-plugin-flag-details node_modules diff --git a/.gitignore b/.gitignore index bcc7c89b1..e253c5904 100644 --- a/.gitignore +++ b/.gitignore @@ -43,5 +43,6 @@ plugins/* !plugins/talk-plugin-toxic-comments !plugins/talk-plugin-remember-sort !plugins/talk-plugin-deep-reply-count +!plugins/talk-plugin-flag-details **/node_modules/* diff --git a/client/coral-admin/src/components/ActionButton.css b/client/coral-admin/src/components/ActionButton.css deleted file mode 100644 index 226006c6b..000000000 --- a/client/coral-admin/src/components/ActionButton.css +++ /dev/null @@ -1,24 +0,0 @@ -.actionButton { - transform: scale(.8); - margin: 0; -} - -.minimal { - width: 45px; - min-width: 0; -} - -.approve__active { - box-shadow: none; - color: white; - background-color: #519954; - cursor: not-allowed; -} - -.reject__active, .rejected__active { - color: white; - background-color: #D03235; - box-shadow: none; - cursor: not-allowed; -} - diff --git a/client/coral-admin/src/components/ActionButton.js b/client/coral-admin/src/components/ActionButton.js deleted file mode 100644 index 77456b939..000000000 --- a/client/coral-admin/src/components/ActionButton.js +++ /dev/null @@ -1,38 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import styles from './ActionButton.css'; -import {Button} from 'coral-ui'; -import {menuActionsMap} from '../utils/moderationQueueActionsMap'; - -import t from 'coral-framework/services/i18n'; - -const ActionButton = ({type = '', active, ...props}) => { - const typeName = type.toLowerCase(); - let text = menuActionsMap[type].text; - - if (text === 'approve' && active) { - text = 'approved'; - } else if (text === 'reject' && active) { - text = 'rejected'; - } - - return ( - - ); -}; - -ActionButton.propTypes = { - active: PropTypes.bool, - type: PropTypes.oneOf(['APPROVE', 'REJECT']), - minimal: PropTypes.bool, - acceptComment: PropTypes.func, - rejectComment: PropTypes.func, -}; - -export default ActionButton; diff --git a/client/coral-admin/src/components/ApproveButton.css b/client/coral-admin/src/components/ApproveButton.css new file mode 100644 index 000000000..4c42cc233 --- /dev/null +++ b/client/coral-admin/src/components/ApproveButton.css @@ -0,0 +1,44 @@ +.root { + display: block; + color: #519954; + border: solid 2px rgba(81, 153, 84, 0.75); + background: white; + padding: 10px 12px; + box-sizing: border-box; + vertical-align: middle; + line-height: 24px; + font-size: 17px; + height: 47px; + border-radius: 3px; + text-transform: capitalize; + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.03), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.09); + width: 129px; + transform: scale(.8); + margin: 0; + + &:hover { + box-shadow: none; + color: white; + background-color: #519954; + cursor: pointer; + } +} + +.active { + box-shadow: none; + color: white; + background-color: #519954; + + &:hover { + cursor: not-allowed; + } +} + +.minimal { + width: 45px; + min-width: 0; +} + +.icon { + margin-right: 5px; +} diff --git a/client/coral-admin/src/components/ApproveButton.js b/client/coral-admin/src/components/ApproveButton.js new file mode 100644 index 000000000..151a5ca29 --- /dev/null +++ b/client/coral-admin/src/components/ApproveButton.js @@ -0,0 +1,30 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import cn from 'classnames'; +import styles from './ApproveButton.css'; +import {Icon} from 'coral-ui'; + +import t from 'coral-framework/services/i18n'; + +const ApproveButton = ({active, minimal, onClick}) => { + const text = active ? t('modqueue.approved') : t('modqueue.approve'); + return ( + + ); +}; + +ApproveButton.propTypes = { + active: PropTypes.bool, + minimal: PropTypes.bool, + onClick: PropTypes.func, +}; + +export default ApproveButton; + diff --git a/client/coral-admin/src/components/CommentDetails.js b/client/coral-admin/src/components/CommentDetails.js index 9d9c26813..d984ce0c1 100644 --- a/client/coral-admin/src/components/CommentDetails.js +++ b/client/coral-admin/src/components/CommentDetails.js @@ -2,7 +2,7 @@ import React, {Component} from 'react'; import PropTypes from 'prop-types'; import styles from './CommentDetails.css'; import t from 'coral-framework/services/i18n'; -import FlagDetails from './FlagDetails'; +import Slot from 'coral-framework/components/Slot'; class CommentDetails extends Component { state = { @@ -23,15 +23,20 @@ class CommentDetails extends Component { } render() { - const {actions, viewUserDetail} = this.props; + const {data, root, comment} = this.props; const {showDetail} = this.state; + const queryData = { + root, + comment, + }; return (
{showDetail ? t('modqueue.less_detail') : t('modqueue.more_detail')} -
@@ -40,11 +45,9 @@ class CommentDetails extends Component { } CommentDetails.propTypes = { - actions: PropTypes.arrayOf(PropTypes.shape({ - message: PropTypes.string, - user: PropTypes.shape({username: PropTypes.string}) - })).isRequired, - viewUserDetail: PropTypes.func.isRequired, + data: PropTypes.object.isRequired, + root: PropTypes.object.isRequired, + comment: PropTypes.object.isRequired, }; export default CommentDetails; diff --git a/client/coral-admin/src/components/RejectButton.css b/client/coral-admin/src/components/RejectButton.css new file mode 100644 index 000000000..a06cf5f43 --- /dev/null +++ b/client/coral-admin/src/components/RejectButton.css @@ -0,0 +1,44 @@ +.root { + display: block; + color: #D03235; + border: solid 1px #D03235; + background: white; + padding: 10px 11px; + box-sizing: border-box; + vertical-align: middle; + line-height: 24px; + font-size: 17px; + height: 47px; + border-radius: 3px; + text-transform: capitalize; + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.03), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.09); + width: 129px; + transform: scale(.8); + margin: 0; + + &:hover { + color: white; + background-color: #D03235; + box-shadow: none; + cursor: pointer; + } +} + +.active { + color: white; + background-color: #D03235; + box-shadow: none; + + &:hover { + cursor: not-allowed; + } +} + +.minimal { + width: 45px; + min-width: 0; +} + +.icon { + margin-right: 5px; +} diff --git a/client/coral-admin/src/components/RejectButton.js b/client/coral-admin/src/components/RejectButton.js new file mode 100644 index 000000000..e01102dc3 --- /dev/null +++ b/client/coral-admin/src/components/RejectButton.js @@ -0,0 +1,30 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import cn from 'classnames'; +import styles from './RejectButton.css'; +import {Icon} from 'coral-ui'; + +import t from 'coral-framework/services/i18n'; + +const RejectButton = ({active, minimal, onClick}) => { + const text = active ? t('modqueue.rejected') : t('modqueue.reject'); + return ( + + ); +}; + +RejectButton.propTypes = { + active: PropTypes.bool, + minimal: PropTypes.bool, + onClick: PropTypes.func, +}; + +export default RejectButton; + diff --git a/client/coral-admin/src/components/UserDetail.js b/client/coral-admin/src/components/UserDetail.js index b6b239057..a5955af45 100644 --- a/client/coral-admin/src/components/UserDetail.js +++ b/client/coral-admin/src/components/UserDetail.js @@ -5,7 +5,6 @@ import styles from './UserDetail.css'; import {Icon, Button, Drawer, Spinner} from 'coral-ui'; import {Slot} from 'coral-framework/components'; import ButtonCopyToClipboard from './ButtonCopyToClipboard'; -import {actionsMap} from '../utils/moderationQueueActionsMap'; import ClickOutside from 'coral-framework/components/ClickOutside'; import LoadMore from '../components/LoadMore'; import cn from 'classnames'; @@ -70,6 +69,7 @@ export default class UserDetail extends React.Component { renderLoaded() { const { + data, root, root: { user, @@ -177,15 +177,15 @@ export default class UserDetail extends React.Component {
{ nodes.map((comment) => { - const status = comment.action_summaries ? 'FLAGGED' : comment.status; const selected = selectedCommentIds.indexOf(comment.id) !== -1; return (this.props.comment.status === 'ACCEPTED' + ? null + : this.props.acceptComment({commentId: this.props.comment.id}) + ); + + reject = () => (this.props.comment.status === 'REJECTED' + ? null + : this.props.rejectComment({commentId: this.props.comment.id}) + ); + render() { const { - actions = [], comment, - viewUserDetail, suspectWords, bannedWords, selected, toggleSelect, className, - user, - ...props + data, } = this.props; - const flagActions = comment.actions && comment.actions.filter((a) => a.__typename === 'FlagAction'); - return (
  • - {actions.map((action, i) => { - const active = - (action === 'REJECT' && comment.status === 'REJECTED') || - (action === 'APPROVE' && comment.status === 'ACCEPTED'); - return ( - - (comment.status === 'ACCEPTED' - ? null - : props.acceptComment({commentId: comment.id}))} - rejectComment={() => - (comment.status === 'REJECTED' - ? null - : props.rejectComment({commentId: comment.id}))} - /> - ); - })} + +
  • - {flagActions && flagActions.length - ? - : null} + ); } @@ -135,6 +127,8 @@ UserDetailComment.propTypes = { bannedWords: PropTypes.arrayOf(PropTypes.string).isRequired, toggleSelect: PropTypes.func, comment: PropTypes.shape({ + id: PropTypes.string.isRequired, + status: PropTypes.string.isRequired, body: PropTypes.string.isRequired, actions: PropTypes.array, created_at: PropTypes.string.isRequired, diff --git a/client/coral-admin/src/containers/CommentDetails.js b/client/coral-admin/src/containers/CommentDetails.js new file mode 100644 index 000000000..a72a8eee4 --- /dev/null +++ b/client/coral-admin/src/containers/CommentDetails.js @@ -0,0 +1,23 @@ +import {gql} from 'react-apollo'; +import CommentDetails from '../components/CommentDetails'; +import {getSlotFragmentSpreads} from 'coral-framework/utils'; +import withFragments from 'coral-framework/hocs/withFragments'; + +const slots = [ + 'adminCommentDetailArea', +]; + +export default withFragments({ + root: gql` + fragment CoralAdmin_CommentDetails_root on RootQuery { + __typename + ${getSlotFragmentSpreads(slots, 'root')} + } + `, + comment: gql` + fragment CoralAdmin_CommentDetails_comment on Comment { + __typename + ${getSlotFragmentSpreads(slots, 'comment')} + } + ` +})(CommentDetails); diff --git a/client/coral-admin/src/containers/CommentLabels.js b/client/coral-admin/src/containers/CommentLabels.js index af6a0d963..1942d1ad0 100644 --- a/client/coral-admin/src/containers/CommentLabels.js +++ b/client/coral-admin/src/containers/CommentLabels.js @@ -8,6 +8,12 @@ const slots = [ ]; export default withFragments({ + root: gql` + fragment CoralAdmin_CommentLabels_root on RootQuery { + __typename + ${getSlotFragmentSpreads(slots, 'root')} + } + `, comment: gql` fragment CoralAdmin_CommentLabels_comment on Comment { hasParent diff --git a/client/coral-admin/src/containers/UserDetail.js b/client/coral-admin/src/containers/UserDetail.js index 5effb2b84..2ae842b1d 100644 --- a/client/coral-admin/src/containers/UserDetail.js +++ b/client/coral-admin/src/containers/UserDetail.js @@ -160,8 +160,10 @@ export const withUserDetailQuery = withQuery(gql` }) { ...CoralAdmin_Moderation_CommentConnection } + ...${getDefinitionName(UserDetailComment.fragments.root)} ${getSlotFragmentSpreads(slots, 'root')} } + ${UserDetailComment.fragments.root} ${commentConnectionFragment} `, { options: ({userId, statuses}) => { diff --git a/client/coral-admin/src/containers/UserDetailComment.js b/client/coral-admin/src/containers/UserDetailComment.js index 6b3572434..9eef5934f 100644 --- a/client/coral-admin/src/containers/UserDetailComment.js +++ b/client/coral-admin/src/containers/UserDetailComment.js @@ -3,10 +3,20 @@ import UserDetailComment from '../components/UserDetailComment'; import withFragments from 'coral-framework/hocs/withFragments'; import {getDefinitionName} from 'coral-framework/utils'; import CommentLabels from './CommentLabels'; +import CommentDetails from './CommentDetails'; export default withFragments({ + root: gql` + fragment CoralAdmin_UserDetailComment_root on RootQuery { + __typename + ...${getDefinitionName(CommentLabels.fragments.root)} + ...${getDefinitionName(CommentDetails.fragments.root)} + } + ${CommentLabels.fragments.root} + ${CommentDetails.fragments.root} + `, comment: gql` - fragment CoralAdmin_UserDetail_comment on Comment { + fragment CoralAdmin_UserDetailComment_comment on Comment { id body created_at @@ -17,22 +27,13 @@ export default withFragments({ title url } - actions { - ... on FlagAction { - id - reason - message - user { - id - username - } - } - } editing { edited } ...${getDefinitionName(CommentLabels.fragments.comment)} + ...${getDefinitionName(CommentDetails.fragments.comment)} } ${CommentLabels.fragments.comment} + ${CommentDetails.fragments.comment} ` })(UserDetailComment); diff --git a/client/coral-admin/src/routes/Community/components/ActionButton.css b/client/coral-admin/src/routes/Community/components/ActionButton.css deleted file mode 100644 index 8f328e8b8..000000000 --- a/client/coral-admin/src/routes/Community/components/ActionButton.css +++ /dev/null @@ -1,4 +0,0 @@ -.actionButton { - transform: scale(.8); - margin: 0; -} diff --git a/client/coral-admin/src/routes/Community/components/ActionButton.js b/client/coral-admin/src/routes/Community/components/ActionButton.js deleted file mode 100644 index 0ef9b8a39..000000000 --- a/client/coral-admin/src/routes/Community/components/ActionButton.js +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; -import styles from './ActionButton.css'; -import {Button} from 'coral-ui'; -import {menuActionsMap} from '../../../utils/moderationQueueActionsMap'; - -import t from 'coral-framework/services/i18n'; - -// TODO: Needs refactoring. -const ActionButton = ({type = '', user, ...props}) => { - return ( - - ); -}; - -export default ActionButton; diff --git a/client/coral-admin/src/routes/Community/components/FlaggedAccounts.js b/client/coral-admin/src/routes/Community/components/FlaggedAccounts.js index 1d78c015a..e617def53 100644 --- a/client/coral-admin/src/routes/Community/components/FlaggedAccounts.js +++ b/client/coral-admin/src/routes/Community/components/FlaggedAccounts.js @@ -47,7 +47,6 @@ class FlaggedAccounts extends React.Component { this.props.viewUserDetail(this.props.user.id); + showRejectUsernameDialog = () => this.props.showRejectUsernameDialog({id: this.props.user.id}); + approveUser = () => this.props.approveUser({ + userId: this.props.user.id, + }); render() { const { user, - modActionButtons, viewUserDetail, selected, - approveUser, - showRejectUsernameDialog, me, className, } = this.props; @@ -125,14 +126,12 @@ class User extends React.Component {
    - {modActionButtons.map((action, i) => - - )} + +
    diff --git a/client/coral-admin/src/routes/Community/components/RejectUsernameDialog.js b/client/coral-admin/src/routes/Community/components/RejectUsernameDialog.js index a9877368a..20c411e52 100644 --- a/client/coral-admin/src/routes/Community/components/RejectUsernameDialog.js +++ b/client/coral-admin/src/routes/Community/components/RejectUsernameDialog.js @@ -51,7 +51,7 @@ class RejectUsernameDialog extends Component { const next = () => this.setState({stage: stage + 1}); const suspend = async () => { try { - await rejectUsername({id: user.user.id, message: this.state.email}); + await rejectUsername({id: user.id, message: this.state.email}); this.props.handleClose(); } catch (err) { diff --git a/client/coral-admin/src/routes/Community/containers/Community.js b/client/coral-admin/src/routes/Community/containers/Community.js index 4e60c64d7..6e20a3167 100644 --- a/client/coral-admin/src/routes/Community/containers/Community.js +++ b/client/coral-admin/src/routes/Community/containers/Community.js @@ -78,7 +78,11 @@ const withData = withQuery(gql` ${FlaggedAccounts.fragments.root} ${FlaggedUser.fragments.root} ${FlaggedUser.fragments.me} -`); +`, { + options: { + fetchPolicy: 'network-only', + }, +}); export default compose( connect(mapStateToProps, mapDispatchToProps), diff --git a/client/coral-admin/src/routes/Moderation/components/Comment.js b/client/coral-admin/src/routes/Moderation/components/Comment.js index c761ff591..42c9c2d13 100644 --- a/client/coral-admin/src/routes/Moderation/components/Comment.js +++ b/client/coral-admin/src/routes/Moderation/components/Comment.js @@ -8,13 +8,13 @@ import styles from './Comment.css'; import CommentLabels from 'coral-admin/src/components/CommentLabels'; import CommentAnimatedEdit from 'coral-admin/src/components/CommentAnimatedEdit'; import Slot from 'coral-framework/components/Slot'; -import {getActionSummary} from 'coral-framework/utils'; -import ActionButton from 'coral-admin/src/components/ActionButton'; import ActionsMenu from 'coral-admin/src/components/ActionsMenu'; import ActionsMenuItem from 'coral-admin/src/components/ActionsMenuItem'; import CommentBodyHighlighter from 'coral-admin/src/components/CommentBodyHighlighter'; import IfHasLink from 'coral-admin/src/components/IfHasLink'; import cn from 'classnames'; +import ApproveButton from 'coral-admin/src/components/ApproveButton'; +import RejectButton from 'coral-admin/src/components/RejectButton'; import t, {timeago} from 'coral-framework/services/i18n'; @@ -45,11 +45,19 @@ class Comment extends React.Component { return viewUserDetail(comment.user.id); }; + approve = () => (this.props.comment.status === 'ACCEPTED' + ? null + : this.props.acceptComment({commentId: this.props.comment.id}) + ); + + reject = () => (this.props.comment.status === 'REJECTED' + ? null + : this.props.rejectComment({commentId: this.props.comment.id}) + ); + render() { const { - actions = [], comment, - viewUserDetail, suspectWords, bannedWords, selected, @@ -58,15 +66,9 @@ class Comment extends React.Component { root, currentUserId, currentAsset, - acceptComment, - rejectComment, } = this.props; - const flagActionSummaries = getActionSummary('FlagActionSummary', comment); - const flagActions = comment.actions && comment.actions.filter((a) => a.__typename === 'FlagAction'); - const selectionStateCSS = selected ? 'mdl-shadow--16dp' : 'mdl-shadow--2dp'; - const queryData = {root, comment, asset: comment.asset}; return ( @@ -153,28 +155,14 @@ class Comment extends React.Component {
    - {actions.map((action, i) => { - const active = - (action === 'REJECT' && comment.status === 'REJECTED') || - (action === 'APPROVE' && comment.status === 'ACCEPTED'); - return ( - - (comment.status === 'ACCEPTED' - ? null - : acceptComment({commentId: comment.id}))} - rejectComment={() => - (comment.status === 'REJECTED' - ? null - : rejectComment({commentId: comment.id}))} - /> - ); - })} + +
    - {flagActions && flagActions.length - ? - : null} - ); @@ -214,6 +195,8 @@ Comment.propTypes = { showSuspendUserDialog: PropTypes.func.isRequired, currentUserId: PropTypes.string.isRequired, comment: PropTypes.shape({ + id: PropTypes.string.isRequired, + status: PropTypes.string.isRequired, body: PropTypes.string.isRequired, action_summaries: PropTypes.array, actions: PropTypes.array, @@ -230,7 +213,6 @@ Comment.propTypes = { }), data: PropTypes.object.isRequired, root: PropTypes.object.isRequired, - actions: PropTypes.array.isRequired, selected: PropTypes.bool, }; diff --git a/client/coral-admin/src/routes/Moderation/components/ModerationQueue.js b/client/coral-admin/src/routes/Moderation/components/ModerationQueue.js index 517892a77..47ed56925 100644 --- a/client/coral-admin/src/routes/Moderation/components/ModerationQueue.js +++ b/client/coral-admin/src/routes/Moderation/components/ModerationQueue.js @@ -4,7 +4,6 @@ import PropTypes from 'prop-types'; import Comment from '../containers/Comment'; import styles from './ModerationQueue.css'; import EmptyCard from '../../../components/EmptyCard'; -import {actionsMap} from '../../../utils/moderationQueueActionsMap'; import LoadMore from '../../../components/LoadMore'; import ViewMore from './ViewMore'; import t from 'coral-framework/services/i18n'; @@ -140,7 +139,6 @@ class ModerationQueue extends React.Component { if (singleView) { const index = comments.findIndex((comment) => comment.id === selectedCommentId); const comment = comments[index]; - const status = comment.action_summaries ? 'FLAGGED' : comment.status; return (
    { - const status = comment.action_summaries ? 'FLAGGED' : comment.status; return gql` organizationName moderation } + ...${getDefinitionName(Comment.fragments.root)} } + ${Comment.fragments.root} ${commentConnectionFragment} `, { options: (props) => { diff --git a/client/coral-admin/src/utils/moderationQueueActionsMap.js b/client/coral-admin/src/utils/moderationQueueActionsMap.js deleted file mode 100644 index 95b0ecb55..000000000 --- a/client/coral-admin/src/utils/moderationQueueActionsMap.js +++ /dev/null @@ -1,14 +0,0 @@ -export const actionsMap = { - PREMOD: ['APPROVE', 'REJECT'], - FLAGGED: ['APPROVE', 'REJECT'], - REJECTED: ['APPROVE', 'REJECTED'] -}; - -export const menuActionsMap = { - 'REJECT': {status: 'REJECTED', text: 'reject', icon: 'close', key: 'f'}, - 'REJECTED': {status: 'REJECTED', text: 'rejected', icon: 'close'}, - 'APPROVE': {status: 'ACCEPTED', text: 'approve', icon: 'done', key: 'd'}, - 'FLAGGED': {status: 'FLAGGED', text: 'flag', icon: 'flag', filter: 'Untouched'}, - 'BAN': {status: 'BANNED', text: 'ban_user', icon: 'not interested'}, - '': {icon: 'done'} -}; diff --git a/client/coral-ui/components/Button.css b/client/coral-ui/components/Button.css index 1b7efb205..ce2cff350 100644 --- a/client/coral-ui/components/Button.css +++ b/client/coral-ui/components/Button.css @@ -130,59 +130,6 @@ background: #00a291; } -.type--approve { - display: block; - color: #519954; - border: solid 2px rgba(81, 153, 84, 0.75); - background: white; - padding: 10px 12px; - box-sizing: border-box; - vertical-align: middle; - line-height: 24px; - font-size: 17px; - height: 47px; - border-radius: 3px; - text-transform: capitalize; - box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.03), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.09); - width: 129px; - - &:hover { - box-shadow: none; - color: white; - background-color: #519954; - } -} - -.type--reject, .type--rejected { - display: block; - color: #D03235; - border: solid 1px #D03235; - background: white; - padding: 10px 11px; - box-sizing: border-box; - vertical-align: middle; - line-height: 24px; - font-size: 17px; - height: 47px; - border-radius: 3px; - text-transform: capitalize; - box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.03), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.09); - width: 129px; - - &:hover { - color: white; - background-color: #D03235; - box-shadow: none; - } -} - -.type--rejected { - color: white; - background-color: #D03235; - box-shadow: none; - cursor: not-allowed; -} - .type--ban, .type--actions { display: block; color: #616161; diff --git a/plugins/talk-plugin-flag-details/.eslintrc.json b/plugins/talk-plugin-flag-details/.eslintrc.json new file mode 100644 index 000000000..78f7c2397 --- /dev/null +++ b/plugins/talk-plugin-flag-details/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "@coralproject/eslint-config-talk" +} diff --git a/plugins/talk-plugin-flag-details/client/.babelrc b/plugins/talk-plugin-flag-details/client/.babelrc new file mode 100644 index 000000000..60be246eb --- /dev/null +++ b/plugins/talk-plugin-flag-details/client/.babelrc @@ -0,0 +1,14 @@ +{ + "presets": [ + "es2015" + ], + "plugins": [ + "add-module-exports", + "transform-class-properties", + "transform-decorators-legacy", + "transform-object-assign", + "transform-object-rest-spread", + "transform-async-to-generator", + "transform-react-jsx" + ] +} \ No newline at end of file diff --git a/plugins/talk-plugin-flag-details/client/.eslintrc.json b/plugins/talk-plugin-flag-details/client/.eslintrc.json new file mode 100644 index 000000000..c8a6db18a --- /dev/null +++ b/plugins/talk-plugin-flag-details/client/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "@coralproject/eslint-config-talk/client" +} diff --git a/plugins/talk-plugin-flag-details/client/components/FlagDetails.css b/plugins/talk-plugin-flag-details/client/components/FlagDetails.css new file mode 100644 index 000000000..302e24858 --- /dev/null +++ b/plugins/talk-plugin-flag-details/client/components/FlagDetails.css @@ -0,0 +1,43 @@ + +.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; + } +} diff --git a/plugins/talk-plugin-flag-details/client/components/FlagDetails.js b/plugins/talk-plugin-flag-details/client/components/FlagDetails.js new file mode 100644 index 000000000..0d415217d --- /dev/null +++ b/plugins/talk-plugin-flag-details/client/components/FlagDetails.js @@ -0,0 +1,79 @@ +import React, {Component} from 'react'; +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'; + +class FlagDetails extends Component { + + render() { + const {comment: {actions}, viewUserDetail, more} = 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++; + 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 ( + + {Object.keys(summaries).map((reason) => +
  • + {reason} {summaries[reason].userFlagged && `(${summaries[reason].count})`} +
  • + )} + + }> + {more && userFlagReasons.length > 0 && ( + + )} +
    + ); + } +} + +FlagDetails.propTypes = { + more: PropTypes.bool, + 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; diff --git a/plugins/talk-plugin-flag-details/client/containers/FlagDetails.js b/plugins/talk-plugin-flag-details/client/containers/FlagDetails.js new file mode 100644 index 000000000..2ee88d2dd --- /dev/null +++ b/plugins/talk-plugin-flag-details/client/containers/FlagDetails.js @@ -0,0 +1,37 @@ +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 'coral-admin/src/actions/userDetail'; +import {connect} from 'react-redux'; + +const mapDispatchToProps = (dispatch) => ({ + ...bindActionCreators({ + viewUserDetail, + }, dispatch) +}); + +const enhance = compose( + connect(null, mapDispatchToProps), + withFragments({ + comment: gql` + fragment CoralAdmin_FlagDetails_comment on Comment { + actions { + __typename + ... on FlagAction { + id + reason + message + user { + id + username + } + } + } + } + ` + }), + excludeIf(({comment: {actions}}) => !actions.some((action) => action.__typename === 'FlagAction')), +); + +export default enhance(FlagDetails); diff --git a/plugins/talk-plugin-flag-details/client/index.js b/plugins/talk-plugin-flag-details/client/index.js new file mode 100644 index 000000000..045194872 --- /dev/null +++ b/plugins/talk-plugin-flag-details/client/index.js @@ -0,0 +1,9 @@ +import FlagDetails from './containers/FlagDetails'; +import translations from './translations.yml'; + +export default { + translations, + slots: { + adminCommentDetailArea: [FlagDetails], + } +}; diff --git a/plugins/talk-plugin-flag-details/client/translations.yml b/plugins/talk-plugin-flag-details/client/translations.yml new file mode 100644 index 000000000..3b2511025 --- /dev/null +++ b/plugins/talk-plugin-flag-details/client/translations.yml @@ -0,0 +1,3 @@ +en: + talk-plugin-fag-details: + diff --git a/plugins/talk-plugin-flag-details/index.js b/plugins/talk-plugin-flag-details/index.js new file mode 100644 index 000000000..f053ebf79 --- /dev/null +++ b/plugins/talk-plugin-flag-details/index.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/plugins/talk-plugin-toxic-comments/client/containers/ToxicDetail.js b/plugins/talk-plugin-toxic-comments/client/containers/ToxicDetail.js index 32b83fbb3..28f75de37 100644 --- a/plugins/talk-plugin-toxic-comments/client/containers/ToxicDetail.js +++ b/plugins/talk-plugin-toxic-comments/client/containers/ToxicDetail.js @@ -15,7 +15,7 @@ const enhance = compose( } }`, }), - excludeIf(({comment: {toxicity}}) => toxicity === null), + excludeIf(({comment: {toxicity}, more}) => !more || toxicity === null), ); export default enhance(ToxicDetail);