decidim 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of decidim might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.eslintrc.json +2 -5
- data/.mention-bot +2 -1
- data/.yardopts +8 -0
- data/Gemfile.lock +64 -62
- data/README.md +11 -9
- data/decidim-admin/app/assets/javascripts/decidim/admin/sort_steps.js.es6 +3 -3
- data/decidim-admin/app/assets/stylesheets/decidim/admin/_email_preview.scss +5 -0
- data/decidim-admin/app/assets/stylesheets/decidim/admin/application.scss +1 -0
- data/decidim-admin/app/commands/decidim/admin/create_newsletter.rb +30 -0
- data/decidim-admin/app/commands/decidim/admin/deliver_newsletter.rb +29 -0
- data/decidim-admin/app/commands/decidim/admin/destroy_participatory_process_step.rb +9 -0
- data/decidim-admin/app/commands/decidim/admin/update_newsletter.rb +33 -0
- data/decidim-admin/app/constraints/decidim/admin/organization_dashboard_constraint.rb +1 -1
- data/decidim-admin/app/controllers/decidim/admin/features_controller.rb +2 -2
- data/decidim-admin/app/controllers/decidim/admin/newsletters_controller.rb +115 -0
- data/decidim-admin/app/controllers/decidim/admin/participatory_processes_controller.rb +4 -4
- data/decidim-admin/app/forms/decidim/admin/newsletter_form.rb +15 -0
- data/decidim-admin/app/jobs/decidim/admin/newsletter_delivery_job.rb +18 -0
- data/decidim-admin/app/jobs/decidim/admin/newsletter_job.rb +32 -0
- data/decidim-admin/app/models/decidim/admin/abilities/admin_user.rb +4 -0
- data/decidim-admin/app/models/decidim/admin/abilities/base.rb +4 -0
- data/decidim-admin/app/models/decidim/admin/abilities/collaborator_user.rb +19 -0
- data/decidim-admin/app/models/decidim/admin/abilities/participatory_process_admin.rb +1 -1
- data/decidim-admin/app/queries/decidim/admin/manageable_participatory_processes_for_user.rb +1 -1
- data/decidim-admin/app/views/decidim/admin/newsletters/_form.html.erb +5 -0
- data/decidim-admin/app/views/decidim/admin/newsletters/edit.html.erb +11 -0
- data/decidim-admin/app/views/decidim/admin/newsletters/index.html.erb +47 -0
- data/decidim-admin/app/views/decidim/admin/newsletters/new.html.erb +11 -0
- data/decidim-admin/app/views/decidim/admin/newsletters/show.html.erb +14 -0
- data/decidim-admin/app/views/decidim/admin/participatory_process_steps/_form.html.erb +1 -1
- data/decidim-admin/app/views/decidim/admin/participatory_processes/_form.html.erb +1 -1
- data/decidim-admin/app/views/decidim/admin/static_pages/_form.html.erb +1 -1
- data/decidim-admin/app/views/layouts/decidim/admin/_sidebar.html.erb +1 -0
- data/decidim-admin/config/locales/ca.yml +40 -0
- data/decidim-admin/config/locales/en.yml +40 -0
- data/decidim-admin/config/locales/es.yml +40 -0
- data/decidim-admin/config/routes.rb +7 -0
- data/decidim-admin/decidim-admin.gemspec +0 -1
- data/decidim-admin/lib/decidim/admin/engine.rb +1 -0
- data/decidim-admin/lib/decidim/admin/features/base_controller.rb +5 -1
- data/decidim-admin/spec/commands/create_newsletter_spec.rb +62 -0
- data/decidim-admin/spec/commands/deliver_newsletter_spec.rb +45 -0
- data/decidim-admin/spec/commands/destroy_participatory_process_step_spec.rb +12 -0
- data/decidim-admin/spec/commands/update_newsletter_spec.rb +64 -0
- data/decidim-admin/spec/features/admin_manages_newsletters_spec.rb +147 -0
- data/decidim-admin/spec/features/admin_manages_participatory_processes_spec.rb +1 -5
- data/decidim-admin/spec/features/static_pages_spec.rb +16 -0
- data/decidim-admin/spec/forms/newsletter_form_spec.rb +47 -0
- data/decidim-admin/spec/jobs/newsletter_delivery_job_spec.rb +25 -0
- data/decidim-admin/spec/jobs/newsletter_job_spec.rb +29 -0
- data/decidim-admin/spec/models/abilities/collaborator_user_spec.rb +66 -0
- data/decidim-admin/spec/organization_dashboard_constraint_spec.rb +55 -0
- data/decidim-admin/spec/queries/manageable_participatory_processes_for_user_spec.rb +8 -0
- data/decidim-admin/spec/shared/manage_processes_examples.rb +1 -5
- data/decidim-api/lib/decidim/api.rb +2 -7
- data/decidim-api/lib/decidim/api/{types/mutation.rb → mutation_type.rb} +0 -0
- data/decidim-api/lib/decidim/api/{types/query.rb → query_type.rb} +0 -0
- data/decidim-budgets/app/assets/javascripts/decidim/budgets/projects.js.es6 +4 -4
- data/decidim-budgets/app/commands/decidim/budgets/add_line_item.rb +4 -2
- data/decidim-budgets/app/commands/decidim/budgets/checkout.rb +7 -3
- data/decidim-budgets/app/models/decidim/budgets/order.rb +16 -1
- data/decidim-budgets/app/models/decidim/budgets/project.rb +16 -0
- data/decidim-budgets/app/views/decidim/budgets/line_items/update_budget.js.erb +7 -7
- data/decidim-budgets/app/views/decidim/budgets/projects/_budget_confirm.html.erb +27 -25
- data/decidim-budgets/app/views/decidim/budgets/projects/_budget_summary.html.erb +4 -13
- data/decidim-budgets/app/views/decidim/budgets/projects/_order_progress.html.erb +23 -21
- data/decidim-budgets/app/views/decidim/budgets/projects/_order_selected_projects.html.erb +25 -23
- data/decidim-budgets/app/views/decidim/budgets/projects/_order_total_budget.html.erb +3 -1
- data/decidim-budgets/app/views/decidim/budgets/projects/_project.html.erb +32 -30
- data/decidim-budgets/app/views/decidim/budgets/projects/_projects.html.erb +1 -3
- data/decidim-budgets/app/views/decidim/budgets/projects/index.html.erb +0 -4
- data/decidim-budgets/app/views/decidim/budgets/projects/show.html.erb +5 -6
- data/decidim-budgets/config/i18n-tasks.yml +1 -0
- data/decidim-budgets/config/locales/ca.yml +7 -2
- data/decidim-budgets/config/locales/en.yml +17 -6
- data/decidim-budgets/config/locales/es.yml +7 -2
- data/decidim-budgets/lib/decidim/budgets/feature.rb +2 -2
- data/decidim-budgets/spec/commands/add_line_item_spec.rb +16 -3
- data/decidim-budgets/spec/commands/cancel_order_spec.rb +7 -1
- data/decidim-budgets/spec/commands/checkout_spec.rb +9 -2
- data/decidim-budgets/spec/commands/remove_line_item_spec.rb +16 -5
- data/decidim-budgets/spec/features/orders_spec.rb +8 -2
- data/decidim-budgets/spec/models/order_spec.rb +31 -2
- data/decidim-budgets/spec/shared/admin_shared_context.rb +1 -1
- data/decidim-comments/README.md +1 -1
- data/decidim-comments/app/assets/javascripts/decidim/comments/bundle.js +0 -0
- data/decidim-comments/app/frontend/comments/add_comment_form.component.jsx +156 -93
- data/decidim-comments/app/frontend/comments/add_comment_form.component.test.jsx +36 -23
- data/decidim-comments/app/frontend/comments/add_comment_form.mutation.graphql +5 -3
- data/decidim-comments/app/frontend/comments/add_comment_form_commentable.fragment.graphql +4 -0
- data/decidim-comments/app/frontend/comments/add_comment_form_session.fragment.graphql +6 -0
- data/decidim-comments/app/frontend/comments/comment.component.jsx +11 -13
- data/decidim-comments/app/frontend/comments/comment.component.test.jsx +22 -21
- data/decidim-comments/app/frontend/comments/comment.fragment.graphql +4 -4
- data/decidim-comments/app/frontend/comments/comment_data.fragment.graphql +4 -3
- data/decidim-comments/app/frontend/comments/comment_order_selector.component.jsx +1 -1
- data/decidim-comments/app/frontend/comments/comment_thread.component.jsx +3 -3
- data/decidim-comments/app/frontend/comments/comment_thread.component.test.jsx +3 -3
- data/decidim-comments/app/frontend/comments/comment_thread.fragment.graphql +1 -1
- data/decidim-comments/app/frontend/comments/comments.component.jsx +47 -39
- data/decidim-comments/app/frontend/comments/comments.component.test.jsx +51 -38
- data/decidim-comments/app/frontend/comments/comments.query.graphql +10 -4
- data/decidim-comments/app/frontend/comments/down_vote_button.component.jsx +6 -3
- data/decidim-comments/app/frontend/comments/up_vote_button.component.jsx +7 -4
- data/decidim-comments/app/frontend/support/generate_comments_data.js +4 -4
- data/decidim-comments/app/models/decidim/comments/comment.rb +7 -9
- data/decidim-comments/app/queries/decidim/comments/{comments_with_replies.rb → sorted_comments.rb} +3 -8
- data/decidim-comments/app/types/decidim/comments/commentable_interface.rb +44 -0
- data/decidim-comments/app/types/decidim/comments/commentable_mutation_type.rb +29 -0
- data/decidim-comments/app/types/decidim/comments/commentable_type.rb +14 -0
- data/decidim-comments/config/locales/ca.yml +3 -1
- data/decidim-comments/config/locales/en.yml +5 -2
- data/decidim-comments/config/locales/es.yml +3 -1
- data/decidim-comments/lib/decidim/comments.rb +4 -0
- data/decidim-comments/{app/types/decidim/comments → lib/decidim/comments/api}/add_comment_type.rb +0 -0
- data/decidim-comments/{app/types/decidim/comments → lib/decidim/comments/api}/comment_mutation_type.rb +0 -0
- data/decidim-comments/{app/types/decidim/comments → lib/decidim/comments/api}/comment_type.rb +11 -17
- data/decidim-comments/lib/decidim/comments/commentable.rb +45 -0
- data/decidim-comments/lib/decidim/comments/comments_helper.rb +15 -10
- data/decidim-comments/lib/decidim/comments/mutation_extensions.rb +8 -16
- data/decidim-comments/lib/decidim/comments/query_extensions.rb +5 -8
- data/decidim-comments/lib/decidim/comments/test/factories.rb +3 -3
- data/decidim-comments/spec/commands/vote_comment_spec.rb +3 -1
- data/decidim-comments/spec/features/comments_spec.rb +28 -14
- data/decidim-comments/spec/features/notifications_spec.rb +1 -1
- data/decidim-comments/spec/helpers/comments_helper_spec.rb +4 -27
- data/decidim-comments/spec/models/comment_spec.rb +7 -11
- data/decidim-comments/spec/models/comment_vote_spec.rb +3 -1
- data/decidim-comments/spec/models/seed_spec.rb +3 -4
- data/decidim-comments/spec/queries/{comments_with_replies_spec.rb → sorted_comments_spec.rb} +12 -29
- data/decidim-comments/spec/types/comment_type_spec.rb +23 -17
- data/decidim-comments/spec/types/commentable_mutation_type_spec.rb +34 -0
- data/decidim-comments/spec/types/commentable_type_spec.rb +48 -0
- data/decidim-comments/spec/types/mutation_type_spec.rb +5 -22
- data/decidim-comments/spec/types/query_type_spec.rb +0 -24
- data/decidim-dev/config/i18n-tasks.yml +4 -0
- data/decidim-dev/decidim-dev.gemspec +1 -1
- data/decidim-dev/lib/decidim/dev/test/rspec_support/action_mailer.rb +10 -4
- data/decidim-dev/lib/decidim/dev/test/rspec_support/feature.rb +6 -5
- data/decidim-dev/lib/decidim/dev/test/rspec_support/i18n.rb +0 -1
- data/decidim-meetings/app/assets/javascripts/decidim/meetings/map.js.es6.erb +8 -3
- data/decidim-meetings/app/assets/stylesheets/decidim/meetings/map.css +3 -1
- data/decidim-meetings/app/controllers/decidim/meetings/meetings_controller.rb +2 -2
- data/decidim-meetings/app/forms/decidim/meetings/admin/close_meeting_form.rb +2 -1
- data/decidim-meetings/app/helpers/decidim/meetings/map_helper.rb +1 -0
- data/decidim-meetings/app/services/decidim/meetings/meeting_search.rb +7 -3
- data/decidim-meetings/app/views/decidim/meetings/meetings/_datetime.html.erb +1 -1
- data/decidim-meetings/app/views/decidim/meetings/meetings/_filters.html.erb +5 -5
- data/decidim-meetings/app/views/decidim/meetings/meetings/_linked_meetings.html.erb +1 -1
- data/decidim-meetings/app/views/decidim/meetings/meetings/index.html.erb +1 -5
- data/decidim-meetings/app/views/decidim/meetings/meetings/show.html.erb +16 -9
- data/decidim-meetings/config/locales/ca.yml +2 -3
- data/decidim-meetings/config/locales/en.yml +2 -3
- data/decidim-meetings/config/locales/es.yml +2 -3
- data/decidim-meetings/spec/features/explore_meetings_spec.rb +75 -24
- data/decidim-meetings/spec/forms/close_meeting_form_spec.rb +1 -1
- data/decidim-meetings/spec/services/meeting_search_spec.rb +15 -12
- data/decidim-meetings/vendor/assets/javascripts/leaflet.markercluster.js +7 -0
- data/decidim-meetings/vendor/assets/stylesheets/MarkerCluster.Default.css +60 -0
- data/decidim-meetings/vendor/assets/stylesheets/MarkerCluster.css +14 -0
- data/decidim-pages/app/models/decidim/pages/page.rb +22 -0
- data/decidim-pages/app/views/decidim/pages/application/show.html.erb +2 -6
- data/decidim-pages/config/locales/ca.yml +2 -2
- data/decidim-pages/config/locales/en.yml +2 -2
- data/decidim-pages/config/locales/es.yml +2 -2
- data/decidim-pages/lib/decidim/pages/feature.rb +2 -2
- data/decidim-pages/spec/features/page_show_spec.rb +0 -33
- data/decidim-proposals/app/controllers/decidim/proposals/admin/proposal_answers_controller.rb +2 -0
- data/decidim-proposals/app/controllers/decidim/proposals/admin/proposals_controller.rb +2 -0
- data/decidim-proposals/app/models/decidim/proposals/abilities/admin_user.rb +45 -0
- data/decidim-proposals/app/models/decidim/proposals/abilities/process_admin_user.rb +57 -0
- data/decidim-proposals/app/models/decidim/proposals/proposal.rb +21 -0
- data/decidim-proposals/app/views/decidim/proposals/admin/proposals/_form.html.erb +1 -1
- data/decidim-proposals/app/views/decidim/proposals/admin/proposals/index.html.erb +16 -10
- data/decidim-proposals/app/views/decidim/proposals/proposal_votes/update_buttons_and_counters.js.erb +4 -4
- data/decidim-proposals/app/views/decidim/proposals/proposals/_filters.html.erb +7 -3
- data/decidim-proposals/app/views/decidim/proposals/proposals/_proposal.html.erb +2 -6
- data/decidim-proposals/app/views/decidim/proposals/proposals/_remaining_votes_count.html.erb +3 -1
- data/decidim-proposals/app/views/decidim/proposals/proposals/_tags.html.erb +1 -1
- data/decidim-proposals/app/views/decidim/proposals/proposals/_vote_button.html.erb +23 -21
- data/decidim-proposals/app/views/decidim/proposals/proposals/_votes_count.html.erb +9 -6
- data/decidim-proposals/app/views/decidim/proposals/proposals/_votes_limit.html.erb +1 -3
- data/decidim-proposals/app/views/decidim/proposals/proposals/index.html.erb +0 -4
- data/decidim-proposals/app/views/decidim/proposals/proposals/new.html.erb +1 -1
- data/decidim-proposals/app/views/decidim/proposals/proposals/show.html.erb +2 -6
- data/decidim-proposals/config/locales/ca.yml +8 -1
- data/decidim-proposals/config/locales/en.yml +8 -1
- data/decidim-proposals/config/locales/es.yml +8 -1
- data/decidim-proposals/lib/decidim/proposals/admin_engine.rb +7 -0
- data/decidim-proposals/lib/decidim/proposals/feature.rb +6 -2
- data/decidim-proposals/spec/features/proposals_spec.rb +226 -40
- data/decidim-proposals/spec/models/decidim/proposals/abilities/admin_user_spec.rb +62 -0
- data/decidim-proposals/spec/models/decidim/proposals/abilities/process_admin_user_spec.rb +63 -0
- data/decidim-proposals/spec/shared/manage_proposals_examples.rb +161 -50
- data/decidim-results/app/models/decidim/results/result.rb +21 -0
- data/decidim-results/app/views/decidim/results/results/index.html.erb +0 -4
- data/decidim-results/app/views/decidim/results/results/show.html.erb +2 -8
- data/decidim-results/config/i18n-tasks.yml +1 -0
- data/decidim-results/config/locales/ca.yml +5 -2
- data/decidim-results/config/locales/en.yml +5 -2
- data/decidim-results/config/locales/es.yml +5 -2
- data/decidim-results/lib/decidim/results/feature.rb +2 -2
- data/decidim-results/spec/services/result_stats_calculator_spec.rb +2 -2
- data/decidim-results/spec/shared/admin_shared_context.rb +1 -1
- data/decidim-system/config/i18n-tasks.yml +1 -1
- data/package.json +50 -51
- data/yarn.lock +198 -151
- metadata +69 -36
- data/decidim-admin/spec/features/admin_access_control.rb +0 -52
- data/decidim-api/lib/decidim/api/types/author_interface.rb +0 -13
- data/decidim-api/lib/decidim/api/types/localized_string.rb +0 -13
- data/decidim-api/lib/decidim/api/types/translated_field.rb +0 -44
- data/decidim-api/spec/types/localized_string_type_spec.rb +0 -31
- data/decidim-api/spec/types/translated_field_type_spec.rb +0 -69
- data/decidim-comments/app/frontend/comments/add_comment_form.fragment.graphql +0 -6
@@ -1,8 +1,6 @@
|
|
1
1
|
<div class="card card--list budget-list">
|
2
2
|
<% projects.each do |project| %>
|
3
|
-
|
4
|
-
<%= render partial: 'project', locals: { project: project } %>
|
5
|
-
</div>
|
3
|
+
<%= render partial: 'project', locals: { project: project } %>
|
6
4
|
<% end %>
|
7
5
|
</div>
|
8
6
|
<%= decidim_paginate projects, random_seed: random_seed %>
|
@@ -1,4 +1,7 @@
|
|
1
|
-
<%
|
1
|
+
<% add_decidim_meta_tags(
|
2
|
+
title: translated_attribute(project.title),
|
3
|
+
description: translated_attribute(project.description)
|
4
|
+
) %>
|
2
5
|
|
3
6
|
<div class="row column view-header">
|
4
7
|
<% if current_user.present? %>
|
@@ -34,11 +37,7 @@
|
|
34
37
|
</div>
|
35
38
|
</div>
|
36
39
|
|
37
|
-
<%=
|
38
|
-
<% if feature_settings.comments_always_enabled || current_settings.comments_enabled %>
|
39
|
-
<%= comments_for project, votable: true %>
|
40
|
-
<% end %>
|
41
|
-
<% end %>
|
40
|
+
<%= comments_for project %>
|
42
41
|
|
43
42
|
<%= attachments_for project %>
|
44
43
|
<%= javascript_include_tag("decidim/budgets/projects") %>
|
@@ -71,8 +71,6 @@ ca:
|
|
71
71
|
category: Categoria
|
72
72
|
scopes: Àmbits
|
73
73
|
search: Cerca
|
74
|
-
index:
|
75
|
-
meta_title: "%{feature_name}"
|
76
74
|
order_progress:
|
77
75
|
vote: Votar
|
78
76
|
order_selected_projects:
|
@@ -93,6 +91,13 @@ ca:
|
|
93
91
|
features:
|
94
92
|
budgets:
|
95
93
|
name: Pressupostos
|
94
|
+
settings:
|
95
|
+
global:
|
96
|
+
comments_enabled: Comentaris habilitats
|
97
|
+
total_budget: Pressupost total
|
98
|
+
vote_threshold_percent: Percentatge del pressupost mínim per fer el vot
|
99
|
+
step:
|
100
|
+
comments_blocked: Comentaris bloquejats
|
96
101
|
orders:
|
97
102
|
checkout:
|
98
103
|
error: S'ha produït un error en processar el teu vot
|
@@ -45,14 +45,17 @@ en:
|
|
45
45
|
title: Title
|
46
46
|
projects:
|
47
47
|
budget_confirm:
|
48
|
-
are_you_sure: Do you agree? Once you have confirmed your vote, you can not
|
48
|
+
are_you_sure: Do you agree? Once you have confirmed your vote, you can not
|
49
|
+
change it.
|
49
50
|
cancel: Cancel
|
50
51
|
confirm: Confirm
|
51
52
|
description: These are the projects you have chosen to be part of the budget.
|
52
53
|
title: Confirm vote
|
53
54
|
budget_excess:
|
54
55
|
close: Close
|
55
|
-
description: This project exceeds the maximum budget and can not be added.
|
56
|
+
description: This project exceeds the maximum budget and can not be added.
|
57
|
+
If you want, you can delete a project you have already selected to add,
|
58
|
+
or make your vote with your preferences.
|
56
59
|
ok: OK
|
57
60
|
title: Maximum budget exceeded
|
58
61
|
budget_summary:
|
@@ -60,9 +63,12 @@ en:
|
|
60
63
|
assigned: 'Assigned:'
|
61
64
|
cancel_order: delete your vote and start over
|
62
65
|
checked_out:
|
63
|
-
description: You've already voted for the budget. If you've changed your
|
66
|
+
description: You've already voted for the budget. If you've changed your
|
67
|
+
mind, you can %{cancel_link}.
|
64
68
|
title: Budget vote completed
|
65
|
-
description: What projects do you think we should allocate budget for? Assign
|
69
|
+
description: What projects do you think we should allocate budget for? Assign
|
70
|
+
at least %{minimum_budget} to the projects you want and vote with your
|
71
|
+
preferences to define the budget.
|
66
72
|
title: You decide the budget
|
67
73
|
count:
|
68
74
|
projects_count:
|
@@ -72,8 +78,6 @@ en:
|
|
72
78
|
category: Category
|
73
79
|
scopes: Scopes
|
74
80
|
search: Search
|
75
|
-
index:
|
76
|
-
meta_title: "%{feature_name}"
|
77
81
|
order_progress:
|
78
82
|
vote: Vote
|
79
83
|
order_selected_projects:
|
@@ -94,6 +98,13 @@ en:
|
|
94
98
|
features:
|
95
99
|
budgets:
|
96
100
|
name: Budgets
|
101
|
+
settings:
|
102
|
+
global:
|
103
|
+
comments_enabled: Comments enabled
|
104
|
+
total_budget: Total budget
|
105
|
+
vote_threshold_percent: Vote threshold percent
|
106
|
+
step:
|
107
|
+
comments_blocked: Comments blocked
|
97
108
|
orders:
|
98
109
|
checkout:
|
99
110
|
error: An error ocurred while processing your vote
|
@@ -71,8 +71,6 @@ es:
|
|
71
71
|
category: Categoría
|
72
72
|
scopes: Ámbitos
|
73
73
|
search: Buscar
|
74
|
-
index:
|
75
|
-
meta_title: "%{feature_name}"
|
76
74
|
order_progress:
|
77
75
|
vote: Votar
|
78
76
|
order_selected_projects:
|
@@ -93,6 +91,13 @@ es:
|
|
93
91
|
features:
|
94
92
|
budgets:
|
95
93
|
name: Presupuestos
|
94
|
+
settings:
|
95
|
+
global:
|
96
|
+
comments_enabled: Comentarios habilitados
|
97
|
+
total_budget: Presupuesto total
|
98
|
+
vote_threshold_percent: Porcentaje mínimo del presupuesto
|
99
|
+
step:
|
100
|
+
comments_blocked: Comentarios bloqueados
|
96
101
|
orders:
|
97
102
|
checkout:
|
98
103
|
error: Se ha producido un error al procesar tu voto
|
@@ -22,11 +22,11 @@ Decidim.register_feature(:budgets) do |feature|
|
|
22
22
|
feature.settings(:global) do |settings|
|
23
23
|
settings.attribute :total_budget, type: :integer, default: 100_000_000
|
24
24
|
settings.attribute :vote_threshold_percent, type: :integer, default: 70
|
25
|
-
settings.attribute :
|
25
|
+
settings.attribute :comments_enabled, type: :boolean, default: true
|
26
26
|
end
|
27
27
|
|
28
28
|
feature.settings(:step) do |settings|
|
29
|
-
settings.attribute :
|
29
|
+
settings.attribute :comments_blocked, type: :boolean, default: false
|
30
30
|
end
|
31
31
|
|
32
32
|
feature.seeds do
|
@@ -2,8 +2,9 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe Decidim::Budgets::AddLineItem do
|
4
4
|
let(:user) { create(:user) }
|
5
|
-
let(:feature) { create(:budget_feature, organization: user.organization) }
|
6
|
-
let(:project) { create(:project, feature: feature) }
|
5
|
+
let(:feature) { create(:budget_feature, organization: user.organization, settings: settings) }
|
6
|
+
let(:project) { create(:project, feature: feature, budget: 60_000) }
|
7
|
+
let(:settings) { { "total_budget" => 100_000, vote_threshold_percent: 50 }}
|
7
8
|
let(:order) { nil }
|
8
9
|
|
9
10
|
subject { described_class.new(order, project, user) }
|
@@ -39,7 +40,19 @@ describe Decidim::Budgets::AddLineItem do
|
|
39
40
|
end
|
40
41
|
|
41
42
|
context "when the order is checked out" do
|
42
|
-
let
|
43
|
+
let(:projects) do
|
44
|
+
build_list(:project, 2, budget: 30_000, feature: feature)
|
45
|
+
end
|
46
|
+
|
47
|
+
let!(:order) do
|
48
|
+
order = create(:order,
|
49
|
+
user: user,
|
50
|
+
feature: feature)
|
51
|
+
order.projects << projects
|
52
|
+
order.checked_out_at = Time.current
|
53
|
+
order.save!
|
54
|
+
order
|
55
|
+
end
|
43
56
|
|
44
57
|
it "broadcasts invalid" do
|
45
58
|
expect { subject.call }.to broadcast(:invalid)
|
@@ -9,7 +9,13 @@ describe Decidim::Budgets::CancelOrder do
|
|
9
9
|
)
|
10
10
|
end
|
11
11
|
let(:project) { create(:project, feature: feature, budget: 90_000_000) }
|
12
|
-
let(:order)
|
12
|
+
let(:order) do
|
13
|
+
order = create(:order, user: user, feature: feature)
|
14
|
+
order.projects << project
|
15
|
+
order.checked_out_at = Time.zone.now
|
16
|
+
order.save!
|
17
|
+
order
|
18
|
+
end
|
13
19
|
|
14
20
|
subject { described_class.new(order) }
|
15
21
|
|
@@ -8,9 +8,16 @@ describe Decidim::Budgets::Checkout do
|
|
8
8
|
organization: user.organization
|
9
9
|
)
|
10
10
|
end
|
11
|
+
|
11
12
|
let(:project) { create(:project, feature: feature, budget: 90_000_000) }
|
12
|
-
|
13
|
-
let
|
13
|
+
|
14
|
+
let(:order) do
|
15
|
+
order = create(:order, user: user, feature: feature)
|
16
|
+
order.projects << project
|
17
|
+
order.save!
|
18
|
+
order
|
19
|
+
end
|
20
|
+
|
14
21
|
let(:current_order) { order }
|
15
22
|
|
16
23
|
subject { described_class.new(current_order, feature) }
|
@@ -2,10 +2,19 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe Decidim::Budgets::RemoveLineItem do
|
4
4
|
let(:user) { create(:user) }
|
5
|
-
let(:feature)
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
let(:feature) do
|
6
|
+
create(:budget_feature,
|
7
|
+
organization: user.organization,
|
8
|
+
settings: { "total_budget" => 100_000, "vote_threshold_percent": 50})
|
9
|
+
end
|
10
|
+
let(:project) { create(:project, feature: feature, budget: 100) }
|
11
|
+
|
12
|
+
let(:order) do
|
13
|
+
order = create(:order, user: user, feature: feature)
|
14
|
+
order.projects << project
|
15
|
+
order.save!
|
16
|
+
order
|
17
|
+
end
|
9
18
|
|
10
19
|
subject { described_class.new(order, project) }
|
11
20
|
|
@@ -22,7 +31,9 @@ describe Decidim::Budgets::RemoveLineItem do
|
|
22
31
|
end
|
23
32
|
|
24
33
|
context "when the order is checked out" do
|
25
|
-
|
34
|
+
before do
|
35
|
+
order.update_attribute :checked_out_at, Time.current
|
36
|
+
end
|
26
37
|
|
27
38
|
it "broadcasts invalid" do
|
28
39
|
expect { subject.call }.to broadcast(:invalid)
|
@@ -123,7 +123,7 @@ describe "Orders", type: :feature do
|
|
123
123
|
|
124
124
|
expect(page).to have_selector '.budget-list__data--added', count: 2
|
125
125
|
|
126
|
-
within "#order-progress .budget-summary__progressbox" do
|
126
|
+
within "#order-progress .budget-summary__progressbox:not(.budget-summary__progressbox--fixed)" do
|
127
127
|
page.find('.button.small').click
|
128
128
|
end
|
129
129
|
|
@@ -143,7 +143,13 @@ describe "Orders", type: :feature do
|
|
143
143
|
end
|
144
144
|
|
145
145
|
context "and has a finished order" do
|
146
|
-
let!(:order)
|
146
|
+
let!(:order) do
|
147
|
+
order = create(:order, user: user, feature: feature)
|
148
|
+
order.projects << projects
|
149
|
+
order.checked_out_at = Time.current
|
150
|
+
order.save!
|
151
|
+
order
|
152
|
+
end
|
147
153
|
|
148
154
|
it "can cancel the order" do
|
149
155
|
visit_feature
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require "spec_helper"
|
4
4
|
|
5
5
|
describe Decidim::Budgets::Order do
|
6
|
-
let(:order) {
|
6
|
+
let!(:order) { create :order, feature: create(:budget_feature) }
|
7
7
|
subject { order }
|
8
8
|
|
9
9
|
describe "validations" do
|
@@ -26,6 +26,34 @@ describe Decidim::Budgets::Order do
|
|
26
26
|
new_order = build :order, user: subject.user, feature: subject.feature
|
27
27
|
expect(new_order).to be_invalid
|
28
28
|
end
|
29
|
+
|
30
|
+
it "can't exceed a maximum order value" do
|
31
|
+
project1 = create(:project, feature: subject.feature, budget: 100)
|
32
|
+
project2 = create(:project, feature: subject.feature, budget: 20)
|
33
|
+
|
34
|
+
subject.projects << project1
|
35
|
+
subject.projects << project2
|
36
|
+
|
37
|
+
subject.feature.settings = {
|
38
|
+
"total_budget" => 100, "vote_threshold" => 50
|
39
|
+
}
|
40
|
+
|
41
|
+
expect(subject).to be_invalid
|
42
|
+
end
|
43
|
+
|
44
|
+
it "can't be lower than a minimum order value when checked out" do
|
45
|
+
project1 = create(:project, feature: subject.feature, budget: 20)
|
46
|
+
|
47
|
+
subject.projects << project1
|
48
|
+
|
49
|
+
subject.feature.settings = {
|
50
|
+
"total_budget" => 100, "vote_threshold" => 50
|
51
|
+
}
|
52
|
+
|
53
|
+
expect(subject).to be_valid
|
54
|
+
subject.checked_out_at = Time.current
|
55
|
+
expect(subject).to be_invalid
|
56
|
+
end
|
29
57
|
end
|
30
58
|
|
31
59
|
describe "#total_budget" do
|
@@ -33,6 +61,7 @@ describe Decidim::Budgets::Order do
|
|
33
61
|
subject.projects << build(:project, feature: subject.feature)
|
34
62
|
|
35
63
|
expect(subject.total_budget).to eq(subject.projects.sum(&:budget))
|
64
|
+
expect(subject)
|
36
65
|
end
|
37
66
|
end
|
38
67
|
|
@@ -42,4 +71,4 @@ describe Decidim::Budgets::Order do
|
|
42
71
|
expect(subject).to be_checked_out
|
43
72
|
end
|
44
73
|
end
|
45
|
-
end
|
74
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
RSpec.shared_context "admin" do
|
2
2
|
let(:organization) { create(:organization) }
|
3
3
|
let!(:user) { create(:user, :admin, :confirmed, organization: organization, email: "admin@decidim.org") }
|
4
|
-
let(:participatory_process) { create(:participatory_process, organization: organization) }
|
4
|
+
let(:participatory_process) { create(:participatory_process, :with_steps, organization: organization) }
|
5
5
|
let(:process_admin) { create :user, :confirmed, organization: organization }
|
6
6
|
let!(:user_role) { create :participatory_process_user_role, user: process_admin, participatory_process: participatory_process }
|
7
7
|
let(:current_feature) { create :feature, participatory_process: participatory_process, manifest_name: "budgets" }
|
data/decidim-comments/README.md
CHANGED
Binary file
|
@@ -1,20 +1,21 @@
|
|
1
|
-
/* eslint-disable no-return-assign, react/no-unused-prop-types */
|
2
|
-
import { Component, PropTypes }
|
3
|
-
import { graphql }
|
4
|
-
import gql
|
5
|
-
import { I18n }
|
6
|
-
import uuid
|
7
|
-
import classnames
|
8
|
-
|
9
|
-
import Icon
|
10
|
-
|
11
|
-
import addCommentMutation
|
12
|
-
import commentThreadFragment
|
13
|
-
import commentFragment
|
14
|
-
import commentDataFragment
|
15
|
-
import upVoteFragment
|
16
|
-
import downVoteFragment
|
17
|
-
import
|
1
|
+
/* eslint-disable no-return-assign, react/no-unused-prop-types, max-lines */
|
2
|
+
import { Component, PropTypes } from 'react';
|
3
|
+
import { graphql } from 'react-apollo';
|
4
|
+
import gql from 'graphql-tag';
|
5
|
+
import { I18n, Translate } from 'react-i18nify';
|
6
|
+
import uuid from 'uuid';
|
7
|
+
import classnames from 'classnames';
|
8
|
+
|
9
|
+
import Icon from '../application/icon.component';
|
10
|
+
|
11
|
+
import addCommentMutation from './add_comment_form.mutation.graphql';
|
12
|
+
import commentThreadFragment from './comment_thread.fragment.graphql'
|
13
|
+
import commentFragment from './comment.fragment.graphql';
|
14
|
+
import commentDataFragment from './comment_data.fragment.graphql';
|
15
|
+
import upVoteFragment from './up_vote.fragment.graphql';
|
16
|
+
import downVoteFragment from './down_vote.fragment.graphql';
|
17
|
+
import addCommentFormSessionFragment from './add_comment_form_session.fragment.graphql';
|
18
|
+
import addCommentFormCommentableFragment from './add_comment_form_commentable.fragment.graphql';
|
18
19
|
|
19
20
|
/**
|
20
21
|
* Renders a form to create new comments.
|
@@ -27,46 +28,18 @@ export class AddCommentForm extends Component {
|
|
27
28
|
|
28
29
|
this.state = {
|
29
30
|
disabled: true,
|
31
|
+
error: false,
|
30
32
|
alignment: 0
|
31
33
|
};
|
32
34
|
}
|
33
35
|
|
34
|
-
componentDidMount() {
|
35
|
-
if ($(document).foundation) {
|
36
|
-
$(this.form).foundation();
|
37
|
-
}
|
38
|
-
}
|
39
|
-
|
40
36
|
render() {
|
41
|
-
const { submitButtonClassName, commentableType, commentableId, maxLength } = this.props;
|
42
|
-
const { disabled } = this.state;
|
43
|
-
|
44
37
|
return (
|
45
38
|
<div className="add-comment">
|
46
39
|
{this._renderHeading()}
|
40
|
+
{this._renderAccountMessage()}
|
47
41
|
{this._renderOpinionButtons()}
|
48
|
-
|
49
|
-
onSubmit={(evt) => this._addComment(evt)}
|
50
|
-
data-abide
|
51
|
-
data-live-validate="true"
|
52
|
-
data-validate-on-blur="true"
|
53
|
-
ref={(form) => this.form = form}
|
54
|
-
>
|
55
|
-
{this._renderCommentAs()}
|
56
|
-
<div className="field">
|
57
|
-
<label className="show-for-sr" htmlFor={`add-comment-${commentableType}-${commentableId}`}>{ I18n.t("components.add_comment_form.form.body.label") }</label>
|
58
|
-
{this._renderTextArea()}
|
59
|
-
<span className="form-error">
|
60
|
-
{ I18n.t("components.add_comment_form.form.form_error", { length: maxLength }) }
|
61
|
-
</span>
|
62
|
-
<input
|
63
|
-
type="submit"
|
64
|
-
className={submitButtonClassName}
|
65
|
-
value={I18n.t("components.add_comment_form.form.submit")}
|
66
|
-
disabled={disabled}
|
67
|
-
/>
|
68
|
-
</div>
|
69
|
-
</form>
|
42
|
+
{this._renderForm()}
|
70
43
|
</div>
|
71
44
|
);
|
72
45
|
}
|
@@ -90,17 +63,75 @@ export class AddCommentForm extends Component {
|
|
90
63
|
return null;
|
91
64
|
}
|
92
65
|
|
66
|
+
/**
|
67
|
+
* Render a message telling the user to sign in or sign up to leave a comment.
|
68
|
+
* @private
|
69
|
+
* @returns {Void|DOMElement} - The message or an empty element.
|
70
|
+
*/
|
71
|
+
_renderAccountMessage() {
|
72
|
+
const { session } = this.props;
|
73
|
+
|
74
|
+
if (!session) {
|
75
|
+
return (
|
76
|
+
<p>
|
77
|
+
<Translate
|
78
|
+
value="components.add_comment_form.account_message"
|
79
|
+
sign_in_url="/users/sign_in"
|
80
|
+
sign_up_url="/users/sign_up"
|
81
|
+
dangerousHTML
|
82
|
+
/>
|
83
|
+
</p>
|
84
|
+
);
|
85
|
+
}
|
86
|
+
|
87
|
+
return null;
|
88
|
+
}
|
89
|
+
|
90
|
+
/**
|
91
|
+
* Render the add comment form if session is present.
|
92
|
+
* @private
|
93
|
+
* @returns {Void|DOMElement} - The add comment form on an empty element.
|
94
|
+
*/
|
95
|
+
_renderForm() {
|
96
|
+
const { session, submitButtonClassName, commentable: { id, type } } = this.props;
|
97
|
+
const { disabled } = this.state;
|
98
|
+
|
99
|
+
if (session) {
|
100
|
+
return (
|
101
|
+
<form onSubmit={(evt) => this._addComment(evt)}>
|
102
|
+
{this._renderCommentAs()}
|
103
|
+
<div className="field">
|
104
|
+
<label className="show-for-sr" htmlFor={`add-comment-${type}-${id}`}>{ I18n.t("components.add_comment_form.form.body.label") }</label>
|
105
|
+
{this._renderTextArea()}
|
106
|
+
{this._renderTextAreaError()}
|
107
|
+
<input
|
108
|
+
type="submit"
|
109
|
+
className={submitButtonClassName}
|
110
|
+
value={I18n.t("components.add_comment_form.form.submit")}
|
111
|
+
disabled={disabled}
|
112
|
+
/>
|
113
|
+
</div>
|
114
|
+
</form>
|
115
|
+
);
|
116
|
+
}
|
117
|
+
|
118
|
+
return null;
|
119
|
+
}
|
120
|
+
|
93
121
|
/**
|
94
122
|
* Render the form heading based on showTitle prop
|
95
123
|
* @private
|
96
124
|
* @returns {Void|DOMElement} - The heading or an empty element
|
97
125
|
*/
|
98
126
|
_renderTextArea() {
|
99
|
-
const {
|
127
|
+
const { commentable: { id, type }, autoFocus, maxLength } = this.props;
|
128
|
+
const { error } = this.state;
|
129
|
+
const className = classnames({ 'is-invalid-input': error });
|
100
130
|
|
101
131
|
let textAreaProps = {
|
102
132
|
ref: (textarea) => {this.bodyTextArea = textarea},
|
103
|
-
id: `add-comment-${
|
133
|
+
id: `add-comment-${type}-${id}`,
|
134
|
+
className,
|
104
135
|
rows: "4",
|
105
136
|
maxLength,
|
106
137
|
required: "required",
|
@@ -117,13 +148,33 @@ export class AddCommentForm extends Component {
|
|
117
148
|
);
|
118
149
|
}
|
119
150
|
|
151
|
+
/**
|
152
|
+
* Render the text area form error if state has an error
|
153
|
+
* @private
|
154
|
+
* @returns {Void|DOMElement} - The error or an empty element
|
155
|
+
*/
|
156
|
+
_renderTextAreaError() {
|
157
|
+
const { maxLength } = this.props;
|
158
|
+
const { error } = this.state;
|
159
|
+
|
160
|
+
if (error) {
|
161
|
+
return (
|
162
|
+
<span className="form-error is-visible">
|
163
|
+
{ I18n.t("components.add_comment_form.form.form_error", { length: maxLength }) }
|
164
|
+
</span>
|
165
|
+
);
|
166
|
+
}
|
167
|
+
|
168
|
+
return null;
|
169
|
+
}
|
170
|
+
|
120
171
|
/**
|
121
172
|
* Render opinion buttons or not based on the arguable prop
|
122
173
|
* @private
|
123
174
|
* @returns {Void|DOMElement} - Returns nothing or a wrapper with buttons
|
124
175
|
*/
|
125
176
|
_renderOpinionButtons() {
|
126
|
-
const { arguable } = this.props;
|
177
|
+
const { session, arguable } = this.props;
|
127
178
|
const { alignment } = this.state;
|
128
179
|
const buttonClassName = classnames('button', 'tiny', 'button--muted');
|
129
180
|
const okButtonClassName = classnames(buttonClassName, 'opinion-toggle--ok', {
|
@@ -136,7 +187,7 @@ export class AddCommentForm extends Component {
|
|
136
187
|
'is-active': alignment === 0
|
137
188
|
});
|
138
189
|
|
139
|
-
if (arguable) {
|
190
|
+
if (session && arguable) {
|
140
191
|
return (
|
141
192
|
<div className="opinion-toggle button-group">
|
142
193
|
<button
|
@@ -170,18 +221,18 @@ export class AddCommentForm extends Component {
|
|
170
221
|
* @returns {Void|DOMElement} - Returns nothing or a form field.
|
171
222
|
*/
|
172
223
|
_renderCommentAs() {
|
173
|
-
const { session,
|
224
|
+
const { session, commentable: { id, type } } = this.props;
|
174
225
|
const { user, verifiedUserGroups } = session;
|
175
226
|
|
176
227
|
if (verifiedUserGroups.length > 0) {
|
177
228
|
return (
|
178
229
|
<div className="field">
|
179
|
-
<label htmlFor={`add-comment-${
|
230
|
+
<label htmlFor={`add-comment-${type}-${id}-user-group-id`}>
|
180
231
|
{ I18n.t('components.add_comment_form.form.user_group_id.label') }
|
181
232
|
</label>
|
182
233
|
<select
|
183
234
|
ref={(select) => {this.userGroupIdSelect = select}}
|
184
|
-
id={`add-comment-${
|
235
|
+
id={`add-comment-${type}-${id}-user-group-id`}
|
185
236
|
>
|
186
237
|
<option value="">{ user.name }</option>
|
187
238
|
{
|
@@ -204,7 +255,8 @@ export class AddCommentForm extends Component {
|
|
204
255
|
* @returns {Void} - Returns nothing
|
205
256
|
*/
|
206
257
|
_checkCommentBody(body) {
|
207
|
-
|
258
|
+
const { maxLength } = this.props;
|
259
|
+
this.setState({ disabled: body === '', error: body === '' || body.length > maxLength });
|
208
260
|
}
|
209
261
|
|
210
262
|
/**
|
@@ -247,9 +299,11 @@ AddCommentForm.propTypes = {
|
|
247
299
|
name: PropTypes.string.isRequired
|
248
300
|
})
|
249
301
|
).isRequired
|
250
|
-
})
|
251
|
-
|
252
|
-
|
302
|
+
}),
|
303
|
+
commentable: PropTypes.shape({
|
304
|
+
id: PropTypes.string.isRequired,
|
305
|
+
type: PropTypes.string.isRequired
|
306
|
+
}),
|
253
307
|
showTitle: PropTypes.bool.isRequired,
|
254
308
|
submitButtonClassName: PropTypes.string.isRequired,
|
255
309
|
onCommentAdded: PropTypes.func,
|
@@ -268,8 +322,11 @@ AddCommentForm.defaultProps = {
|
|
268
322
|
};
|
269
323
|
|
270
324
|
AddCommentForm.fragments = {
|
271
|
-
|
272
|
-
${
|
325
|
+
session: gql`
|
326
|
+
${addCommentFormSessionFragment}
|
327
|
+
`,
|
328
|
+
commentable: gql`
|
329
|
+
${addCommentFormCommentableFragment}
|
273
330
|
`
|
274
331
|
};
|
275
332
|
|
@@ -284,48 +341,51 @@ const AddCommentFormWithMutation = graphql(gql`
|
|
284
341
|
props: ({ ownProps, mutate }) => ({
|
285
342
|
addComment: ({ body, alignment, userGroupId }) => mutate({
|
286
343
|
variables: {
|
287
|
-
commentableId: ownProps.
|
288
|
-
commentableType: ownProps.
|
344
|
+
commentableId: ownProps.commentable.id,
|
345
|
+
commentableType: ownProps.commentable.type,
|
289
346
|
body,
|
290
347
|
alignment,
|
291
348
|
userGroupId
|
292
349
|
},
|
293
350
|
optimisticResponse: {
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
351
|
+
commentable: {
|
352
|
+
__typename: 'CommentableMutation',
|
353
|
+
addComment: {
|
354
|
+
__typename: 'Comment',
|
355
|
+
id: uuid(),
|
356
|
+
type: "Decidim::Comments::Comment",
|
357
|
+
createdAt: new Date().toISOString(),
|
358
|
+
body,
|
359
|
+
alignment: alignment,
|
360
|
+
author: {
|
361
|
+
__typename: 'User',
|
362
|
+
name: ownProps.session.user.name,
|
363
|
+
avatarUrl: ownProps.session.user.avatarUrl
|
364
|
+
},
|
365
|
+
comments: [],
|
366
|
+
hasComments: false,
|
367
|
+
acceptsNewComments: false,
|
368
|
+
upVotes: 0,
|
369
|
+
upVoted: false,
|
370
|
+
downVotes: 0,
|
371
|
+
downVoted: false
|
372
|
+
}
|
313
373
|
}
|
314
374
|
},
|
315
375
|
updateQueries: {
|
316
376
|
GetComments: (prev, { mutationResult: { data } }) => {
|
317
|
-
const {
|
318
|
-
const newComment = data.addComment;
|
377
|
+
const { id, type } = ownProps.commentable;
|
378
|
+
const newComment = data.commentable.addComment;
|
319
379
|
let comments = [];
|
320
380
|
|
321
381
|
const commentReducer = (comment) => {
|
322
|
-
const replies = comment.
|
382
|
+
const replies = comment.comments || [];
|
323
383
|
|
324
|
-
if (comment.id ===
|
384
|
+
if (comment.id === id) {
|
325
385
|
return {
|
326
386
|
...comment,
|
327
|
-
|
328
|
-
|
387
|
+
hasComments: true,
|
388
|
+
comments: [
|
329
389
|
...replies,
|
330
390
|
newComment
|
331
391
|
]
|
@@ -333,22 +393,25 @@ const AddCommentFormWithMutation = graphql(gql`
|
|
333
393
|
}
|
334
394
|
return {
|
335
395
|
...comment,
|
336
|
-
|
396
|
+
comments: replies.map(commentReducer)
|
337
397
|
};
|
338
398
|
};
|
339
399
|
|
340
|
-
if (
|
341
|
-
comments = prev.comments.map(commentReducer);
|
400
|
+
if (type === "Decidim::Comments::Comment") {
|
401
|
+
comments = prev.commentable.comments.map(commentReducer);
|
342
402
|
} else {
|
343
403
|
comments = [
|
344
|
-
...prev.comments,
|
404
|
+
...prev.commentable.comments,
|
345
405
|
newComment
|
346
406
|
];
|
347
407
|
}
|
348
408
|
|
349
409
|
return {
|
350
410
|
...prev,
|
351
|
-
|
411
|
+
commentable: {
|
412
|
+
...prev.commentable,
|
413
|
+
comments
|
414
|
+
}
|
352
415
|
};
|
353
416
|
}
|
354
417
|
}
|