decidim-comments 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +33 -0
- data/app/assets/javascripts/decidim/comments/bundle.js +44 -44
- data/app/assets/javascripts/decidim/comments/bundle.js.map +1 -1
- data/app/assets/javascripts/decidim/comments/comments.js.erb +2 -0
- data/app/frontend/application/{apollo_client.js → apollo_client.ts} +5 -5
- data/app/frontend/application/application.component.test.tsx +36 -0
- data/app/frontend/application/application.component.tsx +37 -0
- data/app/frontend/application/icon.component.test.tsx +49 -0
- data/app/frontend/application/icon.component.tsx +35 -0
- data/app/frontend/comments/{add_comment_form.component.test.jsx → add_comment_form.component.test.tsx} +98 -92
- data/app/frontend/comments/{add_comment_form.component.jsx → add_comment_form.component.tsx} +152 -153
- data/app/frontend/comments/{comment.component.test.jsx → comment.component.test.tsx} +59 -71
- data/app/frontend/comments/{comment.component.jsx → comment.component.tsx} +114 -116
- data/app/frontend/comments/comment_order_selector.component.test.tsx +21 -0
- data/app/frontend/comments/comment_order_selector.component.tsx +88 -0
- data/app/frontend/comments/comment_thread.component.test.tsx +65 -0
- data/app/frontend/comments/comment_thread.component.tsx +70 -0
- data/app/frontend/comments/{comments.component.test.jsx → comments.component.test.tsx} +38 -81
- data/app/frontend/comments/{comments.component.jsx → comments.component.tsx} +49 -63
- data/app/frontend/comments/down_vote_button.component.test.tsx +39 -0
- data/app/frontend/comments/down_vote_button.component.tsx +89 -0
- data/app/frontend/comments/up_vote_button.component.test.tsx +39 -0
- data/app/frontend/comments/up_vote_button.component.tsx +89 -0
- data/app/frontend/comments/vote_button.component.tsx +36 -0
- data/app/frontend/comments/{vote_button_component.test.jsx → vote_button_component.test.tsx} +16 -20
- data/app/frontend/entry.ts +19 -0
- data/app/frontend/{comments → fragments}/add_comment_form_commentable.fragment.graphql +1 -1
- data/app/frontend/{comments → fragments}/add_comment_form_session.fragment.graphql +1 -1
- data/app/frontend/{comments → fragments}/comment.fragment.graphql +3 -1
- data/app/frontend/{comments → fragments}/comment_data.fragment.graphql +6 -3
- data/app/frontend/{comments → fragments}/comment_thread.fragment.graphql +3 -1
- data/app/frontend/{comments/down_vote.fragment.graphql → fragments/down_vote_button.fragment.graphql} +2 -2
- data/app/frontend/{comments/up_vote.fragment.graphql → fragments/up_vote_button.fragment.graphql} +2 -2
- data/app/frontend/{comments/add_comment_form.mutation.graphql → mutations/add_comment.mutation.graphql} +3 -1
- data/app/frontend/{comments → mutations}/down_vote.mutation.graphql +3 -1
- data/app/frontend/{comments → mutations}/up_vote.mutation.graphql +3 -1
- data/app/frontend/{comments → queries}/comments.query.graphql +4 -1
- data/app/frontend/support/{asset_url.js → asset_url.ts} +1 -1
- data/app/frontend/support/{generate_comments_data.js → generate_comments_data.ts} +11 -6
- data/app/frontend/support/{generate_user_data.js → generate_user_data.ts} +2 -2
- data/app/frontend/support/{generate_user_group_data.js → generate_user_group_data.ts} +2 -2
- data/app/frontend/support/graphql_transformer.js +32 -0
- data/app/frontend/support/load_translations.ts +44 -0
- data/app/frontend/support/{require_all.js → require_all.ts} +1 -1
- data/app/frontend/support/{resolve_graphql_query.js → resolve_graphql_query.ts} +7 -7
- data/app/frontend/support/schema.ts +119 -0
- data/config/locales/eu.yml +29 -5
- metadata +49 -51
- data/app/frontend/application/application.component.jsx +0 -37
- data/app/frontend/application/application.component.test.jsx +0 -33
- data/app/frontend/application/icon.component.jsx +0 -26
- data/app/frontend/application/icon.component.test.jsx +0 -53
- data/app/frontend/comments/comment_order_selector.component.jsx +0 -72
- data/app/frontend/comments/comment_order_selector.component.test.jsx +0 -20
- data/app/frontend/comments/comment_thread.component.jsx +0 -75
- data/app/frontend/comments/comment_thread.component.test.jsx +0 -83
- data/app/frontend/comments/down_vote_button.component.jsx +0 -98
- data/app/frontend/comments/down_vote_button.component.test.jsx +0 -48
- data/app/frontend/comments/featured_comment.component.jsx +0 -23
- data/app/frontend/comments/featured_comment.component.test.jsx +0 -15
- data/app/frontend/comments/up_vote_button.component.jsx +0 -98
- data/app/frontend/comments/up_vote_button.component.test.jsx +0 -48
- data/app/frontend/comments/vote_button.component.jsx +0 -32
- data/app/frontend/entry.js +0 -17
- data/app/frontend/entry.test.js +0 -31
- data/app/frontend/support/load_translations.js +0 -23
- data/app/frontend/support/stub_component.js +0 -29
@@ -1,72 +0,0 @@
|
|
1
|
-
import { Component, PropTypes } from 'react';
|
2
|
-
import { I18n } from 'react-i18nify';
|
3
|
-
|
4
|
-
/**
|
5
|
-
* A simple static component with the comment's order selector markup
|
6
|
-
* @class
|
7
|
-
* @augments Component
|
8
|
-
* @todo Needs a proper implementation
|
9
|
-
*/
|
10
|
-
class CommentOrderSelector extends Component {
|
11
|
-
|
12
|
-
constructor(props) {
|
13
|
-
super(props);
|
14
|
-
this.state = {
|
15
|
-
orderBy: this.props.defaultOrderBy
|
16
|
-
}
|
17
|
-
}
|
18
|
-
|
19
|
-
render() {
|
20
|
-
const { orderBy } = this.state;
|
21
|
-
|
22
|
-
return (
|
23
|
-
<div className="order-by__dropdown order-by__dropdown--right">
|
24
|
-
<span className="order-by__text">{ I18n.t("components.comment_order_selector.title") }</span>
|
25
|
-
<ul
|
26
|
-
className="dropdown menu"
|
27
|
-
data-dropdown-menu
|
28
|
-
data-close-on-click-inside="false">
|
29
|
-
<li>
|
30
|
-
<a>{ I18n.t(`components.comment_order_selector.order.${orderBy}`) }</a>
|
31
|
-
<ul className="menu">
|
32
|
-
<li>
|
33
|
-
<a href="" className="test" onClick={(event) => this._updateOrder(event, "best_rated")} >
|
34
|
-
{ I18n.t("components.comment_order_selector.order.best_rated") }
|
35
|
-
</a>
|
36
|
-
</li>
|
37
|
-
<li>
|
38
|
-
<a href="" onClick={(event) => this._updateOrder(event, "recent")} >
|
39
|
-
{ I18n.t("components.comment_order_selector.order.recent") }
|
40
|
-
</a>
|
41
|
-
</li>
|
42
|
-
<li>
|
43
|
-
<a href="" onClick={(event) => this._updateOrder(event, "older")} >
|
44
|
-
{ I18n.t("components.comment_order_selector.order.older") }
|
45
|
-
</a>
|
46
|
-
</li>
|
47
|
-
<li>
|
48
|
-
<a href="" onClick={(event) => this._updateOrder(event, "most_discussed")} >
|
49
|
-
{ I18n.t("components.comment_order_selector.order.most_discussed") }
|
50
|
-
</a>
|
51
|
-
</li>
|
52
|
-
</ul>
|
53
|
-
</li>
|
54
|
-
</ul>
|
55
|
-
</div>
|
56
|
-
);
|
57
|
-
}
|
58
|
-
|
59
|
-
_updateOrder(event, orderBy) {
|
60
|
-
event.preventDefault();
|
61
|
-
this.setState({ orderBy });
|
62
|
-
this.props.reorderComments(orderBy);
|
63
|
-
}
|
64
|
-
|
65
|
-
}
|
66
|
-
|
67
|
-
CommentOrderSelector.propTypes = {
|
68
|
-
reorderComments: PropTypes.func.isRequired,
|
69
|
-
defaultOrderBy: PropTypes.string.isRequired
|
70
|
-
};
|
71
|
-
|
72
|
-
export default CommentOrderSelector;
|
@@ -1,20 +0,0 @@
|
|
1
|
-
import { shallow } from 'enzyme';
|
2
|
-
import CommentOrderSelector from './comment_order_selector.component';
|
3
|
-
|
4
|
-
describe('<CommentOrderSelector />', () => {
|
5
|
-
const orderBy = "older";
|
6
|
-
const reorderComments = sinon.spy();
|
7
|
-
|
8
|
-
it("renders a div with classes order-by__dropdown order-by__dropdown--right", () => {
|
9
|
-
const wrapper = shallow(<CommentOrderSelector reorderComments={reorderComments} defaultOrderBy={orderBy} />);
|
10
|
-
expect(wrapper.find('div.order-by__dropdown.order-by__dropdown--right')).to.present();
|
11
|
-
})
|
12
|
-
|
13
|
-
it("should set state order to best_rated if user clicks on the first element", () => {
|
14
|
-
const preventDefault = sinon.spy();
|
15
|
-
const wrapper = shallow(<CommentOrderSelector reorderComments={reorderComments} defaultOrderBy={orderBy} />);
|
16
|
-
wrapper.find('a.test').simulate('click', {preventDefault});
|
17
|
-
expect(reorderComments).to.calledWith("best_rated");
|
18
|
-
});
|
19
|
-
})
|
20
|
-
|
@@ -1,75 +0,0 @@
|
|
1
|
-
import { Component, PropTypes } from 'react';
|
2
|
-
import { filter, propType } from 'graphql-anywhere';
|
3
|
-
import gql from 'graphql-tag';
|
4
|
-
import { I18n } from 'react-i18nify';
|
5
|
-
|
6
|
-
import Comment from './comment.component';
|
7
|
-
|
8
|
-
import commentThreadFragment from './comment_thread.fragment.graphql'
|
9
|
-
|
10
|
-
/**
|
11
|
-
* Define a collection of comments. It represents a conversation with multiple users.
|
12
|
-
* @class
|
13
|
-
* @augments Component
|
14
|
-
* @todo It doesn't handle multiple comments yet
|
15
|
-
*/
|
16
|
-
class CommentThread extends Component {
|
17
|
-
render() {
|
18
|
-
const { comment, session, votable } = this.props;
|
19
|
-
|
20
|
-
return (
|
21
|
-
<div>
|
22
|
-
{this._renderTitle()}
|
23
|
-
<div className="comment-thread">
|
24
|
-
<Comment
|
25
|
-
comment={filter(Comment.fragments.comment, comment)}
|
26
|
-
session={session}
|
27
|
-
votable={votable}
|
28
|
-
isRootComment
|
29
|
-
/>
|
30
|
-
</div>
|
31
|
-
</div>
|
32
|
-
);
|
33
|
-
}
|
34
|
-
|
35
|
-
/**
|
36
|
-
* Render conversation title if comment has commments
|
37
|
-
* @private
|
38
|
-
* @returns {Void|DOMElement} - The conversation's title
|
39
|
-
*/
|
40
|
-
_renderTitle() {
|
41
|
-
const { comment: { author, hasComments } } = this.props;
|
42
|
-
|
43
|
-
if (hasComments) {
|
44
|
-
return (
|
45
|
-
<h6 className="comment-thread__title">
|
46
|
-
{ I18n.t("components.comment_thread.title", { authorName: author.name }) }
|
47
|
-
</h6>
|
48
|
-
);
|
49
|
-
}
|
50
|
-
|
51
|
-
return null;
|
52
|
-
}
|
53
|
-
}
|
54
|
-
|
55
|
-
CommentThread.fragments = {
|
56
|
-
comment: gql`
|
57
|
-
${commentThreadFragment}
|
58
|
-
${Comment.fragments.comment}
|
59
|
-
`
|
60
|
-
};
|
61
|
-
|
62
|
-
CommentThread.propTypes = {
|
63
|
-
session: PropTypes.shape({
|
64
|
-
user: PropTypes.any.isRequired
|
65
|
-
}),
|
66
|
-
comment: propType(CommentThread.fragments.comment).isRequired,
|
67
|
-
votable: PropTypes.bool
|
68
|
-
};
|
69
|
-
|
70
|
-
CommentThread.defaultProps = {
|
71
|
-
session: null,
|
72
|
-
votable: false
|
73
|
-
};
|
74
|
-
|
75
|
-
export default CommentThread;
|
@@ -1,83 +0,0 @@
|
|
1
|
-
import { shallow } from 'enzyme';
|
2
|
-
import { filter } from 'graphql-anywhere';
|
3
|
-
import gql from 'graphql-tag';
|
4
|
-
|
5
|
-
import CommentThread from './comment_thread.component';
|
6
|
-
import Comment from './comment.component';
|
7
|
-
|
8
|
-
import commentThreadFragment from './comment_thread.fragment.graphql'
|
9
|
-
|
10
|
-
import stubComponent from '../support/stub_component';
|
11
|
-
import generateCommentsData from '../support/generate_comments_data';
|
12
|
-
import generateCUserData from '../support/generate_user_data';
|
13
|
-
|
14
|
-
describe('<CommentThread />', () => {
|
15
|
-
let comment = {};
|
16
|
-
let session = null;
|
17
|
-
|
18
|
-
const commentFragment = gql`
|
19
|
-
fragment Comment on Comment {
|
20
|
-
body
|
21
|
-
}
|
22
|
-
`;
|
23
|
-
|
24
|
-
stubComponent(Comment, {
|
25
|
-
fragments: {
|
26
|
-
comment: commentFragment
|
27
|
-
}
|
28
|
-
});
|
29
|
-
|
30
|
-
beforeEach(() => {
|
31
|
-
const commentsData = generateCommentsData(1);
|
32
|
-
|
33
|
-
const fragment = gql`
|
34
|
-
${commentThreadFragment}
|
35
|
-
${commentFragment}
|
36
|
-
`;
|
37
|
-
|
38
|
-
session = {
|
39
|
-
user: generateCUserData()
|
40
|
-
};
|
41
|
-
comment = filter(fragment, commentsData[0]);
|
42
|
-
});
|
43
|
-
|
44
|
-
describe("when comment doesn't have comments", () => {
|
45
|
-
it("should not render a title with author name", () => {
|
46
|
-
const wrapper = shallow(<CommentThread comment={comment} session={session} />);
|
47
|
-
expect(wrapper.find('h6.comment-thread__title')).not.to.present();
|
48
|
-
});
|
49
|
-
});
|
50
|
-
|
51
|
-
describe("when comment does has comments", () => {
|
52
|
-
beforeEach(() => {
|
53
|
-
comment.hasComments = true;
|
54
|
-
});
|
55
|
-
|
56
|
-
it("should render a h6 comment-thread__title with author name", () => {
|
57
|
-
const wrapper = shallow(<CommentThread comment={comment} session={session} />);
|
58
|
-
expect(wrapper.find('h6.comment-thread__title')).to.have.text(`Conversation with ${comment.author.name}`);
|
59
|
-
});
|
60
|
-
});
|
61
|
-
|
62
|
-
describe("should render a Comment", () => {
|
63
|
-
it("and pass the session as a prop to it", () => {
|
64
|
-
const wrapper = shallow(<CommentThread comment={comment} session={session} />);
|
65
|
-
expect(wrapper.find(Comment).first()).to.have.prop("session").deep.equal(session);
|
66
|
-
});
|
67
|
-
|
68
|
-
it("and pass filter comment data as a prop to it", () => {
|
69
|
-
const wrapper = shallow(<CommentThread comment={comment} session={session} />);
|
70
|
-
expect(wrapper.find(Comment).first()).to.have.prop("comment").deep.equal(filter(commentFragment, comment));
|
71
|
-
});
|
72
|
-
|
73
|
-
it("and pass the votable as a prop to it", () => {
|
74
|
-
const wrapper = shallow(<CommentThread comment={comment} session={session} votable />);
|
75
|
-
expect(wrapper.find(Comment).first()).to.have.prop("votable").equal(true);
|
76
|
-
});
|
77
|
-
|
78
|
-
it("and pass the isRootComment equal true", () => {
|
79
|
-
const wrapper = shallow(<CommentThread comment={comment} session={session} votable isRootComment />);
|
80
|
-
expect(wrapper.find(Comment).first()).to.have.prop("isRootComment").equal(true);
|
81
|
-
});
|
82
|
-
});
|
83
|
-
});
|
@@ -1,98 +0,0 @@
|
|
1
|
-
import { PropTypes } from 'react';
|
2
|
-
import { propType } from 'graphql-anywhere';
|
3
|
-
import { graphql } from 'react-apollo';
|
4
|
-
import gql from 'graphql-tag';
|
5
|
-
|
6
|
-
import VoteButton from './vote_button.component';
|
7
|
-
|
8
|
-
import downVoteMutation from './down_vote.mutation.graphql';
|
9
|
-
|
10
|
-
import commentFragment from './comment.fragment.graphql';
|
11
|
-
import commentDataFragment from './comment_data.fragment.graphql';
|
12
|
-
import upVoteFragment from './up_vote.fragment.graphql';
|
13
|
-
import downVoteFragment from './down_vote.fragment.graphql';
|
14
|
-
|
15
|
-
export const DownVoteButton = ({ comment: { downVotes, upVoted, downVoted }, downVote }) => {
|
16
|
-
let selectedClass = '';
|
17
|
-
|
18
|
-
if (downVoted) {
|
19
|
-
selectedClass = 'is-vote-selected';
|
20
|
-
} else if (upVoted) {
|
21
|
-
selectedClass = 'is-vote-notselected';
|
22
|
-
}
|
23
|
-
|
24
|
-
return (
|
25
|
-
<VoteButton
|
26
|
-
buttonClassName="comment__votes--down"
|
27
|
-
iconName="icon-chevron-bottom"
|
28
|
-
votes={downVotes}
|
29
|
-
voteAction={downVote}
|
30
|
-
disabled={upVoted || downVoted}
|
31
|
-
selectedClass={selectedClass}
|
32
|
-
/>
|
33
|
-
);
|
34
|
-
};
|
35
|
-
|
36
|
-
DownVoteButton.fragments = {
|
37
|
-
comment: gql`
|
38
|
-
${downVoteFragment}
|
39
|
-
`
|
40
|
-
};
|
41
|
-
|
42
|
-
DownVoteButton.propTypes = {
|
43
|
-
comment: propType(DownVoteButton.fragments.comment).isRequired,
|
44
|
-
downVote: PropTypes.func.isRequired
|
45
|
-
};
|
46
|
-
|
47
|
-
const DownVoteButtonWithMutation = graphql(gql`
|
48
|
-
${downVoteMutation}
|
49
|
-
${commentFragment}
|
50
|
-
${commentDataFragment}
|
51
|
-
${upVoteFragment}
|
52
|
-
${downVoteFragment}
|
53
|
-
`, {
|
54
|
-
props: ({ ownProps, mutate }) => ({
|
55
|
-
downVote: () => mutate({
|
56
|
-
variables: {
|
57
|
-
id: ownProps.comment.id
|
58
|
-
},
|
59
|
-
optimisticResponse: {
|
60
|
-
__typename: 'Mutation',
|
61
|
-
comment: {
|
62
|
-
__typename: 'CommentMutation',
|
63
|
-
downVote: {
|
64
|
-
__typename: 'Comment',
|
65
|
-
...ownProps.comment,
|
66
|
-
downVotes: ownProps.comment.downVotes + 1,
|
67
|
-
downVoted: true
|
68
|
-
}
|
69
|
-
}
|
70
|
-
},
|
71
|
-
updateQueries: {
|
72
|
-
GetComments: (prev, { mutationResult: { data } }) => {
|
73
|
-
const commentReducer = (comment) => {
|
74
|
-
const replies = comment.comments || [];
|
75
|
-
|
76
|
-
if (comment.id === ownProps.comment.id) {
|
77
|
-
return data.comment.downVote;
|
78
|
-
}
|
79
|
-
return {
|
80
|
-
...comment,
|
81
|
-
comments: replies.map(commentReducer)
|
82
|
-
};
|
83
|
-
};
|
84
|
-
|
85
|
-
return {
|
86
|
-
...prev,
|
87
|
-
commentable: {
|
88
|
-
...prev.commentable,
|
89
|
-
comments: prev.commentable.comments.map(commentReducer)
|
90
|
-
}
|
91
|
-
}
|
92
|
-
}
|
93
|
-
}
|
94
|
-
})
|
95
|
-
})
|
96
|
-
})(DownVoteButton);
|
97
|
-
|
98
|
-
export default DownVoteButtonWithMutation;
|
@@ -1,48 +0,0 @@
|
|
1
|
-
import { shallow } from 'enzyme';
|
2
|
-
import { filter } from 'graphql-anywhere';
|
3
|
-
import gql from 'graphql-tag';
|
4
|
-
|
5
|
-
import { DownVoteButton } from './down_vote_button.component';
|
6
|
-
|
7
|
-
import VoteButton from './vote_button.component';
|
8
|
-
|
9
|
-
import downVoteFragment from './down_vote.fragment.graphql';
|
10
|
-
|
11
|
-
import stubComponent from '../support/stub_component';
|
12
|
-
import generateCommentsData from '../support/generate_comments_data';
|
13
|
-
|
14
|
-
describe("<DownVoteButton />", () => {
|
15
|
-
let comment = {};
|
16
|
-
const downVote = () => {};
|
17
|
-
|
18
|
-
stubComponent(VoteButton);
|
19
|
-
|
20
|
-
beforeEach(() => {
|
21
|
-
let commentsData = generateCommentsData(1);
|
22
|
-
|
23
|
-
const fragment = gql`
|
24
|
-
${downVoteFragment}
|
25
|
-
`;
|
26
|
-
|
27
|
-
comment = filter(fragment, commentsData[0]);
|
28
|
-
});
|
29
|
-
|
30
|
-
it("should render a VoteButton component with the correct props", () => {
|
31
|
-
const wrapper = shallow(<DownVoteButton comment={comment} downVote={downVote} />);
|
32
|
-
expect(wrapper.find(VoteButton)).to.have.prop("buttonClassName").equal("comment__votes--down");
|
33
|
-
expect(wrapper.find(VoteButton)).to.have.prop("iconName").equal("icon-chevron-bottom");
|
34
|
-
expect(wrapper.find(VoteButton)).to.have.prop("votes").equal(comment.downVotes);
|
35
|
-
});
|
36
|
-
|
37
|
-
it("should pass disabled prop as true if comment downVoted is true", () => {
|
38
|
-
comment.downVoted = true;
|
39
|
-
const wrapper = shallow(<DownVoteButton comment={comment} downVote={downVote} />);
|
40
|
-
expect(wrapper.find(VoteButton)).to.have.prop("disabled").equal(true);
|
41
|
-
});
|
42
|
-
|
43
|
-
it("should pass disabled prop as true if comment downVoted is true", () => {
|
44
|
-
comment.downVoted = true;
|
45
|
-
const wrapper = shallow(<DownVoteButton comment={comment} downVote={downVote} />);
|
46
|
-
expect(wrapper.find(VoteButton)).to.have.prop("disabled").equal(true);
|
47
|
-
});
|
48
|
-
});
|
@@ -1,23 +0,0 @@
|
|
1
|
-
import { Component } from 'react';
|
2
|
-
import { I18n } from 'react-i18nify';
|
3
|
-
|
4
|
-
import Comment from './comment.component';
|
5
|
-
|
6
|
-
/**
|
7
|
-
* A wrapper component for a highlighted component.
|
8
|
-
* @class
|
9
|
-
* @augments Component
|
10
|
-
* @todo It's not used right now
|
11
|
-
*/
|
12
|
-
export default class FeaturedComment extends Component {
|
13
|
-
render() {
|
14
|
-
return (
|
15
|
-
<section className="comments">
|
16
|
-
<h4 className="section-heading">{ I18n.t("components.featured_comment.title") }</h4>
|
17
|
-
<div className="comment-thread comment--pinned">
|
18
|
-
<Comment />
|
19
|
-
</div>
|
20
|
-
</section>
|
21
|
-
);
|
22
|
-
}
|
23
|
-
}
|
@@ -1,15 +0,0 @@
|
|
1
|
-
import { shallow } from 'enzyme';
|
2
|
-
|
3
|
-
import FeaturedComment from './featured_comment.component';
|
4
|
-
import Comment from './comment.component';
|
5
|
-
|
6
|
-
import stubComponent from '../support/stub_component';
|
7
|
-
|
8
|
-
describe('<FeaturedComment />', () => {
|
9
|
-
stubComponent(Comment);
|
10
|
-
|
11
|
-
it("should render a section of class comments", () => {
|
12
|
-
const wrapper = shallow(<FeaturedComment />);
|
13
|
-
expect(wrapper.find('section.comments')).to.be.present();
|
14
|
-
});
|
15
|
-
});
|
@@ -1,98 +0,0 @@
|
|
1
|
-
import { PropTypes } from 'react';
|
2
|
-
import { propType } from 'graphql-anywhere';
|
3
|
-
import { graphql } from 'react-apollo';
|
4
|
-
import gql from 'graphql-tag';
|
5
|
-
|
6
|
-
import VoteButton from './vote_button.component';
|
7
|
-
|
8
|
-
import upVoteMutation from './up_vote.mutation.graphql';
|
9
|
-
|
10
|
-
import commentFragment from './comment.fragment.graphql';
|
11
|
-
import commentDataFragment from './comment_data.fragment.graphql';
|
12
|
-
import upVoteFragment from './up_vote.fragment.graphql';
|
13
|
-
import downVoteFragment from './down_vote.fragment.graphql';
|
14
|
-
|
15
|
-
export const UpVoteButton = ({ comment: { upVotes, upVoted, downVoted }, upVote }) => {
|
16
|
-
let selectedClass = '';
|
17
|
-
|
18
|
-
if (upVoted) {
|
19
|
-
selectedClass = 'is-vote-selected';
|
20
|
-
} else if (downVoted) {
|
21
|
-
selectedClass = 'is-vote-notselected';
|
22
|
-
}
|
23
|
-
|
24
|
-
return (
|
25
|
-
<VoteButton
|
26
|
-
buttonClassName="comment__votes--up"
|
27
|
-
iconName="icon-chevron-top"
|
28
|
-
votes={upVotes}
|
29
|
-
voteAction={upVote}
|
30
|
-
disabled={upVoted || downVoted}
|
31
|
-
selectedClass={selectedClass}
|
32
|
-
/>
|
33
|
-
);
|
34
|
-
}
|
35
|
-
|
36
|
-
UpVoteButton.fragments = {
|
37
|
-
comment: gql`
|
38
|
-
${upVoteFragment}
|
39
|
-
`
|
40
|
-
};
|
41
|
-
|
42
|
-
UpVoteButton.propTypes = {
|
43
|
-
comment: propType(UpVoteButton.fragments.comment).isRequired,
|
44
|
-
upVote: PropTypes.func.isRequired
|
45
|
-
};
|
46
|
-
|
47
|
-
const UpVoteButtonWithMutation = graphql(gql`
|
48
|
-
${upVoteMutation}
|
49
|
-
${commentFragment}
|
50
|
-
${commentDataFragment}
|
51
|
-
${upVoteFragment}
|
52
|
-
${downVoteFragment}
|
53
|
-
`, {
|
54
|
-
props: ({ ownProps, mutate }) => ({
|
55
|
-
upVote: () => mutate({
|
56
|
-
variables: {
|
57
|
-
id: ownProps.comment.id
|
58
|
-
},
|
59
|
-
optimisticResponse: {
|
60
|
-
__typename: 'Mutation',
|
61
|
-
comment: {
|
62
|
-
__typename: 'CommentMutation',
|
63
|
-
upVote: {
|
64
|
-
__typename: 'Comment',
|
65
|
-
...ownProps.comment,
|
66
|
-
upVotes: ownProps.comment.upVotes + 1,
|
67
|
-
upVoted: true
|
68
|
-
}
|
69
|
-
}
|
70
|
-
},
|
71
|
-
updateQueries: {
|
72
|
-
GetComments: (prev, { mutationResult: { data } }) => {
|
73
|
-
const commentReducer = (comment) => {
|
74
|
-
const replies = comment.comments || [];
|
75
|
-
|
76
|
-
if (comment.id === ownProps.comment.id) {
|
77
|
-
return data.comment.upVote;
|
78
|
-
}
|
79
|
-
return {
|
80
|
-
...comment,
|
81
|
-
comments: replies.map(commentReducer)
|
82
|
-
};
|
83
|
-
};
|
84
|
-
|
85
|
-
return {
|
86
|
-
...prev,
|
87
|
-
commentable: {
|
88
|
-
...prev.commentable,
|
89
|
-
comments: prev.commentable.comments.map(commentReducer)
|
90
|
-
}
|
91
|
-
}
|
92
|
-
}
|
93
|
-
}
|
94
|
-
})
|
95
|
-
})
|
96
|
-
})(UpVoteButton);
|
97
|
-
|
98
|
-
export default UpVoteButtonWithMutation;
|