decidim-comments 0.0.3 → 0.0.5
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 +1 -1
- data/app/assets/javascripts/decidim/comments/bundle.js +28 -23
- data/app/assets/javascripts/decidim/comments/bundle.js.map +1 -1
- data/app/commands/decidim/comments/create_comment.rb +10 -0
- data/app/forms/decidim/comments/comment_form.rb +1 -1
- data/app/frontend/comments/add_comment_form.component.jsx +171 -87
- data/app/frontend/comments/add_comment_form.component.test.jsx +41 -22
- data/app/frontend/comments/add_comment_form.mutation.graphql +5 -3
- data/app/frontend/comments/add_comment_form_commentable.fragment.graphql +4 -0
- data/app/frontend/comments/add_comment_form_session.fragment.graphql +6 -0
- data/app/frontend/comments/comment.component.jsx +18 -18
- data/app/frontend/comments/comment.component.test.jsx +22 -21
- data/app/frontend/comments/comment.fragment.graphql +4 -4
- data/app/frontend/comments/comment_data.fragment.graphql +4 -3
- data/app/frontend/comments/comment_order_selector.component.jsx +3 -3
- data/app/frontend/comments/comment_thread.component.jsx +8 -3
- data/app/frontend/comments/comment_thread.component.test.jsx +3 -3
- data/app/frontend/comments/comment_thread.fragment.graphql +1 -1
- data/app/frontend/comments/comments.component.jsx +52 -33
- data/app/frontend/comments/comments.component.test.jsx +51 -38
- data/app/frontend/comments/comments.query.graphql +10 -4
- data/app/frontend/comments/down_vote_button.component.jsx +6 -3
- data/app/frontend/comments/up_vote_button.component.jsx +7 -4
- data/app/frontend/comments/vote_button.component.jsx +5 -0
- data/app/frontend/comments/vote_button_component.test.jsx +1 -1
- data/app/frontend/entry.test.js +2 -0
- data/app/frontend/support/generate_comments_data.js +4 -4
- data/app/mailers/decidim/comments/comment_notification_mailer.rb +31 -0
- data/app/models/decidim/comments/comment.rb +13 -9
- data/app/queries/decidim/comments/{comments_with_replies.rb → sorted_comments.rb} +3 -8
- data/app/types/decidim/comments/commentable_interface.rb +44 -0
- data/app/types/decidim/comments/commentable_mutation_type.rb +29 -0
- data/app/types/decidim/comments/commentable_type.rb +14 -0
- data/app/views/decidim/comments/comment_notification_mailer/comment_created.html.erb +18 -0
- data/app/views/decidim/comments/comment_notification_mailer/reply_created.html.erb +18 -0
- data/config/locales/ca.yml +20 -4
- data/config/locales/en.yml +22 -5
- data/config/locales/es.yml +20 -4
- data/config/locales/eu.yml +5 -0
- data/lib/decidim/comments.rb +5 -0
- data/{app/types/decidim/comments → lib/decidim/comments/api}/add_comment_type.rb +0 -0
- data/{app/types/decidim/comments → lib/decidim/comments/api}/comment_mutation_type.rb +0 -0
- data/{app/types/decidim/comments → lib/decidim/comments/api}/comment_type.rb +11 -17
- data/lib/decidim/comments/commentable.rb +45 -0
- data/{app/helpers → lib}/decidim/comments/comments_helper.rb +15 -10
- data/lib/decidim/comments/mutation_extensions.rb +8 -16
- data/lib/decidim/comments/query_extensions.rb +5 -8
- data/lib/decidim/comments/test/factories.rb +3 -3
- metadata +21 -12
- data/app/frontend/comments/add_comment_form.fragment.graphql +0 -6
@@ -12,7 +12,7 @@ describe("<VoteButton />", () => {
|
|
12
12
|
|
13
13
|
it("should render the number of votes passed as a prop", () => {
|
14
14
|
const wrapper = shallow(<VoteButton votes={10} buttonClassName="vote-button" iconName="vote-icon" voteAction={voteAction} />);
|
15
|
-
expect(wrapper.find('button')).to.
|
15
|
+
expect(wrapper.find('button').text()).to.match(/10/);
|
16
16
|
});
|
17
17
|
|
18
18
|
it("should render a button with the given buttonClassName", () => {
|
data/app/frontend/entry.test.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import { random, name, date, image } from 'faker/locale/en';
|
2
2
|
|
3
|
-
/**
|
3
|
+
/**
|
4
4
|
* Generate random comment data to emulate a database real content
|
5
5
|
* @param {number} num - The number of comments to generate random data
|
6
6
|
* @returns {Object[]} - An array of objects representing comments data
|
@@ -17,9 +17,9 @@ const generateCommentsData = (num = 1) => {
|
|
17
17
|
name: name.findName(),
|
18
18
|
avatarUrl: image.imageUrl()
|
19
19
|
},
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
hasComments: false,
|
21
|
+
comments: [],
|
22
|
+
acceptsNewComments: true,
|
23
23
|
alignment: 0,
|
24
24
|
upVotes: random.number(),
|
25
25
|
upVoted: false,
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Decidim
|
3
|
+
module Comments
|
4
|
+
# A custom mailer for sending notifications to users when
|
5
|
+
# a comment is created.
|
6
|
+
class CommentNotificationMailer < Decidim::ApplicationMailer
|
7
|
+
helper Decidim::ResourceHelper
|
8
|
+
|
9
|
+
def comment_created(user, comment, commentable)
|
10
|
+
with_user(user) do
|
11
|
+
@comment = comment
|
12
|
+
@commentable = commentable
|
13
|
+
@organization = commentable.organization
|
14
|
+
subject = I18n.t("comment_created.subject", scope: "decidim.comments.mailer.comment_notification")
|
15
|
+
mail(to: commentable.author.email, subject: subject)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def reply_created(user, reply, comment, commentable)
|
20
|
+
with_user(user) do
|
21
|
+
@reply = reply
|
22
|
+
@comment = comment
|
23
|
+
@commentable = commentable
|
24
|
+
@organization = commentable.organization
|
25
|
+
subject = I18n.t("reply_created.subject", scope: "decidim.comments.mailer.comment_notification")
|
26
|
+
mail(to: comment.author.email, subject: subject)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -6,6 +6,7 @@ module Decidim
|
|
6
6
|
# to discuss or share their thoughts about the resource.
|
7
7
|
class Comment < ApplicationRecord
|
8
8
|
include Decidim::Authorable
|
9
|
+
include Decidim::Comments::Commentable
|
9
10
|
|
10
11
|
# Limit the max depth of a comment tree. If C is a comment and R is a reply:
|
11
12
|
# C (depth 0)
|
@@ -16,7 +17,6 @@ module Decidim
|
|
16
17
|
MAX_DEPTH = 3
|
17
18
|
|
18
19
|
belongs_to :commentable, foreign_key: "decidim_commentable_id", foreign_type: "decidim_commentable_type", polymorphic: true
|
19
|
-
has_many :replies, as: :commentable, foreign_key: "decidim_commentable_id", foreign_type: "decidim_commentable_type", class_name: Comment
|
20
20
|
has_many :up_votes, -> { where(weight: 1) }, foreign_key: "decidim_comment_id", class_name: CommentVote, dependent: :destroy
|
21
21
|
has_many :down_votes, -> { where(weight: -1) }, foreign_key: "decidim_comment_id", class_name: CommentVote, dependent: :destroy
|
22
22
|
|
@@ -24,16 +24,14 @@ module Decidim
|
|
24
24
|
validates :depth, numericality: { greater_than_or_equal_to: 0 }
|
25
25
|
validates :alignment, inclusion: { in: [0, 1, -1] }
|
26
26
|
|
27
|
-
validate :
|
27
|
+
validate :commentable_can_have_comments
|
28
28
|
|
29
29
|
before_save :compute_depth
|
30
30
|
|
31
31
|
delegate :organization, to: :commentable
|
32
32
|
|
33
|
-
# Public:
|
34
|
-
|
35
|
-
# Returns a bool value to indicate if comment can have replies
|
36
|
-
def can_have_replies?
|
33
|
+
# Public: Override Commentable concern method `accepts_new_comments?`
|
34
|
+
def accepts_new_comments?
|
37
35
|
depth < MAX_DEPTH
|
38
36
|
end
|
39
37
|
|
@@ -51,12 +49,18 @@ module Decidim
|
|
51
49
|
down_votes.any? { |vote| vote.author == user }
|
52
50
|
end
|
53
51
|
|
52
|
+
# Public: Returns the commentable object of the parent comment
|
53
|
+
def root_commentable
|
54
|
+
return commentable if depth == 0
|
55
|
+
commentable.root_commentable
|
56
|
+
end
|
57
|
+
|
54
58
|
private
|
55
59
|
|
56
|
-
# Private: Check if commentable can have
|
60
|
+
# Private: Check if commentable can have comments and if not adds
|
57
61
|
# a validation error to the model
|
58
|
-
def
|
59
|
-
errors.add(:commentable, :
|
62
|
+
def commentable_can_have_comments
|
63
|
+
errors.add(:commentable, :cannot_have_comments) unless commentable.accepts_new_comments?
|
60
64
|
end
|
61
65
|
|
62
66
|
# Private: Compute comment depth inside the current comment tree
|
@@ -2,7 +2,7 @@
|
|
2
2
|
module Decidim
|
3
3
|
module Comments
|
4
4
|
# A class used to find comments for a commentable resource
|
5
|
-
class
|
5
|
+
class SortedComments < Rectify::Query
|
6
6
|
attr_reader :commentable
|
7
7
|
|
8
8
|
# Syntactic sugar to initialize the class and return the queried objects.
|
@@ -32,11 +32,6 @@ module Decidim
|
|
32
32
|
scope = Comment
|
33
33
|
.where(commentable: commentable)
|
34
34
|
.includes(:author, :up_votes, :down_votes)
|
35
|
-
.includes(
|
36
|
-
replies: [:author, :up_votes, :down_votes,
|
37
|
-
replies: [:author, :up_votes, :down_votes,
|
38
|
-
replies: [:author, :up_votes, :down_votes]]]
|
39
|
-
)
|
40
35
|
|
41
36
|
scope = case @options[:order_by]
|
42
37
|
when "older"
|
@@ -77,8 +72,8 @@ module Decidim
|
|
77
72
|
end
|
78
73
|
|
79
74
|
def count_replies(comment)
|
80
|
-
if comment.
|
81
|
-
comment.
|
75
|
+
if comment.comments.size.positive?
|
76
|
+
comment.comments.size + comment.comments.sum { |reply| count_replies(reply) }
|
82
77
|
else
|
83
78
|
0
|
84
79
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Decidim
|
3
|
+
module Comments
|
4
|
+
# This interface represents a commentable object.
|
5
|
+
CommentableInterface = GraphQL::InterfaceType.define do
|
6
|
+
name "CommentableInterface"
|
7
|
+
description "A commentable interface"
|
8
|
+
|
9
|
+
field :id, !types.ID, "The commentable's ID"
|
10
|
+
|
11
|
+
field :type, !types.String, "The commentable's class name. i.e. `Decidim::ParticipatoryProcess`" do
|
12
|
+
property :commentable_type
|
13
|
+
end
|
14
|
+
|
15
|
+
field :acceptsNewComments, !types.Boolean, "Wether the object can have new comments or not" do
|
16
|
+
property :accepts_new_comments?
|
17
|
+
end
|
18
|
+
|
19
|
+
field :commentsHaveAlignment, !types.Boolean, "Wether the object comments have alignment or not" do
|
20
|
+
property :comments_have_alignment?
|
21
|
+
end
|
22
|
+
|
23
|
+
field :commentsHaveVotes, !types.Boolean, "Wether the object comments have votes or not" do
|
24
|
+
property :comments_have_votes?
|
25
|
+
end
|
26
|
+
|
27
|
+
field :comments do
|
28
|
+
type !types[CommentType]
|
29
|
+
|
30
|
+
argument :orderBy, types.String, "Order the comments"
|
31
|
+
|
32
|
+
resolve lambda { |obj, args, _ctx|
|
33
|
+
SortedComments.for(obj, order_by: args[:orderBy])
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
field :hasComments, !types.Boolean, "Check if the commentable has comments" do
|
38
|
+
resolve lambda { |obj, _args, _ctx|
|
39
|
+
obj.comments.size.positive?
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Decidim
|
3
|
+
module Comments
|
4
|
+
CommentableMutationType = GraphQL::ObjectType.define do
|
5
|
+
name "CommentableMutation"
|
6
|
+
description "A commentable which includes its available mutations"
|
7
|
+
|
8
|
+
field :id, !types.ID, "The Commentable's unique ID"
|
9
|
+
|
10
|
+
field :addComment, Decidim::Comments::CommentType do
|
11
|
+
description "Add a new comment to a commentable"
|
12
|
+
|
13
|
+
argument :body, !types.String, "The comments's body"
|
14
|
+
argument :alignment, types.Int, "The comment's alignment. Can be 0 (neutral), 1 (in favor) or -1 (against)'", default_value: 0
|
15
|
+
argument :userGroupId, types.ID, "The comment's user group id. Replaces the author."
|
16
|
+
|
17
|
+
resolve lambda { |obj, args, ctx|
|
18
|
+
params = { "comment" => { "body" => args[:body], "alignment" => args[:alignment], "user_group_id" => args[:userGroupId] } }
|
19
|
+
form = Decidim::Comments::CommentForm.from_params(params)
|
20
|
+
Decidim::Comments::CreateComment.call(form, ctx[:current_user], obj) do
|
21
|
+
on(:ok) do |comment|
|
22
|
+
return comment
|
23
|
+
end
|
24
|
+
end
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Decidim
|
3
|
+
module Comments
|
4
|
+
# This type represents a commentable object.
|
5
|
+
CommentableType = GraphQL::ObjectType.define do
|
6
|
+
name "Commentable"
|
7
|
+
description "A commentable object"
|
8
|
+
|
9
|
+
interfaces [
|
10
|
+
Decidim::Comments::CommentableInterface
|
11
|
+
]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<p><%= t("decidim.comments.comment_notification_mailer.hello", name: @commentable.author.name) %></p>
|
2
|
+
|
3
|
+
<p>
|
4
|
+
<%=
|
5
|
+
t(".new_comment_html", {
|
6
|
+
commenter: @comment.author.name,
|
7
|
+
commentable_link: link_to(@commentable.title, decidim_resource_url(@commentable))
|
8
|
+
})
|
9
|
+
%>
|
10
|
+
</p>
|
11
|
+
|
12
|
+
<blockquote>
|
13
|
+
<%= @comment.body %>
|
14
|
+
</blockquote>
|
15
|
+
|
16
|
+
<p>
|
17
|
+
<%= t("decidim.comments.comment_notification_mailer.manage_email_subscriptions_html", link: link_to(t("decidim.comments.comment_notification_mailer.notifications_settings_link"), decidim.notifications_settings_url(host: @organization.host))) %>
|
18
|
+
</p>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<p><%= t("decidim.comments.comment_notification_mailer.hello", name: @comment.author.name) %></p>
|
2
|
+
|
3
|
+
<p>
|
4
|
+
<%=
|
5
|
+
t(".new_reply_html", {
|
6
|
+
commenter: @reply.author.name,
|
7
|
+
commentable_link: link_to(@commentable.title, decidim_resource_url(@commentable))
|
8
|
+
})
|
9
|
+
%>
|
10
|
+
</p>
|
11
|
+
|
12
|
+
<blockquote>
|
13
|
+
<%= @reply.body %>
|
14
|
+
</blockquote>
|
15
|
+
|
16
|
+
<p>
|
17
|
+
<%= t("decidim.comments.comment_notification_mailer.manage_email_subscriptions_html", link: link_to(t("decidim.comments.comment_notification_mailer.notifications_settings_link"), decidim.notifications_settings_url(host: @organization.host))) %>
|
18
|
+
</p>
|
data/config/locales/ca.yml
CHANGED
@@ -2,21 +2,36 @@ ca:
|
|
2
2
|
activerecord:
|
3
3
|
errors:
|
4
4
|
messages:
|
5
|
-
|
5
|
+
cannot_have_comments: no pot tenir comentaris
|
6
6
|
decidim:
|
7
|
+
comments:
|
8
|
+
comment_notification_mailer:
|
9
|
+
comment_created:
|
10
|
+
new_comment_html: Hi ha un nou comentari d'<b>%{commenter}</b> a <b>%{commentable_link}</b>
|
11
|
+
hello: Hola %{name},
|
12
|
+
manage_email_subscriptions_html: Pots deixar de rebre aquests correus electrònics canviant la configuració a %{link}.
|
13
|
+
notifications_settings_link: la pàgina de configuració de les notificacions
|
14
|
+
reply_created:
|
15
|
+
new_reply_html: Hi ha una nova resposta del teu comentari de l'<b>%{commenter}</b> a <b>%{commentable_link}</b>
|
16
|
+
mailer:
|
17
|
+
comment_notification:
|
18
|
+
comment_created:
|
19
|
+
subject: Tens un nou comentari
|
20
|
+
reply_created:
|
21
|
+
subject: Tens una nova resposta del teu comentari
|
7
22
|
components:
|
8
23
|
add_comment_form:
|
24
|
+
account_message: "<a href=\"%{sign_in_url}\">Entra amb el teu compte</a> o <a href=\"%{sign_up_url}\">registra't</a> per a deixar un comentari.\n"
|
9
25
|
form:
|
10
26
|
body:
|
11
27
|
label: Comentari
|
12
28
|
placeholder: Què en penses d'això?
|
29
|
+
form_error: El text és necessari i no pot ser més llarg de %{length}
|
13
30
|
submit: Envia
|
14
31
|
user_group_id:
|
15
32
|
label: Comentar com a
|
16
33
|
opinion:
|
17
|
-
|
18
|
-
in_favor: Hi estic a favor
|
19
|
-
neutral: Sóc neutral
|
34
|
+
neutral: Neutral
|
20
35
|
title: Deixa el teu comentari
|
21
36
|
comment:
|
22
37
|
alignment:
|
@@ -33,6 +48,7 @@ ca:
|
|
33
48
|
comment_thread:
|
34
49
|
title: Conversa amb %{authorName}
|
35
50
|
comments:
|
51
|
+
blocked_comments_warning: Els comentaris estan desactivats a la fase actual però pots llegir els comentaris de les fases anteriors.
|
36
52
|
loading: Carregant els comentaris ...
|
37
53
|
title: "%{count} comentaris"
|
38
54
|
featured_comment:
|
data/config/locales/en.yml
CHANGED
@@ -3,22 +3,38 @@ en:
|
|
3
3
|
activerecord:
|
4
4
|
errors:
|
5
5
|
messages:
|
6
|
-
|
6
|
+
cannot_have_comments: can't have comments
|
7
7
|
decidim:
|
8
|
+
comments:
|
9
|
+
comment_notification_mailer:
|
10
|
+
comment_created:
|
11
|
+
new_comment_html: There is a new comment from <b>%{commenter}</b> in <b>%{commentable_link}</b>
|
12
|
+
hello: Hello %{name},
|
13
|
+
manage_email_subscriptions_html: You can stop receiving these emails by changing your settings in %{link}.
|
14
|
+
notifications_settings_link: the notifications settings page
|
15
|
+
reply_created:
|
16
|
+
new_reply_html: There is a new reply of your comment from <b>%{commenter}</b> in <b>%{commentable_link}</b>
|
17
|
+
mailer:
|
18
|
+
comment_notification:
|
19
|
+
comment_created:
|
20
|
+
subject: You have a new comment
|
21
|
+
reply_created:
|
22
|
+
subject: You have a new reply of your comment
|
8
23
|
components:
|
9
24
|
add_comment_form:
|
25
|
+
account_message: "<a href=\"%{sign_in_url}\">Sign in with your account</a> or <a href=\"%{sign_up_url}\">sign up</a> to add your comment.
|
26
|
+
"
|
10
27
|
form:
|
11
28
|
body:
|
12
29
|
label: Comment
|
13
30
|
placeholder: What do you think about this?
|
31
|
+
form_error: The text is required and it can't be longer than %{length} characters.
|
14
32
|
submit: Send
|
15
33
|
user_group_id:
|
16
34
|
label: Comment as
|
17
35
|
opinion:
|
18
|
-
|
19
|
-
|
20
|
-
neutral: I am neutral
|
21
|
-
title: Leave your comment
|
36
|
+
neutral: Neutral
|
37
|
+
title: Add your comment
|
22
38
|
comment:
|
23
39
|
alignment:
|
24
40
|
against: Against
|
@@ -34,6 +50,7 @@ en:
|
|
34
50
|
comment_thread:
|
35
51
|
title: Conversation with %{authorName}
|
36
52
|
comments:
|
53
|
+
blocked_comments_warning: Comments are disabled in the current step, but you can read the comments from previous steps.
|
37
54
|
loading: Loading comments ...
|
38
55
|
title: "%{count} comments"
|
39
56
|
featured_comment:
|
data/config/locales/es.yml
CHANGED
@@ -2,21 +2,36 @@ es:
|
|
2
2
|
activerecord:
|
3
3
|
errors:
|
4
4
|
messages:
|
5
|
-
|
5
|
+
cannot_have_comments: no puede tener comentarios
|
6
6
|
decidim:
|
7
|
+
comments:
|
8
|
+
comment_notification_mailer:
|
9
|
+
comment_created:
|
10
|
+
new_comment_html: Hay un nuevo comentario de <b>%{commenter}</b> en <b>%{commentable_link}</b>
|
11
|
+
hello: Hola %{name},
|
12
|
+
manage_email_subscriptions_html: Puedes dejar de recibir estos correos electrónicos cambiando la configuración en %{link}.
|
13
|
+
notifications_settings_link: la página de configuración de las notificaciones
|
14
|
+
reply_created:
|
15
|
+
new_reply_html: Hay una nueva respuesta de tu comentario de <b>%{commenter}</b> en <b>%{commentable_link}</b>
|
16
|
+
mailer:
|
17
|
+
comment_notification:
|
18
|
+
comment_created:
|
19
|
+
subject: Tienes un nuevo comentario
|
20
|
+
reply_created:
|
21
|
+
subject: Uno de tus comentarios ha recibido respuesta
|
7
22
|
components:
|
8
23
|
add_comment_form:
|
24
|
+
account_message: "<a href=\"%{sign_in_url}\">Entra con tu cuenta</a> o <a href=\"%{sign_up_url}\">regístrate</a> para dejar tu comentario.\n"
|
9
25
|
form:
|
10
26
|
body:
|
11
27
|
label: Comentario
|
12
28
|
placeholder: '¿Qué piensas sobre esto?'
|
29
|
+
form_error: El texto es necesario y no puede ser más de caracteres %{length}.
|
13
30
|
submit: Enviar
|
14
31
|
user_group_id:
|
15
32
|
label: Comentar como
|
16
33
|
opinion:
|
17
|
-
|
18
|
-
in_favor: Estoy a favor
|
19
|
-
neutral: Soy neutral
|
34
|
+
neutral: Neutral
|
20
35
|
title: Deje su comentario
|
21
36
|
comment:
|
22
37
|
alignment:
|
@@ -33,6 +48,7 @@ es:
|
|
33
48
|
comment_thread:
|
34
49
|
title: Conversación con %{authorName}
|
35
50
|
comments:
|
51
|
+
blocked_comments_warning: Los comentarios estan desactivados en la fase actual pero puedes leer los comentarios de las fases anteriores.
|
36
52
|
loading: Cargando los comentarios ...
|
37
53
|
title: "%{count} comentarios"
|
38
54
|
featured_comment:
|