decidim-reporting_proposals 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +32 -0
  3. data/.erb-lint.yml +30 -0
  4. data/.eslintignore +3 -0
  5. data/.eslintrc.json +239 -0
  6. data/.github/workflows/codeql-analysis.yml +74 -0
  7. data/.github/workflows/lint.yml +45 -0
  8. data/.github/workflows/test_integration.yml +125 -0
  9. data/.github/workflows/test_unit.yml +51 -0
  10. data/.gitignore +27 -0
  11. data/.rspec +3 -0
  12. data/.rubocop.yml +3 -0
  13. data/.rubocop_rails.yml +87 -0
  14. data/.rubocop_ruby.yml +1754 -0
  15. data/.ruby-version +1 -0
  16. data/.simplecov +13 -0
  17. data/CODE_OF_CONDUCT.md +74 -0
  18. data/Gemfile +40 -0
  19. data/Gemfile.lock +815 -0
  20. data/LICENSE-AGPLv3.txt +661 -0
  21. data/README.md +166 -0
  22. data/Rakefile +40 -0
  23. data/app/cells/decidim/reporting_proposals/edit_note_modal/show.erb +20 -0
  24. data/app/cells/decidim/reporting_proposals/edit_note_modal_cell.rb +37 -0
  25. data/app/commands/concerns/decidim/reporting_proposals/admin/create_category_override.rb +32 -0
  26. data/app/commands/concerns/decidim/reporting_proposals/admin/update_category_override.rb +32 -0
  27. data/app/commands/concerns/decidim/reporting_proposals/create_report_override.rb +19 -0
  28. data/app/commands/decidim/reporting_proposals/admin/update_proposal.rb +46 -0
  29. data/app/commands/decidim/reporting_proposals/admin/update_proposal_note.rb +36 -0
  30. data/app/commands/decidim/reporting_proposals/create_reporting_proposal.rb +68 -0
  31. data/app/controllers/concerns/decidim/reporting_proposals/admin/categories_controller_override.rb +16 -0
  32. data/app/controllers/concerns/decidim/reporting_proposals/admin/needs_header_snippets.rb +50 -0
  33. data/app/controllers/concerns/decidim/reporting_proposals/admin/proposal_answer_templates_controller_override.rb +18 -0
  34. data/app/controllers/concerns/decidim/reporting_proposals/admin/proposal_answers_controller_override.rb +35 -0
  35. data/app/controllers/concerns/decidim/reporting_proposals/admin/proposals_controller_override.rb +28 -0
  36. data/app/controllers/concerns/decidim/reporting_proposals/needs_proposal_extra_validations_snippets.rb +51 -0
  37. data/app/controllers/concerns/decidim/reporting_proposals/proposals_controller_override.rb +113 -0
  38. data/app/controllers/decidim/reporting_proposals/admin/application_controller.rb +18 -0
  39. data/app/controllers/decidim/reporting_proposals/admin/proposal_notes_controller.rb +38 -0
  40. data/app/controllers/decidim/reporting_proposals/admin/proposals_controller.rb +61 -0
  41. data/app/controllers/decidim/reporting_proposals/application_controller.rb +11 -0
  42. data/app/controllers/decidim/reporting_proposals/geolocation_controller.rb +32 -0
  43. data/app/forms/concerns/decidim/reporting_proposals/admin/category_form_override.rb +19 -0
  44. data/app/forms/concerns/decidim/reporting_proposals/form_builder_override.rb +48 -0
  45. data/app/forms/concerns/decidim/reporting_proposals/map_builder_override.rb +60 -0
  46. data/app/forms/decidim/reporting_proposals/admin/proposal_photo_form.rb +23 -0
  47. data/app/forms/decidim/reporting_proposals/proposal_form.rb +33 -0
  48. data/app/helpers/concerns/decidim/reporting_proposals/admin/proposals_helper_override.rb +63 -0
  49. data/app/helpers/concerns/decidim/reporting_proposals/proposal_wizard_helper_override.rb +61 -0
  50. data/app/jobs/decidim/reporting_proposals/assign_proposal_valuators_job.rb +51 -0
  51. data/app/models/concerns/decidim/reporting_proposals/category_override.rb +28 -0
  52. data/app/models/concerns/decidim/reporting_proposals/participatory_space_role_config/valuator_override.rb +17 -0
  53. data/app/models/concerns/decidim/reporting_proposals/participatory_space_user_role_override.rb +25 -0
  54. data/app/models/decidim/reporting_proposals/category_valuator.rb +28 -0
  55. data/app/overrides/decidim/admin/categories/_form/add_valuators_field.html.erb.deface +3 -0
  56. data/app/overrides/decidim/admin/categories/index/add_table_column_name.html.erb.deface +3 -0
  57. data/app/overrides/decidim/admin/categories/index/add_valuators.html.erb.deface +3 -0
  58. data/app/overrides/decidim/proposals/admin/proposal_notes/_proposal_notes/add_edit_link.html.erb.deface +3 -0
  59. data/app/overrides/decidim/proposals/admin/proposal_notes/_proposal_notes/add_links_to_note.html.erb.deface +3 -0
  60. data/app/overrides/decidim/proposals/admin/proposals/_proposal-tr/add_td_hide_action.html.erb.deface +3 -0
  61. data/app/overrides/decidim/proposals/admin/proposals/_proposal-tr/add_valuators_name.html.erb.deface +9 -0
  62. data/app/overrides/decidim/proposals/admin/proposals/_proposal-tr/replace_td_title.html.erb.deface +3 -0
  63. data/app/overrides/decidim/proposals/admin/proposals/show/add_photo_management.html.erb.deface +3 -0
  64. data/app/overrides/decidim/proposals/admin/proposals/show/add_send_email_btn.html.erb.deface +3 -0
  65. data/app/overrides/decidim/proposals/admin/proposals/show/remove_photos.html.erb.deface +4 -0
  66. data/app/overrides/decidim/proposals/admin/proposals/show/replace_valuators.html.erb.deface +3 -0
  67. data/app/overrides/decidim/proposals/proposals/_proposal_similar/add_distance_badge.html.erb.deface +5 -0
  68. data/app/overrides/decidim/proposals/proposals/_wizard_header/replace_title.html.erb.deface +14 -0
  69. data/app/overrides/decidim/proposals/proposals/edit/add_user_group.html.erb.deface +3 -0
  70. data/app/overrides/decidim/proposals/proposals/edit/replace_javascript.html.erb.deface +8 -0
  71. data/app/overrides/decidim/proposals/proposals/edit/replace_partial_edit_form_fields.html.erb.deface +3 -0
  72. data/app/overrides/decidim/proposals/proposals/edit_draft/add_user_group.html.erb.deface +3 -0
  73. data/app/overrides/decidim/proposals/proposals/edit_draft/replace_javascript.html.erb.deface +8 -0
  74. data/app/overrides/decidim/proposals/proposals/edit_draft/replace_partial_edit_form_fields.html.erb.deface +3 -0
  75. data/app/overrides/decidim/proposals/proposals/index/add_additional_button.html.erb.deface +3 -0
  76. data/app/overrides/decidim/proposals/proposals/new/remove_title.html.erb.deface +1 -0
  77. data/app/overrides/decidim/proposals/proposals/new/replace_body.html.erb.deface +3 -0
  78. data/app/overrides/decidim/proposals/proposals/new/replace_javascript.html.erb.deface +8 -0
  79. data/app/overrides/decidim/proposals/proposals/show/add_additional_button.html.erb.deface +3 -0
  80. data/app/overrides/layouts/decidim/_process_header_steps/always_show_new_proposals.html.erb.deface +3 -0
  81. data/app/packs/entrypoints/decidim_reporting_proposals.js +6 -0
  82. data/app/packs/entrypoints/decidim_reporting_proposals_camera.js +2 -0
  83. data/app/packs/entrypoints/decidim_reporting_proposals_geocoding.js +2 -0
  84. data/app/packs/entrypoints/decidim_reporting_proposals_js_validations.js +1 -0
  85. data/app/packs/entrypoints/decidim_reporting_proposals_list_component_admin.js +1 -0
  86. data/app/packs/entrypoints/decidim_reporting_proposals_manage_component_admin.js +1 -0
  87. data/app/packs/images/.keep +0 -0
  88. data/app/packs/src/decidim/reporting_proposals/proposal_extra_validations.js +89 -0
  89. data/app/packs/src/decidim/reporting_proposals/proposals/add_proposal.js +66 -0
  90. data/app/packs/src/decidim/reporting_proposals/reverse_geocoding.js +54 -0
  91. data/app/packs/src/decidim/reporting_proposals/user_camera_inputs.js +49 -0
  92. data/app/packs/stylesheets/decidim/reporting_proposals/geocoding_addons.scss +34 -0
  93. data/app/packs/stylesheets/decidim/reporting_proposals/list_component_admin.scss +27 -0
  94. data/app/packs/stylesheets/decidim/reporting_proposals/manage_component_admin.scss +31 -0
  95. data/app/packs/stylesheets/decidim/reporting_proposals/proposals/add_proposal.scss +12 -0
  96. data/app/packs/stylesheets/decidim/reporting_proposals/user_camera_inputs.scss +19 -0
  97. data/app/permissions/concerns/decidim/reporting_proposals/admin/permissions_override.rb +27 -0
  98. data/app/permissions/decidim/reporting_proposals/admin/permissions.rb +79 -0
  99. data/app/permissions/decidim/reporting_proposals/permissions.rb +17 -0
  100. data/app/queries/decidim/reporting_proposals/nearby_proposals.rb +57 -0
  101. data/app/serializers/decidim/reporting_proposals/proposal_serializer_override.rb +77 -0
  102. data/app/validators/concerns/decidim/reporting_proposals/component_validator_override.rb +25 -0
  103. data/app/views/decidim/proposals/admin/proposal_notes/_editing_note.html.erb +18 -0
  104. data/app/views/decidim/proposals/admin/proposal_notes/_proposal_notes_body.html.erb +6 -0
  105. data/app/views/decidim/proposals/admin/proposals/_send_email_button.html.erb +4 -0
  106. data/app/views/decidim/proposals/proposals/_additional_button.html.erb +6 -0
  107. data/app/views/decidim/reporting_proposals/admin/categories/_column_valuators.html.erb +1 -0
  108. data/app/views/decidim/reporting_proposals/admin/categories/_valuators.html.erb +1 -0
  109. data/app/views/decidim/reporting_proposals/admin/categories/_valuators_field.html.erb +7 -0
  110. data/app/views/decidim/reporting_proposals/admin/proposals/_photo_form.html.erb +24 -0
  111. data/app/views/decidim/reporting_proposals/admin/proposals/_photo_gallery.html.erb +21 -0
  112. data/app/views/decidim/reporting_proposals/admin/proposals/_photos.html.erb +14 -0
  113. data/app/views/decidim/reporting_proposals/admin/proposals/_proposal_td_hide.html.erb +20 -0
  114. data/app/views/decidim/reporting_proposals/admin/proposals/_proposal_td_title.html.erb +41 -0
  115. data/app/views/decidim/reporting_proposals/proposals/_additional_button_for_show.html.erb +6 -0
  116. data/app/views/decidim/reporting_proposals/proposals/_new_proposal_fields.html.erb +7 -0
  117. data/app/views/decidim/reporting_proposals/proposals/_reporting_proposal_fields.html.erb +113 -0
  118. data/app/views/decidim/reporting_proposals/proposals/_user_group.html.erb +5 -0
  119. data/bin/rails +6 -0
  120. data/bin/webpack-dev-server +6 -0
  121. data/codecov.yml +11 -0
  122. data/config/assets.rb +13 -0
  123. data/config/i18n-tasks.yml +13 -0
  124. data/config/locales/ca.yml +366 -0
  125. data/config/locales/de.yml +366 -0
  126. data/config/locales/en.yml +426 -0
  127. data/config/locales/es.yml +366 -0
  128. data/crowdin.yml +45 -0
  129. data/db/migrate/20221219151846_create_decidim_categories_valuators.rb +17 -0
  130. data/decidim-reporting_proposals.gemspec +34 -0
  131. data/lib/decidim/api/reporting_proposals_type.rb +10 -0
  132. data/lib/decidim/reporting_proposals/admin.rb +8 -0
  133. data/lib/decidim/reporting_proposals/admin_engine.rb +31 -0
  134. data/lib/decidim/reporting_proposals/component.rb +490 -0
  135. data/lib/decidim/reporting_proposals/config.rb +53 -0
  136. data/lib/decidim/reporting_proposals/engine.rb +96 -0
  137. data/lib/decidim/reporting_proposals/test/factories.rb +13 -0
  138. data/lib/decidim/reporting_proposals/version.rb +15 -0
  139. data/lib/decidim/reporting_proposals.rb +13 -0
  140. data/package-lock.json +7844 -0
  141. data/package.json +195 -0
  142. metadata +319 -0
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module ReportingProposals
5
+ class AssignProposalValuatorsJob < ApplicationJob
6
+ queue_as :default
7
+ attr_reader :resource
8
+
9
+ def perform(data)
10
+ @resource = data[:resource]
11
+
12
+ return if valuator_roles.blank?
13
+
14
+ unless data[:event_class] == "Decidim::Proposals::Admin::UpdateProposalCategoryEvent"
15
+ return unless data[:extra][:participatory_space]
16
+ return if data[:extra][:type] == "admin"
17
+ end
18
+
19
+ valuator_roles.each do |valuator_role|
20
+ Decidim::Proposals::Admin::AssignProposalsToValuator.call(form(valuator_role)) do
21
+ on(:ok) do
22
+ Rails.logger.info("Automatically assigned valuator #{valuator_role.user.name} to proposal ##{resource.id}")
23
+ end
24
+ on(:invalid) do
25
+ Rails.logger.warn("Couldn't automatically assign valuator #{valuator_role.user.name} to proposal ##{resource.id}")
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ def form(valuator_role)
32
+ Decidim::Proposals::Admin::ValuationAssignmentForm.from_params(
33
+ id: valuator_role.id,
34
+ proposal_ids: [resource.id]
35
+ ).with_context(
36
+ current_component: resource.component,
37
+ current_user: resource.organization.users.first # first admin for the traceability
38
+ )
39
+ end
40
+
41
+ # get valuators from categories
42
+ def valuator_roles
43
+ @valuator_roles ||= category.valuator_roles
44
+ end
45
+
46
+ def category
47
+ @category ||= resource.category
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module ReportingProposals
5
+ module CategoryOverride
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ has_many :category_valuators,
10
+ class_name: "Decidim::ReportingProposals::CategoryValuator",
11
+ foreign_key: :decidim_category_id,
12
+ dependent: :destroy
13
+
14
+ def valuator_roles
15
+ category_valuators.map(&:valuator_role)
16
+ end
17
+
18
+ def valuator_users
19
+ category_valuators.map(&:user)
20
+ end
21
+
22
+ def valuator_names
23
+ valuator_users.map(&:name)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module ReportingProposals
5
+ module ParticipatorySpaceRoleConfig
6
+ module ValuatorOverride
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ def accepted_components
11
+ [:proposals, :reporting_proposals]
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module ReportingProposals
5
+ module ParticipatorySpaceUserRoleOverride
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ has_many :category_valuators,
10
+ class_name: "Decidim::ReportingProposals::CategoryValuator",
11
+ foreign_key: :valuator_role_id,
12
+ dependent: :destroy
13
+
14
+ # there is a bug in decidim that does not clean records from ValuationAssignment when removing Space roles
15
+ # This is a workaround to clean them manually
16
+ # It might be possible that we need to change this when this is solved:
17
+ # https://github.com/decidim/decidim/issues/10353
18
+ has_many :proposal_valuation_assignments,
19
+ class_name: "Decidim::Proposals::ValuationAssignment",
20
+ foreign_key: :valuator_role_id,
21
+ dependent: :destroy
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module ReportingProposals
5
+ class CategoryValuator < ApplicationRecord
6
+ self.table_name = "decidim_reporting_proposals_category_valuators"
7
+
8
+ belongs_to :category,
9
+ foreign_key: "decidim_category_id",
10
+ class_name: "Decidim::Category"
11
+
12
+ belongs_to :valuator_role,
13
+ polymorphic: true
14
+
15
+ delegate :user, to: :valuator_role
16
+
17
+ validate :category_belongs_to_same_participatory_space
18
+
19
+ private
20
+
21
+ def category_belongs_to_same_participatory_space
22
+ return if category.participatory_space == valuator_role.participatory_space
23
+
24
+ errors.add(:category, :invalid)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ <!-- insert_bottom ".card-section" -->
2
+
3
+ <%= render "decidim/reporting_proposals/admin/categories/valuators_field", form: form %>
@@ -0,0 +1,3 @@
1
+ <!-- insert_before ".actions" -->
2
+
3
+ <%= render "decidim/reporting_proposals/admin/categories/column_valuators" %>
@@ -0,0 +1,3 @@
1
+ <!-- insert_before ".table-list__actions" -->
2
+
3
+ <%= render "decidim/reporting_proposals/admin/categories/valuators", category: defined?(subcategory) ? subcategory : category %>
@@ -0,0 +1,3 @@
1
+ <!-- insert_after "erb[loud]:contains('l note.created_at, format: :decidim_short')" -->
2
+
3
+ <%= render "decidim/proposals/admin/proposal_notes/editing_note", note: note %>
@@ -0,0 +1,3 @@
1
+ <!-- replace "erb[loud]:contains('simple_format note.body')" -->
2
+
3
+ <%= render partial: "decidim/proposals/admin/proposal_notes/proposal_notes_body", locals: { note: note } %>
@@ -0,0 +1,3 @@
1
+ <!-- insert_bottom ".table-list__actions" -->
2
+
3
+ <%= render "decidim/reporting_proposals/admin/proposals/proposal_td_hide", proposal: proposal %>
@@ -0,0 +1,9 @@
1
+ <!-- replace "erb[loud]:contains('proposal.valuation_assignments.count')" -->
2
+
3
+ <% count = proposal.valuation_assignments.count %>
4
+ <% if count.zero? %>
5
+ 0
6
+ <% else %>
7
+ <%= proposal.valuation_assignments.first&.valuator_role&.user&.name %>
8
+ <%= "(+#{(count - 1)})" if count > 1 %>
9
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <!-- replace_contents "td[3]" -->
2
+
3
+ <%= render "decidim/reporting_proposals/admin/proposals/proposal_td_title", proposal: proposal %>
@@ -0,0 +1,3 @@
1
+ <!-- insert_after ".card[1]" -->
2
+
3
+ <%= render partial: "decidim/reporting_proposals/admin/proposals/photos" %>
@@ -0,0 +1,3 @@
1
+ <!-- insert_after "erb[loud]:contains('current_or_new_conversation_path_with(presented_author)')" -->
2
+
3
+ <%= render partial: "decidim/proposals/admin/proposals/send_email_button", locals: { presented_author: presented_author }%>
@@ -0,0 +1,4 @@
1
+ <!-- replace "erb[silent]:contains('if proposal.photos.any?')" -->
2
+
3
+ <% if nil %>
4
+
@@ -0,0 +1,3 @@
1
+ <!-- replace "erb[silent]:contains('if proposal.valuators.any?')" -->
2
+
3
+ <% if true %>
@@ -0,0 +1,5 @@
1
+ <!-- insert_before ".card__header" -->
2
+
3
+ <% if geocoding_comparison? %>
4
+ <span class="label secondary float-right"><%= icon("location") %> <%= t("away", scope: "decidim.reporting_proposals.proposals.compare.geocoding", meters: distance(1000 * @proposal.distance_from([proposal.latitude, proposal.longitude], :km))) %></span>
5
+ <% end %>
@@ -0,0 +1,14 @@
1
+ <!-- replace ".section-heading" -->
2
+
3
+ <% if geocoding_comparison? && action_name == "compare" %>
4
+ <h2 class="section-heading">
5
+ <%= t("title", scope: "decidim.reporting_proposals.proposals.compare.geocoding") %>
6
+ <%= "(#{@similar_proposals.count})" if @similar_proposals.present? %>
7
+ </h2>
8
+ <p><%= t("description", scope: "decidim.reporting_proposals.proposals.compare.geocoding", meters: distance) %></p>
9
+ <% else %>
10
+ <h2 class="section-heading">
11
+ <%= proposal_wizard_step_title action_name %>
12
+ <%= "(#{@similar_proposals.count})" if @similar_proposals.present? %>
13
+ </h2>
14
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <!-- insert_before ".actions" -->
2
+
3
+ <%= render partial: "decidim/reporting_proposals/proposals/user_group", locals: { form: form } if reporting_proposal? %>
@@ -0,0 +1,8 @@
1
+ <!-- replace "erb[loud]:contains('javascript_pack_tag')" -->
2
+
3
+ <% if reporting_proposal? %>
4
+ <%= javascript_pack_tag "decidim_reporting_proposals" %>
5
+ <%= stylesheet_pack_tag "decidim_reporting_proposals" %>
6
+ <% else %>
7
+ <%= javascript_pack_tag "decidim_proposals" %>
8
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <!-- replace "erb[loud]:contains('edit_form_fields')" -->
2
+
3
+ <%= render "decidim/#{reporting_proposal? ? 'reporting_proposals/proposals/reporting_proposal_fields' : 'proposals/proposals/edit_form_fields'}", form: form %>
@@ -0,0 +1,3 @@
1
+ <!-- insert_before ".row.column.flex-center" -->
2
+
3
+ <%= render partial: "decidim/reporting_proposals/proposals/user_group", locals: { form: form } if reporting_proposal? %>
@@ -0,0 +1,8 @@
1
+ <!-- replace "erb[loud]:contains('javascript_pack_tag')" -->
2
+
3
+ <% if reporting_proposal? %>
4
+ <%= javascript_pack_tag "decidim_reporting_proposals" %>
5
+ <%= stylesheet_pack_tag "decidim_reporting_proposals" %>
6
+ <% else %>
7
+ <%= javascript_pack_tag "decidim_proposals" %>
8
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <!-- replace "erb[loud]:contains('edit_form_fields')" -->
2
+
3
+ <%= render "decidim/#{reporting_proposal? ? 'reporting_proposals/proposals/reporting_proposal_fields' : 'proposals/proposals/edit_form_fields'}", form: form %>
@@ -0,0 +1,3 @@
1
+ <!-- insert_before "erb[silent]:contains('if component_settings.collaborative_drafts_enabled?')" -->
2
+
3
+ <%= render partial: "decidim/proposals/proposals/additional_button" %>
@@ -0,0 +1 @@
1
+ <!-- remove ".hashtags__container" -->
@@ -0,0 +1,3 @@
1
+ <!-- insert_after "erb[loud]:contains('form_required_explanation')" -->
2
+
3
+ <%= render "decidim/reporting_proposals/proposals/#{reporting_proposal? ? 'reporting_proposal_fields' : 'new_proposal_fields'}", form: form %>
@@ -0,0 +1,8 @@
1
+ <!-- replace "erb[loud]:contains('javascript_pack_tag')" -->
2
+
3
+ <% if reporting_proposal? %>
4
+ <%= javascript_pack_tag "decidim_reporting_proposals" %>
5
+ <%= stylesheet_pack_tag "decidim_reporting_proposals" %>
6
+ <% else %>
7
+ <%= javascript_pack_tag "decidim_proposals" %>
8
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <!-- insert_bottom ".m-bottom" -->
2
+
3
+ <%= render partial: "decidim/reporting_proposals/proposals/additional_button_for_show" %>
@@ -0,0 +1,3 @@
1
+ <!-- replace "erb[loud]:contains('button small button--sc show-for-medium')" -->
2
+
3
+ <%= link_to(cta_text, step_cta_url(participatory_process), class: "button small button--sc") %>
@@ -0,0 +1,6 @@
1
+ import "src/decidim/proposals/utils"
2
+ import "src/decidim/reporting_proposals/proposals/add_proposal"
3
+ import "stylesheets/decidim/reporting_proposals/proposals/add_proposal.scss";
4
+
5
+ // Images
6
+ require.context("../images", true)
@@ -0,0 +1,2 @@
1
+ import "src/decidim/reporting_proposals/user_camera_inputs.js"
2
+ import "stylesheets/decidim/reporting_proposals/user_camera_inputs.scss";
@@ -0,0 +1,2 @@
1
+ import "src/decidim/reporting_proposals/reverse_geocoding.js"
2
+ import "stylesheets/decidim/reporting_proposals/geocoding_addons.scss";
@@ -0,0 +1 @@
1
+ import "src/decidim/reporting_proposals/proposal_extra_validations.js"
@@ -0,0 +1 @@
1
+ import "stylesheets/decidim/reporting_proposals/list_component_admin.scss";
@@ -0,0 +1 @@
1
+ import "stylesheets/decidim/reporting_proposals/manage_component_admin.scss";
File without changes
@@ -0,0 +1,89 @@
1
+ $(() => {
2
+
3
+ const $title = $('input[name="proposal[title]"]');
4
+ const $body = $('[name="proposal[body]"]');
5
+ let quill;
6
+ try {
7
+ quill = window.Quill.find(document.querySelector(".editor-container"));
8
+ } catch (e) {
9
+ console.log("Quill not found");
10
+ }
11
+ const $form = $title.closest("form");
12
+
13
+ const findError = ($field, prop) => {
14
+ let $closest = $field.closest("label");
15
+ if (!$closest.length) {
16
+ $closest = $field.closest(".editor");
17
+ }
18
+ // console.log("findError", $closest, $field, prop);
19
+ let search = `.form-error.${prop}`;
20
+ if (!prop) {
21
+ search = ".form-error"
22
+ }
23
+ let $error = $closest.find(search);
24
+ if ($error.length === 0) {
25
+ $error = $(`<span class="${search.replace(/\./g, " ")}"></span>`).appendTo($closest);
26
+ }
27
+ return $error;
28
+ };
29
+
30
+ const clearErrors = ($field, prop) => {
31
+ findError($field, prop).remove();
32
+ };
33
+
34
+ const addError = ($field, options, prop) => {
35
+ // console.log("addError", $field, options, prop)
36
+ let $error = findError($field, prop);
37
+ $error.addClass("is-visible");
38
+ if (options && options[prop]) {
39
+ $error.html(options[prop].error);
40
+ }
41
+ else {$error.html(Decidim.ProposalRules.genericError);}
42
+ };
43
+
44
+ const validate = ($field, value, options) => {
45
+ // console.log("validate", $field, value, options);
46
+
47
+ // validate caps if needed
48
+ const minLen = $field.attr("minlength");
49
+
50
+ if (options && options.caps.enabled) {
51
+ if (value.charAt(0) !== value.charAt(0).toUpperCase()) {
52
+ addError($field, options, "caps");
53
+ return false;
54
+ }
55
+ }
56
+ if (minLen && value.length < minLen) {
57
+ addError($field);
58
+ return false;
59
+ }
60
+ return true;
61
+ }
62
+
63
+ if ($title.length > 0) {
64
+ $title.change(() => {
65
+ clearErrors($title, "caps");
66
+ });
67
+ if (quill) {
68
+ // on change quill
69
+ quill.on("text-change", () => {
70
+ clearErrors($body, "caps");
71
+ clearErrors($body);
72
+ });
73
+ } else {
74
+ $body.change(() => {
75
+ clearErrors($body, "caps");
76
+ });
77
+ }
78
+ $form.on("submit", (ev) => {
79
+ if (!validate($title, $title.val(), Decidim.ProposalRules.title)) {
80
+ ev.preventDefault();
81
+ }
82
+ if (!validate($body, quill
83
+ ? quill.getText()
84
+ : $body.val(), Decidim.ProposalRules.body)) {
85
+ ev.preventDefault();
86
+ }
87
+ });
88
+ }
89
+ });
@@ -0,0 +1,66 @@
1
+ import attachGeocoding from "src/decidim/geocoding/attach_input"
2
+
3
+ $(() => {
4
+ const $checkbox = $("input:checkbox[name$='[has_no_address]']");
5
+ const $hasAdressInput = $("input[name$='[has_address]']");
6
+ const $addressInput = $("#address_input");
7
+ const $addressInputField = $("input[name='proposal[address]']");
8
+ const $map = $("#address_map");
9
+ let latFieldName = "proposal[latitude]";
10
+ let longFieldName = "proposal[longitude]";
11
+ const $labelInput = $("label[for='proposal_address']");
12
+ const $buttonLocation = $(".user-device-location button");
13
+
14
+ $map.hide();
15
+
16
+ // Handle no address checkbox in reverse, mandatory by default instead of default decidim
17
+ if ($checkbox.length > 0) {
18
+ const toggleInput = () => {
19
+ $hasAdressInput.val($checkbox[0].checked
20
+ ? 0
21
+ : 1);
22
+
23
+ if ($checkbox[0].checked) {
24
+ const $formError = $labelInput.find('span.form-error[style="display: block;"]');
25
+
26
+ $map.hide();
27
+ $addressInputField.prop("disabled", true);
28
+ $addressInputField.removeClass("is-invalid-input");
29
+ $labelInput.removeClass("is-invalid-label");
30
+ $buttonLocation.prop("disabled", true);
31
+ $buttonLocation.removeClass("loading-spinner");
32
+ $formError.attr("style", "display:none;");
33
+
34
+ } else {
35
+ if ($(`input[name='${latFieldName}']`).val()) {
36
+ $map.show();
37
+ }
38
+ $addressInputField.prop("disabled", false);
39
+ $buttonLocation.prop("disabled", false);
40
+ }
41
+ }
42
+ toggleInput();
43
+ $checkbox.on("change", toggleInput);
44
+ }
45
+
46
+ if ($addressInput.length > 0) {
47
+ const ctrl = $("[data-decidim-map]").data("map-controller");
48
+ ctrl.setEventHandler("coordinates", (ev) => {
49
+ $(`input[name='${latFieldName}']`).val(ev.lat);
50
+ $(`input[name='${longFieldName}']`).val(ev.lng);
51
+ });
52
+
53
+ attachGeocoding($addressInputField, null, (coordinates) => {
54
+ $map.show();
55
+ // Remove previous marker when user updates address in address field
56
+ ctrl.removeMarker();
57
+ ctrl.addMarker({
58
+ latitude: coordinates[0],
59
+ longitude: coordinates[1],
60
+ address: $addressInputField.val()
61
+ });
62
+ });
63
+ }
64
+
65
+
66
+ });
@@ -0,0 +1,54 @@
1
+ $(() => {
2
+ const info = ($target, msg) => {
3
+ const $label = $target.closest("label")
4
+ $label.find(".form-error").remove();
5
+ if (msg) {
6
+ $('<span class="form-error"/>').text(msg).appendTo($label).show();
7
+ }
8
+ };
9
+
10
+ const setLocating = ($button, enable) => {
11
+ if (enable) {
12
+ $button.addClass("loading-spinner");
13
+ $button.attr("disabled", true);
14
+ } else {
15
+ $button.removeClass("loading-spinner");
16
+ $button.attr("disabled", false);
17
+ }
18
+ }
19
+
20
+ $(".user-device-location button").on("click", (e) => {
21
+ const $this = $(e.target);
22
+ if ($this.is(":disabled")) {
23
+ return;
24
+ }
25
+
26
+ const $input = $(`#${e.target.dataset.input}`);
27
+ const errorNoLocation = e.target.dataset.errorNoLocation;
28
+ const errorUnsupported = e.target.dataset.errorUnsupported;
29
+ const url = e.target.dataset.url;
30
+
31
+ if (navigator.geolocation) {
32
+ setLocating($this, true);
33
+ navigator.geolocation.getCurrentPosition((position) => {
34
+ const coordinates = [position.coords.latitude, position.coords.longitude];
35
+ // reverse geolocation
36
+ $.post(url, { latitude: coordinates[0], longitude: coordinates[1] }, (data) => {
37
+ $input.val(data.address)
38
+ })
39
+ setLocating($this, false);
40
+ $input.trigger(
41
+ "geocoder-suggest-coordinates.decidim",
42
+ [coordinates]
43
+ );
44
+ }, (evt) => {
45
+ info($input, `${errorNoLocation} ${evt.message}`);
46
+ $this.attr("disabled", false);
47
+ }, {
48
+ enableHighAccuracy: true
49
+ });
50
+ } else {
51
+ info($input, errorUnsupported);
52
+ }
53
+ });
54
+ });
@@ -0,0 +1,49 @@
1
+ $(() => {
2
+ $('input[type="file"]').each((_i, el) => {
3
+ const $input = $(el);
4
+ const $inputField = $input.closest(".row.column");
5
+ const $button = $inputField.find("button:first");
6
+ const $checkbox = $inputField.find("input:checkbox[name$='[has_no_image]']");
7
+ const $formError = $inputField.find("span.form-error")
8
+ const $labelInput = $("label[for='proposal_add_photos']")
9
+
10
+ const removeErrors = () => {
11
+ $input.removeClass("is-invalid-input");
12
+ $formError.removeClass("is-visible");
13
+ $labelInput.removeClass("is-invalid-label");
14
+ };
15
+
16
+ const toggleInput = () => {
17
+ if ($checkbox[0].checked) {
18
+ removeErrors();
19
+ $input.prop("disabled", true);
20
+ $button.prop("disabled", true);
21
+ } else {
22
+ $input.prop("disabled", false);
23
+ $button.prop("disabled", false);
24
+ }
25
+ }
26
+
27
+ $input.attr("accept", "image/*");
28
+
29
+ $button.on("click", () => {
30
+ console.log("click button")
31
+ $input.attr("capture", "camera");
32
+ $input.click();
33
+ $input.removeAttr("capture", "camera");
34
+ });
35
+
36
+ $input.on("click", () => {
37
+ console.log("click", $input);
38
+ $input.one("blur", () => {
39
+ console.log("blur", $input);
40
+ removeErrors();
41
+ });
42
+ });
43
+
44
+ if ($checkbox.length > 0) {
45
+ $checkbox.on("change", toggleInput);
46
+ toggleInput();
47
+ }
48
+ });
49
+ });
@@ -0,0 +1,34 @@
1
+ .input-group.has-tribute {
2
+ position: relative;
3
+
4
+ .tribute-container {
5
+ margin-top: 2.3rem;
6
+ }
7
+ }
8
+
9
+ .user-device-location {
10
+ button {
11
+ max-height: 3rem;
12
+
13
+ &.loading-spinner {
14
+ position: relative;
15
+ margin: 0 !important;
16
+
17
+ &::before {
18
+ position: absolute;
19
+ top: 6px;
20
+ left: 12px;
21
+ }
22
+ }
23
+ }
24
+
25
+ @media only screen and (max-width: 596px) {
26
+ display: block !important;
27
+ margin-top: 1rem;
28
+ margin-bottom: -.5rem;
29
+
30
+ button {
31
+ border-radius: 4px !important;
32
+ }
33
+ }
34
+ }