Merge branch 'graphql' of github.com:coralproject/talk into graphql

This commit is contained in:
Belen Curcio
2017-01-23 19:46:34 -03:00
11 changed files with 173 additions and 80 deletions
+31 -5
View File
@@ -12,10 +12,14 @@ import PermalinkButton from 'coral-plugin-permalinks/PermalinkButton';
import Content from '../../coral-plugin-commentcontent/CommentContent';
import PubDate from '../../coral-plugin-pubdate/PubDate';
// import {ReplyBox, ReplyButton} from '../../coral-plugin-replies';
// import FlagComment from '../../coral-plugin-flags/FlagComment';
// import LikeButton from '../../coral-plugin-likes/LikeButton';
import FlagComment from '../../coral-plugin-flags/FlagComment';
import LikeButton from '../../coral-plugin-likes/LikeButton';
const Comment = ({comment, currentUser, asset, depth}) => {
const getAction = (type, comment) => comment.actions.filter((a) => a.type === type)[0];
const Comment = ({comment, currentUser, asset, depth, showSignInDialog, postAction, deleteAction}) => {
const like = getAction('LIKE', comment);
const flag = getAction('FLAG', comment);
return (
<div
className="comment"
@@ -36,10 +40,28 @@ const Comment = ({comment, currentUser, asset, depth}) => {
<PubDate created_at={comment.created_at} />
<Content body={comment.body} />
<div className="commentActionsLeft">
{/*
<ReplyButton/>
*/}
<LikeButton
like={like}
id={comment.id}
postAction={postAction}
deleteAction={deleteAction}
showSignInDialog={showSignInDialog}
currentUser={currentUser}
/>
</div>
<div className="commentActionsRight">
<FlagComment
flag={flag}
id={comment.id}
author_id={comment.user.id}
postAction={postAction}
deleteAction={deleteAction}
showSignInDialog={showSignInDialog}
currentUser={currentUser}
/>
<PermalinkButton articleURL={asset.url} commentId={comment.id} />
</div>
{
@@ -49,6 +71,10 @@ const Comment = ({comment, currentUser, asset, depth}) => {
depth={depth + 1}
asset={asset}
currentUser={currentUser}
currentUser={currentUser}
postAction={postAction}
deleteAction={deleteAction}
showSignInDialog={showSignInDialog}
key={reply.id}
comment={reply} />;
})
+6 -1
View File
@@ -3,7 +3,7 @@ import React, {Component, PropTypes} from 'react';
import {compose} from 'react-apollo';
import {connect} from 'react-redux';
import {postComment} from './graphql/mutations';
import {postComment, postAction, deleteAction} from './graphql/mutations';
import {queryStream} from './graphql/queries';
import {
@@ -149,6 +149,9 @@ class Embed extends Component {
<Stream
asset={asset}
currentUser={user}
postAction={this.props.postAction}
deleteAction={this.props.deleteAction}
showSignInDialog={this.props.showSignInDialog}
comments={asset.comments} />
<Notification
notifLength={4500}
@@ -211,5 +214,7 @@ const mapDispatchToProps = dispatch => ({
export default compose(
connect(mapStateToProps, mapDispatchToProps),
postComment,
postAction,
deleteAction,
queryStream
)(Embed);
+4 -2
View File
@@ -1,8 +1,7 @@
import React, {PropTypes} from 'react';
import Comment from './Comment';
const Stream = ({comments, currentUser, asset}) => {
console.log('currentUser', currentUser);
const Stream = ({comments, currentUser, asset, postAction, deleteAction, showSignInDialog}) => {
return (
<div>
{
@@ -11,6 +10,9 @@ const Stream = ({comments, currentUser, asset}) => {
depth={0}
asset={asset}
currentUser={currentUser}
postAction={postAction}
deleteAction={deleteAction}
showSignInDialog={showSignInDialog}
key={comment.id}
comment={comment} />;
})
@@ -0,0 +1,3 @@
mutation deleteAction ($id: ID!) {
deleteAction(id:$id)
}
@@ -1,5 +1,7 @@
import {graphql} from 'react-apollo';
import POST_COMMENT from './postComment.graphql';
import POST_ACTION from './postAction.graphql';
import DELETE_ACTION from './deleteAction.graphql';
export const postComment = graphql(POST_COMMENT, {
props: ({mutate}) => ({
@@ -13,3 +15,25 @@ export const postComment = graphql(POST_COMMENT, {
});
}}),
});
export const postAction = graphql(POST_ACTION, {
props: ({mutate}) => ({
postAction: (action) => {
return mutate({
variables: {
action
}
});
}}),
});
export const deleteAction = graphql(DELETE_ACTION, {
props: ({mutate}) => ({
deleteAction: (id) => {
return mutate({
variables: {
id
}
});
}}),
});
@@ -1,5 +1,5 @@
mutation CreateAction ($action: ActionInput) {
mutation CreateAction ($action: CreateActionInput!) {
createAction(action:$action) {
...action
id
}
}
@@ -3,7 +3,7 @@ import STREAM_QUERY from './streamQuery.graphql';
import Pym from 'pym.js';
const pym = new Pym.Child({polling: 100});
let url = pym.parentUrl;
let url = pym.parentUrl || 'http://localhost:3000/';
export const queryStream = graphql(STREAM_QUERY, {
options: {variables: {asset_url: url}}
+1 -1
View File
@@ -9,7 +9,7 @@ const getPopupMenu = [
() => {
return {
header: lang.t('step-2-header'),
itemType: 'user',
itemType: 'USERS',
field: 'bio',
options: [
{val: 'This bio is offensive', text: lang.t('bio-offensive')},
+32 -23
View File
@@ -14,22 +14,31 @@ class FlagButton extends Component {
reason: '',
note: '',
step: 0,
posted: false
localPost: null,
localDelete: false
}
// When the "report" button is clicked expand the menu
onReportClick = () => {
if (!this.props.currentUser) {
const {currentUser, flag, deleteAction} = this.props;
const {localPost, localDelete} = this.state;
const flagged = (flag && flag.current && !localDelete) || localPost;
if (!currentUser) {
const offset = document.getElementById(`c_${this.props.id}`).getBoundingClientRect().top - 75;
this.props.showSignInDialog(offset);
return;
}
this.setState({showMenu: !this.state.showMenu});
if (flagged) {
this.setState((prev) => prev.localPost ? {...prev, localPost: null, step: 0} : {...prev, localDelete: true});
deleteAction(localPost || flag.current.id);
} else {
this.setState({showMenu: !this.state.showMenu});
}
}
onPopupContinue = () => {
const {postAction, addItem, updateItem, flag, id, author_id} = this.props;
const {itemType, field, reason, step, note, posted} = this.state;
const {postAction, id, author_id} = this.props;
const {itemType, reason, step, localPost} = this.state;
// Proceed to the next step or close the menu if we've reached the end
if (step + 1 >= this.props.getPopupMenu.length) {
@@ -39,33 +48,32 @@ class FlagButton extends Component {
}
// If itemType and reason are both set, post the action
if (itemType && reason && !posted) {
if (itemType && reason && !localPost) {
// Set the text from the "other" field if it exists.
let item_id;
switch(itemType) {
case 'comments':
case 'COMMENTS':
item_id = id;
break;
case 'users':
case 'USERS':
item_id = author_id;
break;
}
const action = {
action_type: 'flag',
metadata: {
field,
reason,
note
// Note: Action metadata has been temporarily removed.
if (itemType === 'COMMENTS') {
this.setState({localPost: 'temp'});
}
postAction({
item_id,
item_type: itemType,
action_type: 'FLAG'
}).then(({data}) => {
if (itemType === 'COMMENTS') {
this.setState({localPost: data.createAction.id});
}
};
postAction(item_id, itemType, action)
.then((action) => {
let id = `${action.action_type}_${action.item_id}`;
addItem({id, current_user: action, count: flag ? flag.count + 1 : 1}, 'actions');
updateItem(action.item_id, action.action_type, id, action.item_type);
this.setState({posted: true});
});
});
}
}
@@ -98,7 +106,8 @@ class FlagButton extends Component {
render () {
const {flag, getPopupMenu} = this.props;
const flagged = flag && flag.current_user;
const {localPost, localDelete} = this.state;
const flagged = (flag && flag.current && !localDelete) || localPost;
const popupMenu = getPopupMenu[this.state.step](this.state.itemType);
return <div className={`${name}-container`}>
+3 -3
View File
@@ -10,15 +10,15 @@ const getPopupMenu = [
return {
header: lang.t('step-1-header'),
options: [
{val: 'users', text: lang.t('flag-username')},
{val: 'comments', text: lang.t('flag-comment')}
{val: 'USERS', text: lang.t('flag-username')},
{val: 'COMMENTS', text: lang.t('flag-comment')}
],
button: lang.t('continue'),
sets: 'itemType'
};
},
(itemType) => {
const options = itemType === 'comments' ?
const options = itemType === 'COMMENTS' ?
[
{val: 'I don\'t agree with this comment', text: lang.t('no-agree-comment')},
{val: 'This comment is offensive', text: lang.t('comment-offensive')},
+66 -42
View File
@@ -1,52 +1,76 @@
import React from 'react';
import React, {Component, PropTypes} from 'react';
import {I18n} from '../coral-framework';
import translations from './translations.json';
const name = 'coral-plugin-likes';
const LikeButton = ({like, id, postAction, deleteAction, addItem, showSignInDialog, updateItem, currentUser, banned}) => {
const liked = like && like.current_user;
const onLikeClick = () => {
if (!currentUser) {
const offset = document.getElementById(`c_${id}`).getBoundingClientRect().top - 75;
showSignInDialog(offset);
return;
}
if (banned) {
return;
}
if (!liked) {
const action = {
action_type: 'like'
};
postAction(id, 'comments', action)
.then((action) => {
let id = `${action.action_type}_${action.item_id}`;
addItem({id, current_user: action, count: like ? like.count + 1 : 1}, 'actions');
updateItem(action.item_id, action.action_type, id, 'comments');
});
} else {
deleteAction(liked.id)
.then(() => {
updateItem(like.id, 'count', like.count - 1, 'actions');
updateItem(like.id, 'current_user', false, 'actions');
});
}
};
class LikeButton extends Component {
return <div className={`${name}-container`}>
<button onClick={onLikeClick} className={`${name}-button ${liked && 'likedButton'}`}>
{
liked
? <span className={`${name}-button-text`}>{lang.t('liked')}</span>
: <span className={`${name}-button-text`}>{lang.t('like')}</span>
static propTypes = {
like: PropTypes.shape({
current: PropTypes.obect,
count: PropTypes.number
}),
id: PropTypes.string,
postAction: PropTypes.func.isRequired,
deleteAction: PropTypes.func.isRequired,
showSignInDialog: PropTypes.func.isRequired,
currentUser: PropTypes.shape({
banned: PropTypes.boolean
}),
}
state = {
localPost: null, // Set to the ID of an action if one is posted
localDelete: false // Set to true is the user deletes an action, unless localPost is already set.
}
render() {
const {like, id, postAction, deleteAction, showSignInDialog, currentUser} = this.props;
const {localPost, localDelete} = this.state;
const liked = (like && like.current && !localDelete) || localPost;
let count = like ? like.count : 0;
if (localPost) {count += 1;}
if (localDelete) {count -= 1;}
const onLikeClick = () => {
if (!currentUser) {
const offset = document.getElementById(`c_${id}`).getBoundingClientRect().top - 75;
showSignInDialog(offset);
return;
}
<i className={`${name}-icon material-icons`}
aria-hidden={true}>thumb_up</i>
<span className={`${name}-like-count`}>{like && like.count > 0 && like.count}</span>
</button>
</div>;
};
if (currentUser.banned) {
return;
}
if (!liked) {
this.setState({localPost: 'temp', localDelete: false});
postAction({
item_id: id,
item_type: 'COMMENTS',
action_type: 'LIKE'
}).then(({data}) => {
this.setState({localPost: data.createAction.id});
});
} else {
this.setState((prev) => prev.localPost ? {...prev, localPost: null} : {...prev, localDelete: true});
deleteAction(localPost || like.current.id);
}
};
return <div className={`${name}-container`}>
<button onClick={onLikeClick} className={`${name}-button ${liked && 'likedButton'}`}>
{
liked
? <span className={`${name}-button-text`}>{lang.t('liked')}</span>
: <span className={`${name}-button-text`}>{lang.t('like')}</span>
}
<i className={`${name}-icon material-icons`}
aria-hidden={true}>thumb_up</i>
<span className={`${name}-like-count`}>{count > 0 && count}</span>
</button>
</div>;
}
}
export default LikeButton;