decidim-comments 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +33 -0
  3. data/app/assets/javascripts/decidim/comments/bundle.js +44 -44
  4. data/app/assets/javascripts/decidim/comments/bundle.js.map +1 -1
  5. data/app/assets/javascripts/decidim/comments/comments.js.erb +2 -0
  6. data/app/frontend/application/{apollo_client.js → apollo_client.ts} +5 -5
  7. data/app/frontend/application/application.component.test.tsx +36 -0
  8. data/app/frontend/application/application.component.tsx +37 -0
  9. data/app/frontend/application/icon.component.test.tsx +49 -0
  10. data/app/frontend/application/icon.component.tsx +35 -0
  11. data/app/frontend/comments/{add_comment_form.component.test.jsx → add_comment_form.component.test.tsx} +98 -92
  12. data/app/frontend/comments/{add_comment_form.component.jsx → add_comment_form.component.tsx} +152 -153
  13. data/app/frontend/comments/{comment.component.test.jsx → comment.component.test.tsx} +59 -71
  14. data/app/frontend/comments/{comment.component.jsx → comment.component.tsx} +114 -116
  15. data/app/frontend/comments/comment_order_selector.component.test.tsx +21 -0
  16. data/app/frontend/comments/comment_order_selector.component.tsx +88 -0
  17. data/app/frontend/comments/comment_thread.component.test.tsx +65 -0
  18. data/app/frontend/comments/comment_thread.component.tsx +70 -0
  19. data/app/frontend/comments/{comments.component.test.jsx → comments.component.test.tsx} +38 -81
  20. data/app/frontend/comments/{comments.component.jsx → comments.component.tsx} +49 -63
  21. data/app/frontend/comments/down_vote_button.component.test.tsx +39 -0
  22. data/app/frontend/comments/down_vote_button.component.tsx +89 -0
  23. data/app/frontend/comments/up_vote_button.component.test.tsx +39 -0
  24. data/app/frontend/comments/up_vote_button.component.tsx +89 -0
  25. data/app/frontend/comments/vote_button.component.tsx +36 -0
  26. data/app/frontend/comments/{vote_button_component.test.jsx → vote_button_component.test.tsx} +16 -20
  27. data/app/frontend/entry.ts +19 -0
  28. data/app/frontend/{comments → fragments}/add_comment_form_commentable.fragment.graphql +1 -1
  29. data/app/frontend/{comments → fragments}/add_comment_form_session.fragment.graphql +1 -1
  30. data/app/frontend/{comments → fragments}/comment.fragment.graphql +3 -1
  31. data/app/frontend/{comments → fragments}/comment_data.fragment.graphql +6 -3
  32. data/app/frontend/{comments → fragments}/comment_thread.fragment.graphql +3 -1
  33. data/app/frontend/{comments/down_vote.fragment.graphql → fragments/down_vote_button.fragment.graphql} +2 -2
  34. data/app/frontend/{comments/up_vote.fragment.graphql → fragments/up_vote_button.fragment.graphql} +2 -2
  35. data/app/frontend/{comments/add_comment_form.mutation.graphql → mutations/add_comment.mutation.graphql} +3 -1
  36. data/app/frontend/{comments → mutations}/down_vote.mutation.graphql +3 -1
  37. data/app/frontend/{comments → mutations}/up_vote.mutation.graphql +3 -1
  38. data/app/frontend/{comments → queries}/comments.query.graphql +4 -1
  39. data/app/frontend/support/{asset_url.js → asset_url.ts} +1 -1
  40. data/app/frontend/support/{generate_comments_data.js → generate_comments_data.ts} +11 -6
  41. data/app/frontend/support/{generate_user_data.js → generate_user_data.ts} +2 -2
  42. data/app/frontend/support/{generate_user_group_data.js → generate_user_group_data.ts} +2 -2
  43. data/app/frontend/support/graphql_transformer.js +32 -0
  44. data/app/frontend/support/load_translations.ts +44 -0
  45. data/app/frontend/support/{require_all.js → require_all.ts} +1 -1
  46. data/app/frontend/support/{resolve_graphql_query.js → resolve_graphql_query.ts} +7 -7
  47. data/app/frontend/support/schema.ts +119 -0
  48. data/config/locales/eu.yml +29 -5
  49. metadata +49 -51
  50. data/app/frontend/application/application.component.jsx +0 -37
  51. data/app/frontend/application/application.component.test.jsx +0 -33
  52. data/app/frontend/application/icon.component.jsx +0 -26
  53. data/app/frontend/application/icon.component.test.jsx +0 -53
  54. data/app/frontend/comments/comment_order_selector.component.jsx +0 -72
  55. data/app/frontend/comments/comment_order_selector.component.test.jsx +0 -20
  56. data/app/frontend/comments/comment_thread.component.jsx +0 -75
  57. data/app/frontend/comments/comment_thread.component.test.jsx +0 -83
  58. data/app/frontend/comments/down_vote_button.component.jsx +0 -98
  59. data/app/frontend/comments/down_vote_button.component.test.jsx +0 -48
  60. data/app/frontend/comments/featured_comment.component.jsx +0 -23
  61. data/app/frontend/comments/featured_comment.component.test.jsx +0 -15
  62. data/app/frontend/comments/up_vote_button.component.jsx +0 -98
  63. data/app/frontend/comments/up_vote_button.component.test.jsx +0 -48
  64. data/app/frontend/comments/vote_button.component.jsx +0 -32
  65. data/app/frontend/entry.js +0 -17
  66. data/app/frontend/entry.test.js +0 -31
  67. data/app/frontend/support/load_translations.js +0 -23
  68. 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;