Removing Best from the core

This commit is contained in:
Belen Curcio
2017-07-03 15:27:08 -03:00
parent 002dc377a6
commit 34dbbb0984
11 changed files with 9 additions and 359 deletions
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import AuthorName from 'coral-plugin-author-name/AuthorName';
import TagLabel from 'coral-plugin-tag-label/TagLabel';
@@ -10,13 +11,6 @@ import {TransitionGroup} from 'react-transition-group';
import cn from 'classnames';
import styles from './Comment.css';
import {
BestButton,
IfUserCanModifyBest,
BEST_TAG,
commentIsBest,
BestIndicator
} from 'coral-plugin-best/BestButton';
import LoadMore from './LoadMore';
import {getEditableUntilDate} from './util';
import {TopRightMenu} from './TopRightMenu';
@@ -180,19 +174,13 @@ export default class Comment extends React.Component {
}).isRequired,
// given a comment, return whether it should be rendered as ignored
commentIsIgnored: React.PropTypes.func,
// dispatch action to add a tag to a comment
addTag: React.PropTypes.func,
// dispatch action to remove a tag from a comment
removeTag: React.PropTypes.func,
commentIsIgnored: PropTypes.func,
// dispatch action to ignore another user
ignoreUser: React.PropTypes.func,
ignoreUser: PropTypes.func,
// edit a comment, passed (id, asset_id, { body })
editComment: React.PropTypes.func,
editComment: PropTypes.func,
}
editComment = (...args) => {
@@ -322,8 +310,6 @@ export default class Comment extends React.Component {
addNotification,
charCountEnable,
showSignInDialog,
addTag,
removeTag,
liveUpdates,
commentIsIgnored,
commentClassNames = []
@@ -351,40 +337,6 @@ export default class Comment extends React.Component {
: `comment ${styles.Comment}`;
commentClass += comment.id.indexOf('pending') >= 0 ? ` ${styles.pendingComment}` : '';
// call a function, and if it errors, call addNotification('error', ...) (e.g. to show user a snackbar)
const notifyOnError = (fn, errorToMessage) =>
async function(...args) {
if (typeof errorToMessage !== 'function') {
errorToMessage = (error) => error.message;
}
try {
return await fn(...args);
} catch (error) {
addNotification('error', errorToMessage(error));
throw error;
}
};
const addBestTag = notifyOnError(
() =>
addTag({
id: comment.id,
name: BEST_TAG,
assetId: asset.id
}),
() => 'Failed to tag comment as best'
);
const removeBestTag = notifyOnError(
() =>
removeTag({
id: comment.id,
name: BEST_TAG,
assetId: asset.id
}),
() => 'Failed to remove best comment tag'
);
/**
* classNamesToAdd
* adds classNames based on condition
@@ -428,10 +380,6 @@ export default class Comment extends React.Component {
<AuthorName author={comment.user} className={'talk-stream-comment-user-name'} />
{isStaff(comment.tags) ? <TagLabel>Staff</TagLabel> : null}
{commentIsBest(comment)
? <TagLabel><BestIndicator /></TagLabel>
: null }
<span className={`${styles.bylineSecondary} talk-stream-comment-user-byline`} >
<PubDate created_at={comment.created_at} className={'talk-stream-comment-published-date'} />
{
@@ -501,15 +449,6 @@ export default class Comment extends React.Component {
commentId={comment.id}
inline
/>
<ActionButton>
<IfUserCanModifyBest user={currentUser}>
<BestButton
isBest={commentIsBest(comment)}
addBest={addBestTag}
removeBest={removeBestTag}
/>
</IfUserCanModifyBest>
</ActionButton>
{!disableReply &&
<ActionButton>
<ReplyButton
@@ -582,8 +521,6 @@ export default class Comment extends React.Component {
currentUser={currentUser}
postFlag={postFlag}
deleteAction={deleteAction}
addTag={addTag}
removeTag={removeTag}
ignoreUser={ignoreUser}
charCountEnable={charCountEnable}
maxCharCount={maxCharCount}
@@ -157,10 +157,8 @@ class Stream extends React.Component {
postDontAgree,
deleteAction,
showSignInDialog,
addTag,
ignoreUser,
auth: {loggedIn, user},
removeTag,
pluginProps,
editName
} = this.props;
@@ -307,8 +305,6 @@ class Stream extends React.Component {
currentUser={user}
postFlag={postFlag}
postDontAgree={postDontAgree}
addTag={addTag}
removeTag={removeTag}
ignoreUser={ignoreUser}
commentIsIgnored={commentIsIgnored}
loadMore={this.props.loadNewReplies}
@@ -4,8 +4,8 @@ import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {ADDTL_COMMENTS_ON_LOAD_MORE} from '../constants/stream';
import {
withPostComment, withPostFlag, withPostDontAgree, withDeleteAction,
withAddTag, withRemoveTag, withIgnoreUser, withEditComment,
withPostComment, withPostFlag, withPostDontAgree,
withDeleteAction, withIgnoreUser, withEditComment
} from 'coral-framework/graphql/mutations';
import {notificationActions, authActions} from 'coral-framework';
@@ -306,8 +306,6 @@ export default compose(
withPostComment,
withPostFlag,
withPostDontAgree,
withAddTag,
withRemoveTag,
withIgnoreUser,
withDeleteAction,
withEditComment,
@@ -183,88 +183,6 @@ const COMMENT_FRAGMENT = gql`
}
`;
export const withAddTag = withMutation(
gql`
mutation AddTag($id: ID!, $asset_id: ID!, $name: String!) {
addTag(tag: {name: $name, id: $id, item_type: COMMENTS, asset_id: $asset_id}) {
...ModifyTagResponse
}
}
`, {
props: ({mutate}) => ({
addTag: ({id, name, assetId}) => {
return mutate({
variables: {
id,
name,
asset_id: assetId
},
optimisticResponse: {
addTag: {
__typename: 'ModifyTagResponse',
errors: null,
}
},
update: (proxy) => {
const fragmentId = `Comment_${id}`;
// Read the data from our cache for this query.
const data = proxy.readFragment({fragment: COMMENT_FRAGMENT, id: fragmentId});
data.tags.push({
tag: {
__typename: 'Tag',
name: 'BEST'
},
__typename: 'TagLink'
});
// Write our data back to the cache.
proxy.writeFragment({fragment: COMMENT_FRAGMENT, id: fragmentId, data});
},
});
}}),
});
export const withRemoveTag = withMutation(
gql`
mutation RemoveTag($id: ID!, $asset_id: ID!, $name: String!) {
removeTag(tag: {name: $name, id: $id, item_type: COMMENTS, asset_id: $asset_id}) {
...ModifyTagResponse
}
}
`, {
props: ({mutate}) => ({
removeTag: ({id, name, assetId}) => {
return mutate({
variables: {
id,
name,
asset_id: assetId
},
optimisticResponse: {
removeTag: {
__typename: 'ModifyTagResponse',
errors: null,
}
},
update: (proxy) => {
const fragmentId = `Comment_${id}`;
// Read the data from our cache for this query.
const data = proxy.readFragment({fragment: COMMENT_FRAGMENT, id: fragmentId});
const idx = data.tags.findIndex((i) => i.tag.name === 'BEST');
data.tags = [...data.tags.slice(0, idx), ...data.tags.slice(idx + 1)];
// Write our data back to the cache.
proxy.writeFragment({fragment: COMMENT_FRAGMENT, id: fragmentId, data});
}
});
}}),
});
export const withIgnoreUser = withMutation(
gql`
mutation IgnoreUser($id: ID!) {
-104
View File
@@ -1,104 +0,0 @@
import React, {Component, PropTypes} from 'react';
import t from 'coral-framework/services/i18n';
import {Icon} from 'coral-ui';
import classnames from 'classnames';
// tag string for best comments
export const BEST_TAG = 'BEST';
export const commentIsBest = ({tags} = {}) => tags.some((t) => t.tag.name === BEST_TAG);
const name = 'coral-plugin-best';
// It would be best if the backend/api held this business logic
const canModifyBestTag = ({roles = []} = {}) => roles && ['ADMIN', 'MODERATOR'].some((role) => roles.includes(role));
// Put this on a comment to show that it is best
export const BestIndicator = ({children = <Icon name='star'/>}) => (
<span aria-label={t('comment_is_best')}>
{ children }
</span>
);
/**
* Component that only renders children if the provided user prop can modify best tags
*/
export const IfUserCanModifyBest = ({user, children}) => {
if (!(user && canModifyBestTag(user))) {return null;}
return children;
};
/**
* Button that lets a moderator tag a comment as "Best".
* Used to recognize really good comments.
*/
export class BestButton extends Component {
static propTypes = {
// whether the comment is already tagged as best
isBest: PropTypes.bool.isRequired,
// set that this comment is best
addBest: PropTypes.func.isRequired,
// remove the best status
removeBest: PropTypes.func.isRequired,
}
constructor(props) {
super(props);
this.onClickAddBest = this.onClickAddBest.bind(this);
this.onClickRemoveBest = this.onClickRemoveBest.bind(this);
}
state = {
isSaving: false
}
async onClickAddBest(e) {
e.preventDefault();
const {addBest} = this.props;
if (!addBest) {
console.warn('BestButton#onClickAddBest called even though there is no addBest prop. doing nothing');
return;
}
this.setState({isSaving: true});
try {
await addBest();
} finally {
this.setState({isSaving: false});
}
}
async onClickRemoveBest(e) {
e.preventDefault();
const {removeBest} = this.props;
if (!removeBest) {
console.warn('BestButton#onClickAddBest called even though there is no removeBest prop. doing nothing');
return;
}
this.setState({isSaving: true});
try {
await removeBest();
} finally {
this.setState({isSaving: false});
}
}
render() {
const {isBest, addBest, removeBest} = this.props;
const {isSaving} = this.state;
const disabled = isSaving || !(isBest ? removeBest : addBest);
return (
<button onClick={isBest ? this.onClickRemoveBest : this.onClickAddBest}
disabled={disabled}
className={classnames(`${name}-button`, `e2e__${isBest ? 'unset' : 'set'}-best-comment`)}
aria-label={t(isBest ? 'unset_best' : 'set_best')}>
<Icon name={ isBest ? 'star' : 'star_border' } />
</button>
);
}
}
-3
View File
@@ -31,7 +31,6 @@ en:
comment_post_notif_premod: "Thank you for posting. Our moderation team will review your comment shortly."
comment_post_banned_word: "Your comment contains one or more words that are not permitted, so it will not be published. If you think this message is incorrect, please contact our moderation team."
characters_remaining: "characters remaining"
comment_is_best: "This comment is one of the best"
comment_offensive: "This comment is offensive"
comment_singular: Comment
comment_plural: Comments
@@ -305,7 +304,6 @@ en:
report_notif: "Thank you for reporting this comment. Our moderation team has been notified and will review it shortly."
report_notif_remove: "Your report has been removed."
reported: Reported
set_best: "Tag as Best"
settings:
all_comments: "All Comments"
from_settings_page: "From the Profile Page you can see your comment history."
@@ -362,7 +360,6 @@ en:
write_message: "Write a message"
send: Send
thank_you: "We value your safety and feedback. A moderator will review your report."
unset_best: "Untag as Best"
user:
bio_flags: "flags for this bio"
user_bio: "User Bio"
-3
View File
@@ -31,7 +31,6 @@ es:
comment_post_notif_premod: "Gracias por el comentario. Nuestro equipo de moderación va a revisarlo muy pronto."
comment_post_banned_word: "Tu comentario contiene una o más palabras que no están permitidas en nuestro espacio, por lo que no será publicado. Si crees que es un error, por favor contacta a nuestro equipo de moderación."
characters_remaining: "carácteres restantes"
comment_is_best: "Este comentario es uno de los mejores"
comment_offensive: "Este comentario es ofensivo"
comment_singular: Comentario
comment_plural: Comentarios
@@ -297,7 +296,6 @@ es:
report_notif: "Gracias por reportar este comentario. Nuestro equipo de moderación ha sido notificado y muy pronto lo va a revisar."
report_notif_remove: "Tu reporte ha sido eliminado."
reported: "Reportado"
set_best: "Etiquetar como el mejor"
settings:
all_comments: "Todos los comentarios"
from_settings_page: "Desde la página de configuración puedes ver tu historial de comentarios."
@@ -385,7 +383,6 @@ es:
write_message: "Escribir un mensaje"
send: "Enviar"
thank_you: "Valoramos tanto su seguridad en este espacio como sus comentarios. Un o una moderadora va a leer su reporte."
unset_best: "Des-etiquetar como el mejor"
user:
bio_flags: "reportes para este bio"
user_bio: "Bio de Usuario"
@@ -1,7 +1,7 @@
import React from 'react';
import styles from './styles.css';
import cn from 'classnames';
import {t, can} from 'plugin-api/beta/client/services';
import {can} from 'plugin-api/beta/client/services';
import {name} from '../../package.json';
import {withTags} from 'plugin-api/beta/client/hocs';
import {Icon} from 'plugin-api/beta/client/components/ui';
@@ -14,15 +14,7 @@ const FeaturedButton = (props) => {
className={cn([name, styles.button, {[styles.featured] : alreadyTagged}])}
onClick={alreadyTagged ? deleteTag : postTag} >
{alreadyTagged ? (
<span>
{t('featured')} <Icon name="label" />
</span>
) : (
<span>
{t('feature')} <Icon name="label_outline" />
</span>
)}
{alreadyTagged ? <Icon name="star" /> : <Icon name="star_border" />}
</button>
) : null ;
-6
View File
@@ -160,12 +160,6 @@ module.exports = {
},
registerButton: {
selector: '#signInDialog #coralRegister'
},
setBestButton: {
selector: '.e2e__set-best-comment'
},
unsetBestButton: {
selector: '.e2e__unset-best-comment'
}
}
};
@@ -1,25 +0,0 @@
module.exports = {
'@tags': ['like', 'comments', 'commenter'],
before: (client) => {
const embedStreamPage = client.page.embedStreamPage();
const {users} = client.globals;
embedStreamPage
.navigate()
.ready();
embedStreamPage
.login(users.commenter);
},
'Commenters should not see the set-best-comment button': (client) => {
const embedStreamPage = client.page.embedStreamPage();
embedStreamPage
.postComment('Hi everyone. Isn\'t this the BEST comment!?')
.waitForElementVisible('@likeButton')
.expect.element('@setBestButton').to.not.be.present;
},
after: (client) => {
client.end();
}
};
@@ -1,50 +0,0 @@
module.exports = {
'@tags': ['like', 'comments', 'commenter'],
before: (client) => {
const embedStreamPage = client.page.embedStreamPage();
const {users} = client.globals;
embedStreamPage
.navigate()
.ready();
embedStreamPage
.login(users.moderator);
},
'Moderator marks/unmarks their comment as BEST': (client) => {
const embedStreamPage = client.page.embedStreamPage();
const setBestCommentButton = '.e2e__set-best-comment';
const unsetBestCommentButton = '.e2e__unset-best-comment';
embedStreamPage
.postComment(`Hi everyone. Isn't this the BEST comment!? ${String(Math.random()).slice(2)}`)
.waitForElementVisible(setBestCommentButton, 2000)
.click(setBestCommentButton)
.waitForElementVisible(unsetBestCommentButton, 2000);
// on refresh, it should still be tagged as best :)
client.refresh();
embedStreamPage.ready()
// (bengo) I have no idea why, but if the selector here is '@unsetBestButton', it doesn't find it... I think nightwatch bug?
// this is why I am not using @elements. Advice appreciated.
.waitForElementVisible(unsetBestCommentButton, 2000);
// now remove the best tag
embedStreamPage
.click(unsetBestCommentButton);
embedStreamPage
.waitForElementVisible(setBestCommentButton, 2000);
// on refresh it should still be untagged best
client.refresh();
embedStreamPage.ready()
.waitForElementVisible(setBestCommentButton);
},
after: (client) => {
client.end();
}
};