diff --git a/.eslintignore b/.eslintignore index 688e285c5..4805e34a4 100644 --- a/.eslintignore +++ b/.eslintignore @@ -21,5 +21,6 @@ plugins/* !plugins/talk-plugin-sort-most-respected !plugins/talk-plugin-author-menu !plugins/talk-plugin-member-since +!plugins/talk-plugin-ignore-user node_modules diff --git a/.gitignore b/.gitignore index f8be44f20..0a2ac00df 100644 --- a/.gitignore +++ b/.gitignore @@ -37,5 +37,6 @@ plugins/* !plugins/talk-plugin-sort-most-respected !plugins/talk-plugin-author-menu !plugins/talk-plugin-member-since +!plugins/talk-plugin-ignore-user **/node_modules/* diff --git a/client/coral-embed-stream/src/components/AllCommentsPane.js b/client/coral-embed-stream/src/components/AllCommentsPane.js index 427d3a68b..1617b8c4f 100644 --- a/client/coral-embed-stream/src/components/AllCommentsPane.js +++ b/client/coral-embed-stream/src/components/AllCommentsPane.js @@ -126,7 +126,6 @@ class AllCommentsPane extends React.Component { root, comments, commentClassNames, - ignoreUser, setActiveReplyBox, activeReplyBox, notify, @@ -173,7 +172,6 @@ class AllCommentsPane extends React.Component { currentUser={currentUser} postFlag={postFlag} postDontAgree={postDontAgree} - ignoreUser={ignoreUser} commentIsIgnored={commentIsIgnored} loadMore={loadNewReplies} deleteAction={deleteAction} diff --git a/client/coral-embed-stream/src/components/Comment.css b/client/coral-embed-stream/src/components/Comment.css index 578df2d80..6dc8eee80 100644 --- a/client/coral-embed-stream/src/components/Comment.css +++ b/client/coral-embed-stream/src/components/Comment.css @@ -66,17 +66,6 @@ border-bottom: 1px solid rgba(255, 255, 255, 0.3); } -.topRight .popover { - margin-top: 1em; - right: 0px; -} - -.topRight .link.active, -.topRight .active .link { - padding-bottom: 0.125em; - border-bottom: 2px solid currentColor; -} - .editCommentForm { margin-bottom: 10px; } @@ -175,4 +164,4 @@ .username { margin-right: 5px; -} \ No newline at end of file +} diff --git a/client/coral-embed-stream/src/components/Comment.js b/client/coral-embed-stream/src/components/Comment.js index 205bc498b..87dc4e776 100644 --- a/client/coral-embed-stream/src/components/Comment.js +++ b/client/coral-embed-stream/src/components/Comment.js @@ -16,7 +16,6 @@ import mapValues from 'lodash/mapValues'; import LoadMore from './LoadMore'; import {getEditableUntilDate} from './util'; import {findCommentWithId} from '../graphql/utils'; -import {TopRightMenu} from './TopRightMenu'; import CommentContent from './CommentContent'; import Slot from 'coral-framework/components/Slot'; import IgnoredCommentTombstone from './IgnoredCommentTombstone'; @@ -187,9 +186,6 @@ export default class Comment extends React.Component { // given a comment, return whether it should be rendered as ignored commentIsIgnored: PropTypes.func, - // dispatch action to ignore another user - ignoreUser: PropTypes.func, - // edit a comment, passed (id, asset_id, { body }) editComment: PropTypes.func, @@ -317,7 +313,6 @@ export default class Comment extends React.Component { comment, postFlag, parentId, - ignoreUser, highlighted, postComment, currentUser, @@ -480,16 +475,6 @@ export default class Comment extends React.Component { } } - { isActive && (currentUser && (comment.user.id !== currentUser.id)) && - - /* TopRightMenu allows currentUser to ignore other users' comments */ - - - - } { !isActive && } @@ -600,7 +585,6 @@ export default class Comment extends React.Component { postFlag={postFlag} deleteAction={deleteAction} loadMore={loadMore} - ignoreUser={ignoreUser} charCountEnable={charCountEnable} maxCharCount={maxCharCount} showSignInDialog={showSignInDialog} diff --git a/client/coral-embed-stream/src/components/Stream.js b/client/coral-embed-stream/src/components/Stream.js index 4d46c8e87..575c1fd00 100644 --- a/client/coral-embed-stream/src/components/Stream.js +++ b/client/coral-embed-stream/src/components/Stream.js @@ -64,7 +64,6 @@ class Stream extends React.Component { postDontAgree, deleteAction, showSignInDialog, - ignoreUser, loadNewReplies, auth: {user}, emit, @@ -90,7 +89,6 @@ class Stream extends React.Component { data={data} root={root} commentClassNames={commentClassNames} - ignoreUser={ignoreUser} setActiveReplyBox={setActiveReplyBox} activeReplyBox={activeReplyBox} notify={notify} @@ -133,7 +131,6 @@ class Stream extends React.Component { postDontAgree, deleteAction, showSignInDialog, - ignoreUser, activeStreamTab, setActiveStreamTab, loadNewReplies, @@ -183,7 +180,6 @@ class Stream extends React.Component { root={root} comments={comments} commentClassNames={commentClassNames} - ignoreUser={ignoreUser} setActiveReplyBox={setActiveReplyBox} activeReplyBox={activeReplyBox} notify={notify} @@ -322,9 +318,6 @@ Stream.propTypes = { notify: PropTypes.func.isRequired, postComment: PropTypes.func.isRequired, - // dispatch action to ignore another user - ignoreUser: React.PropTypes.func, - // edit a comment, passed (id, asset_id, { body }) editComment: React.PropTypes.func }; diff --git a/client/coral-embed-stream/src/components/TopRightMenu.js b/client/coral-embed-stream/src/components/TopRightMenu.js deleted file mode 100644 index 47147e853..000000000 --- a/client/coral-embed-stream/src/components/TopRightMenu.js +++ /dev/null @@ -1,60 +0,0 @@ -import React, {PropTypes} from 'react'; -import {IgnoreUserWizard} from './IgnoreUserWizard'; -import Toggleable from './Toggleable'; - -// TopRightMenu appears as a dropdown in the top right of the comment. -// when you click the down cehvron, it expands and shows IgnoreUserWizard -// when you click 'cancel' in the wizard, it closes the menu -export class TopRightMenu extends React.Component { - static propTypes = { - - // comment on which this menu appears - comment: PropTypes.shape({ - user: PropTypes.shape({ - id: PropTypes.string.isRequired, - username: PropTypes.string.isRequired - }).isRequired - }).isRequired, - ignoreUser: PropTypes.func, - - // show notification to the user (e.g. for errors) - notify: PropTypes.func.isRequired, - } - constructor(props) { - super(props); - this.state = { - timesReset: 0 - }; - } - render() { - const {comment, ignoreUser, notify} = this.props; - - // timesReset is used as Toggleable key so it re-renders on reset (closing the toggleable) - const reset = () => this.setState({timesReset: this.state.timesReset + 1}); - const ignoreUserAndCloseMenuAndNotifyOnError = async ({id}) => { - - // close menu - reset(); - - // ignore user - try { - await ignoreUser({id}); - } catch (error) { - notify('error', 'Failed to ignore user'); - throw error; - } - }; - return ( - -
- -
-
- ); - } -} - diff --git a/client/coral-embed-stream/src/containers/Stream.js b/client/coral-embed-stream/src/containers/Stream.js index 194bfc5d9..d3279896c 100644 --- a/client/coral-embed-stream/src/containers/Stream.js +++ b/client/coral-embed-stream/src/containers/Stream.js @@ -5,7 +5,7 @@ import {bindActionCreators} from 'redux'; import {ADDTL_COMMENTS_ON_LOAD_MORE, THREADING_LEVEL} from '../constants/stream'; import { withPostComment, withPostFlag, withPostDontAgree, - withDeleteAction, withIgnoreUser, withEditComment + withDeleteAction, withEditComment } from 'coral-framework/graphql/mutations'; import * as authActions from 'coral-embed-stream/src/actions/auth'; @@ -374,7 +374,6 @@ export default compose( withPostComment, withPostFlag, withPostDontAgree, - withIgnoreUser, withDeleteAction, withEditComment, )(StreamContainer); diff --git a/client/coral-embed-stream/src/graphql/index.js b/client/coral-embed-stream/src/graphql/index.js index 9ec9a2132..d01e353fc 100644 --- a/client/coral-embed-stream/src/graphql/index.js +++ b/client/coral-embed-stream/src/graphql/index.js @@ -108,18 +108,6 @@ export default { `, }, mutations: { - IgnoreUser: ({variables}) => ({ - updateQueries: { - CoralEmbedStream_Embed: (previousData) => { - const ignoredUserId = variables.id; - const updated = update(previousData, {me: {ignoredUsers: {$push: [{ - id: ignoredUserId, - __typename: 'User', - }]}}}); - return updated; - } - } - }), StopIgnoringUser: ({variables}) => ({ updateQueries: { CoralEmbedStream_Profile: (previousData) => { diff --git a/client/coral-framework/graphql/mutations.js b/client/coral-framework/graphql/mutations.js index 91d2ae0ab..4254400bb 100644 --- a/client/coral-framework/graphql/mutations.js +++ b/client/coral-framework/graphql/mutations.js @@ -293,7 +293,7 @@ export const withIgnoreUser = withMutation( } `, { props: ({mutate}) => ({ - ignoreUser: ({id}) => { + ignoreUser: (id) => { return mutate({ variables: { id, diff --git a/plugin-api/beta/client/hocs/index.js b/plugin-api/beta/client/hocs/index.js index 1bc47868e..2659237f3 100644 --- a/plugin-api/beta/client/hocs/index.js +++ b/plugin-api/beta/client/hocs/index.js @@ -5,3 +5,4 @@ export {default as withFragments} from 'coral-framework/hocs/withFragments'; export {default as excludeIf} from 'coral-framework/hocs/excludeIf'; export {default as connect} from 'coral-framework/hocs/connect'; export {default as withEmit} from 'coral-framework/hocs/withEmit'; +export {withIgnoreUser} from 'coral-framework/graphql/mutations'; diff --git a/plugins/talk-plugin-author-menu/client/components/Menu.css b/plugins/talk-plugin-author-menu/client/components/Menu.css index 86befe54a..e3a111235 100644 --- a/plugins/talk-plugin-author-menu/client/components/Menu.css +++ b/plugins/talk-plugin-author-menu/client/components/Menu.css @@ -35,3 +35,7 @@ transform: rotate(180deg); } +.actions { + display: flex; + justify-content: flex-end; +} diff --git a/plugins/talk-plugin-author-menu/client/components/Menu.js b/plugins/talk-plugin-author-menu/client/components/Menu.js index fdedf6594..620bd59c9 100644 --- a/plugins/talk-plugin-author-menu/client/components/Menu.js +++ b/plugins/talk-plugin-author-menu/client/components/Menu.js @@ -5,11 +5,13 @@ import {Slot} from 'plugin-api/beta/client/components'; export default ({data, root, asset, comment, contentSlot}) => { if (contentSlot) { return ( - +
+ +
); } @@ -21,6 +23,7 @@ export default ({data, root, asset, comment, contentSlot}) => { queryData={{asset, root, comment}} /> ( + +); diff --git a/plugins/talk-plugin-ignore-user/client/components/IgnoreUserConfirmation.css b/plugins/talk-plugin-ignore-user/client/components/IgnoreUserConfirmation.css new file mode 100644 index 000000000..5cd38f244 --- /dev/null +++ b/plugins/talk-plugin-ignore-user/client/components/IgnoreUserConfirmation.css @@ -0,0 +1,9 @@ +.root { + width: 250px; +} + +.actions { + display: flex; + justify-content: flex-end; +} + diff --git a/plugins/talk-plugin-ignore-user/client/components/IgnoreUserConfirmation.js b/plugins/talk-plugin-ignore-user/client/components/IgnoreUserConfirmation.js new file mode 100644 index 000000000..ba2f62b0b --- /dev/null +++ b/plugins/talk-plugin-ignore-user/client/components/IgnoreUserConfirmation.js @@ -0,0 +1,14 @@ +import React from 'react'; +import styles from './IgnoreUserConfirmation.css'; +import {t} from 'plugin-api/beta/client/services'; + +export default ({ignoreUser}) => ( +
+ Do you really want to ignore this user? +
+ +
+
+); diff --git a/plugins/talk-plugin-ignore-user/client/containers/IgnoreUserAction.js b/plugins/talk-plugin-ignore-user/client/containers/IgnoreUserAction.js new file mode 100644 index 000000000..422162a6e --- /dev/null +++ b/plugins/talk-plugin-ignore-user/client/containers/IgnoreUserAction.js @@ -0,0 +1,34 @@ +import React from 'react'; +import IgnoreUserAction from '../components/IgnoreUserAction'; +import {compose} from 'react-apollo'; +import {connect, withFragments} from 'plugin-api/beta/client/hocs'; +import {bindActionCreators} from 'redux'; +import {setContentSlot} from 'plugins/talk-plugin-author-menu/client/actions'; +import IgnoreUserConfirmation from './IgnoreUserConfirmation'; + +class IgnoreUserActionContainer extends React.Component { + + ignoreUser = () => { + this.props.setContentSlot('ignoreUserConfirmation'); + }; + + render() { + return ; + } +} + +const mapDispatchToProps = (dispatch) => + bindActionCreators({ + setContentSlot, + }, dispatch); + +const withIgnoreUserActionFragments = withFragments(IgnoreUserConfirmation.fragments); + +const enhance = compose( + connect(null, mapDispatchToProps), + withIgnoreUserActionFragments, +); + +export default enhance(IgnoreUserActionContainer); diff --git a/plugins/talk-plugin-ignore-user/client/containers/IgnoreUserConfirmation.js b/plugins/talk-plugin-ignore-user/client/containers/IgnoreUserConfirmation.js new file mode 100644 index 000000000..5d014277c --- /dev/null +++ b/plugins/talk-plugin-ignore-user/client/containers/IgnoreUserConfirmation.js @@ -0,0 +1,44 @@ +import React from 'react'; +import IgnoreUserConfirmation from '../components/IgnoreUserConfirmation'; +import {compose, gql} from 'react-apollo'; +import {connect, withFragments, withIgnoreUser} from 'plugin-api/beta/client/hocs'; +import {bindActionCreators} from 'redux'; +import {setContentSlot} from 'plugins/talk-plugin-author-menu/client/actions'; + +class IgnoreUserConfirmationContainer extends React.Component { + + ignoreUser = () => { + this.props.ignoreUser(this.props.comment.user.id); + this.props.setContentSlot(null); + }; + + render() { + return ; + } +} + +const mapDispatchToProps = (dispatch) => + bindActionCreators({ + setContentSlot, + }, dispatch); + +const withIgnoreUserConfirmationFragments = withFragments({ + comment: gql` + fragment TalkIgnoreUser_IgnoreUserConfirmation_comment on Comment { + user { + id + username + } + }`, +}); + +const enhance = compose( + connect(null, mapDispatchToProps), + withIgnoreUserConfirmationFragments, + withIgnoreUser, +); + +export default enhance(IgnoreUserConfirmationContainer); diff --git a/plugins/talk-plugin-ignore-user/client/index.js b/plugins/talk-plugin-ignore-user/client/index.js new file mode 100644 index 000000000..79f440126 --- /dev/null +++ b/plugins/talk-plugin-ignore-user/client/index.js @@ -0,0 +1,26 @@ +import IgnoreUserAction from './containers/IgnoreUserAction'; +import IgnoreUserConfirmation from './containers/IgnoreUserConfirmation'; +import translations from './translations.yml'; +import update from 'immutability-helper'; + +export default { + mutations: { + IgnoreUser: ({variables}) => ({ + updateQueries: { + CoralEmbedStream_Embed: (previousData) => { + const ignoredUserId = variables.id; + const updated = update(previousData, {me: {ignoredUsers: {$push: [{ + id: ignoredUserId, + __typename: 'User', + }]}}}); + return updated; + } + } + }), + }, + slots: { + authorMenuActions: [IgnoreUserAction], + ignoreUserConfirmation: [IgnoreUserConfirmation] + }, + translations +}; diff --git a/plugins/talk-plugin-ignore-user/client/translations.yml b/plugins/talk-plugin-ignore-user/client/translations.yml new file mode 100644 index 000000000..1e40c7ba1 --- /dev/null +++ b/plugins/talk-plugin-ignore-user/client/translations.yml @@ -0,0 +1,5 @@ +en: + talk-plugin-ignore-user: + ignore: "ignore" +es: + talk-plugin-ignore-user: diff --git a/plugins/talk-plugin-ignore-user/index.js b/plugins/talk-plugin-ignore-user/index.js new file mode 100644 index 000000000..f053ebf79 --- /dev/null +++ b/plugins/talk-plugin-ignore-user/index.js @@ -0,0 +1 @@ +module.exports = {};