Almost fully working

This commit is contained in:
Belen Curcio
2017-05-08 15:44:11 -03:00
parent a5f6e1f343
commit 011e5da26f
11 changed files with 221 additions and 400 deletions
+1 -1
View File
@@ -21,7 +21,7 @@ export function getSlotElements(slot, props = {}) {
.filter(o => o.module.slots[slot])
.map(o => o.module.slots[slot]));
return components
.map((component, i) => React.createElement(component, {...props, key: i}));
.map((component, i) => React.createElement(component, {key: i, ...props}));
}
function getComponentFragments(components) {
+220
View File
@@ -0,0 +1,220 @@
import React from 'react';
import get from 'lodash/get';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {compose, gql, graphql} from 'react-apollo';
import withFragments from 'coral-framework/hocs/withFragments';
import {showSignInDialog} from 'coral-framework/actions/auth';
import {capitalize} from 'coral-framework/helpers/strings';
import {getMyActionSummary, getTotalActionCount} from 'coral-framework/utils';
export default reaction => WrappedComponent => {
if (typeof reaction !== 'string') {
console.error('Reaction must be a valid string');
return null;
}
reaction = reaction.toLowerCase();
class WithReactions extends React.Component {
render() {
const {comment} = this.props;
const reactionSummary = getMyActionSummary(
`${capitalize(reaction)}ActionSummary`,
comment
);
const count = getTotalActionCount(
`${capitalize(reaction)}ActionSummary`,
comment
);
const withReactionProps = {reactionSummary, count};
return <WrappedComponent {...this.props} {...withReactionProps} />;
}
}
const isReaction = a =>
a.__typereaction === `${capitalize(reaction)}ActionSummary`;
const COMMENT_FRAGMENT = gql`
fragment ${capitalize(reaction)}Button_updateFragment on Comment {
action_summaries {
... on ${capitalize(reaction)}ActionSummary {
count
current_user {
id
}
}
}
}
`;
const withDeleteReaction = graphql(
gql`
mutation deleteReaction($id: ID!) {
deleteAction(id:$id) {
errors {
translation_key
}
}
}
`,
{
props: ({mutate}) => ({
deleteReaction: (id, commentId) => {
return mutate({
variables: {id},
optimisticResponse: {
deleteAction: {
__typereaction: 'DeleteActionResponse',
errors: null
}
},
update: proxy => {
const fragmentId = `Comment_${commentId}`;
// Read the data from our cache for this query.
const data = proxy.readFragment({
fragment: COMMENT_FRAGMENT,
id: fragmentId
});
// Check whether we liked this comment.
const idx = data.action_summaries.findIndex(isReaction);
if (
idx < 0 ||
get(data.action_summaries[idx], 'current_user.id') !== id
) {
return;
}
data.action_summaries[idx] = {
...data.action_summaries[idx],
count: data.action_summaries[idx].count - 1,
current_user: null
};
// Write our data back to the cache.
proxy.writeFragment({
fragment: COMMENT_FRAGMENT,
id: fragmentId,
data
});
}
});
}
})
}
);
const withPostReaction = graphql(
gql`
mutation create${capitalize(reaction)}($${reaction}: Create${capitalize(reaction)}Input!) {
create${capitalize(reaction)}(${reaction}: $${reaction}) {
${reaction} {
id
}
errors {
translation_key
}
}
}
`,
{
props: ({mutate}) => ({
postReaction: reactionData => {
return mutate({
variables: {[reaction]: reactionData},
optimisticResponse: {
[`create${capitalize(reaction)}`]: {
__typereaction: `Create${capitalize(reaction)}Response`,
errors: null,
[reaction]: {
__typereaction: `${capitalize(reaction)}Action`,
id: 'pending'
}
}
},
update: (proxy, mutationResult) => {
console.log(isReaction);
const fragmentId = `Comment_${reactionData.item_id}`;
// Read the data from our cache for this query.
const data = proxy.readFragment({
fragment: COMMENT_FRAGMENT,
id: fragmentId
});
// Add our comment from the mutation to the end.
let idx = data.action_summaries.findIndex(isReaction);
console.log(data.action_summaries);
// Check whether we already reactioned this comment.
if (idx >= 0 && data.action_summaries[idx].current_user) {
return;
}
if (idx < 0) {
// Add initial action when it doesn't exist.
data.action_summaries.push({
__typereaction: `${capitalize(reaction)}ActionSummary`,
count: 0,
current_user: null
});
idx = data.action_summaries.length - 1;
}
data.action_summaries[idx] = {
...data.action_summaries[idx],
count: data.action_summaries[idx].count + 1,
current_user: mutationResult.data[
`create${capitalize(reaction)}`
][reaction]
};
// Write our data back to the cache.
proxy.writeFragment({
fragment: COMMENT_FRAGMENT,
id: fragmentId,
data
});
}
});
}
})
}
);
const mapDispatchToProps = dispatch =>
bindActionCreators({showSignInDialog}, dispatch);
const enhance = compose(
withFragments({
root: gql`
fragment ${capitalize(reaction)}Button_root on RootQuery {
me {
status
}
}
`,
comment: gql`
fragment ${capitalize(reaction)}Button_comment on Comment {
action_summaries {
... on ${capitalize(reaction)}ActionSummary {
count
current_user {
id
}
}
}
}`
}),
connect(null, mapDispatchToProps),
withDeleteReaction,
withPostReaction
);
return enhance(WithReactions);
};
View File
@@ -1,98 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import cn from 'classnames';
import styles from './style.css';
import {capitalize} from '../helpers';
import {getMyActionSummary, getTotalActionCount} from 'coral-framework/utils';
class CoralReaction extends React.Component {
handleClick = () => {
const name = this.props.children;
const {postReaction, deleteReaction, showSignInDialog} = this.props;
const {root: {me}, comment} = this.props;
const myActionSummary = getMyActionSummary(
`${capitalize(name)}ActionSummary`,
comment
);
// If the current user does not exist, trigger sign in dialog.
if (!me) {
showSignInDialog();
return;
}
// If the current user is banned, do nothing.
if (me.status === 'BANNED') {
return;
}
if (myActionSummary) {
deleteReaction(myActionSummary.current_user.id, comment.id);
} else {
postReaction({
item_id: comment.id,
item_type: 'COMMENTS'
});
}
};
render() {
const name = this.props.children;
const {comment} = this.props;
console.log(this.props)
if (!comment) {
return null;
}
const myReaction = getMyActionSummary(`${capitalize(name)}ActionSummary`, comment);
let count = getTotalActionCount(`${capitalize(name)}ActionSummary`, comment);
return (
<div className={cn(styles.like, `${name}-container`)}>
<button
className={cn(
styles.button,
{[styles.liked]: myReaction},
`${name}-button`
)}
onClick={this.handleClick}
>
<span className={`${name}-button-text`}>
{this.props.children} {(myReaction ? 'd' : '')}
</span>
<i
className={cn(
styles.icon,
'material-icons',
{[styles.liked]: myReaction},
`${name}-icon`
)}
aria-hidden={true}
>
thumb_up
</i>
<span className={`${name}-count`}>{count > 0 && count}</span>
</button>
</div>
);
}
}
CoralReaction.propTypes = {
children: PropTypes.string.isRequired,
icon: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
tag: PropTypes.string,
translations: PropTypes.object
};
export default CoralReaction;
/**
*
* icon: Could be a string or a component https://material.io/icons/
**/
@@ -1,30 +0,0 @@
.like {
display: inline-block;
}
.button {
color: #2a2a2a;
margin: 5px 10px 5px 0px;
background: none;
padding: 0px;
border: none;
font-size: inherit;
&:hover {
color: #767676;
cursor: pointer;
}
&.liked {
color: rgb(0,134,227);
&:hover {
color: rgb(0,134,227);
cursor: pointer;
}
}
}
.icon {
padding: 0 5px;
}
View File
@@ -1,188 +0,0 @@
import get from 'lodash/get';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {compose, gql, graphql} from 'react-apollo';
import CoralReaction from '../components/CoralReaction';
import withFragments from 'coral-framework/hocs/withFragments';
import {showSignInDialog} from 'coral-framework/actions/auth';
import {capitalize} from '../helpers';
const name = 'love';
const isReaction = a => a.__typename === `${capitalize(name)}ActionSummary`;
const COMMENT_FRAGMENT = gql`
fragment ${capitalize(name)}Button_updateFragment on Comment {
action_summaries {
... on ${capitalize(name)}ActionSummary {
count
current_user {
id
}
}
}
}
`;
const withDeleteReaction = graphql(
gql`
mutation deleteReaction($id: ID!) {
deleteAction(id:$id) {
errors {
translation_key
}
}
}
`,
{
props: ({mutate}) => ({
deleteReaction: (id, commentId) => {
return mutate({
variables: {id},
optimisticResponse: {
deleteAction: {
__typename: 'DeleteActionResponse',
errors: null
}
},
update: proxy => {
const fragmentId = `Comment_${commentId}`;
// Read the data from our cache for this query.
const data = proxy.readFragment({
fragment: COMMENT_FRAGMENT,
id: fragmentId
});
// Check whether we liked this comment.
const idx = data.action_summaries.findIndex(isReaction);
if (
idx < 0 ||
get(data.action_summaries[idx], 'current_user.id') !== id
) {
return;
}
data.action_summaries[idx] = {
...data.action_summaries[idx],
count: data.action_summaries[idx].count - 1,
current_user: null
};
// Write our data back to the cache.
proxy.writeFragment({
fragment: COMMENT_FRAGMENT,
id: fragmentId,
data
});
}
});
}
})
}
);
const withPostReaction = graphql(
gql`
mutation create${capitalize(name)}($${name}: Create${capitalize(name)}Input!) {
create${capitalize(name)}(${name}: $${capitalize(name)}) {
${name} {
id
}
errors {
translation_key
}
}
}
`,
{
props: ({mutate}) => ({
postReaction: reaction => {
return mutate({
variables: {reaction},
optimisticResponse: {
[`create${capitalize(name)}`]: {
__typename: `Create${capitalize(name)}Response`,
errors: null,
[name]: {
__typename: `${capitalize(name)}Action`,
id: 'pending'
}
}
},
update: (proxy, mutationResult) => {
const fragmentId = `Comment_${reaction.item_id}`;
// Read the data from our cache for this query.
const data = proxy.readFragment({
fragment: COMMENT_FRAGMENT,
id: fragmentId
});
// Add our comment from the mutation to the end.
let idx = data.action_summaries.findIndex(isReaction);
// Check whether we already reactioned this comment.
if (idx >= 0 && data.action_summaries[idx].current_user) {
return;
}
if (idx < 0) {
// Add initial action when it doesn't exist.
data.action_summaries.push({
__typename: `${capitalize(name)}ActionSummary`,
count: 0,
current_user: null
});
idx = data.action_summaries.length - 1;
}
data.action_summaries[idx] = {
...data.action_summaries[idx],
count: data.action_summaries[idx].count + 1,
current_user: mutationResult.data[`create${capitalize(name)}`][name]
};
// Write our data back to the cache.
proxy.writeFragment({
fragment: COMMENT_FRAGMENT,
id: fragmentId,
data
});
}
});
}
})
}
);
const mapDispatchToProps = dispatch =>
bindActionCreators({showSignInDialog}, dispatch);
const enhance = compose(
withFragments({
root: gql`
fragment ${capitalize(name)}Button_root on RootQuery {
me {
status
}
}
`,
comment: gql`
fragment ${capitalize(name)}Button_comment on Comment {
action_summaries {
... on ${capitalize(name)}ActionSummary {
count
current_user {
id
}
}
}
}`
}),
connect(null, mapDispatchToProps),
withDeleteReaction,
withPostReaction
);
export default enhance(CoralReaction);
-3
View File
@@ -1,3 +0,0 @@
import CoralReaction from './containers/CoralReaction';
export default CoralReaction;
View File
-80
View File
@@ -1,80 +0,0 @@
export function typeDefGenerator(type = '') {
function capitalize(str) {
const newString = String.new(str);
return newString.charAt(0).toUpperCase() + newString.slice(1);
}
return `
enum ACTION_TYPE {
# Represents a Like.
LIKE
}
enum ASSET_METRICS_SORT {
# Represents a LikeAction.
LIKE
}
input CreateLikeInput {
# The item's id for which we are to create a like.
item_id: ID!
# The type of the item for which we are to create the like.
item_type: ACTION_ITEM_TYPE!
}
# LikeAction is used by users who "like" a specific entity.
type LikeAction implements Action {
# The ID of the action.
id: ID!
# The author of the action.
user: User
# The time when the Action was updated.
updated_at: Date
# The time when the Action was created.
created_at: Date
}
type LikeActionSummary implements ActionSummary {
# The count of actions with this group.
count: Int
# The current user's action.
current_user: LikeAction
}
# A summary of counts related to all the Likes on an Asset.
type LikeAssetActionSummary implements AssetActionSummary {
# Number of likes associated with actionable types on this this Asset.
actionCount: Int
# Number of unique actionable types that are referenced by the likes.
actionableItemCount: Int
}
type CreateLikeResponse implements Response {
# The like that was created.
like: LikeAction
# An array of errors relating to the mutation that occurred.
errors: [UserError]
}
type RootMutation {
# Creates a like on an entity.
createLike(like: CreateLikeInput!): CreateLikeResponse
}
`;
}