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.
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;