decidim-budgets 0.27.4 → 0.28.0.rc5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (173) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/app/assets/stylesheets/decidim/budgets/budget/_budget-vote-button.scss +5 -5
  4. data/app/cells/decidim/budgets/budget_cell.rb +6 -1
  5. data/app/cells/decidim/budgets/budget_information_modal/show.erb +14 -26
  6. data/app/cells/decidim/budgets/budget_list_item/projects_count.erb +6 -0
  7. data/app/cells/decidim/budgets/budget_list_item/show.erb +34 -29
  8. data/app/cells/decidim/budgets/budget_list_item/vote_action.erb +13 -0
  9. data/app/cells/decidim/budgets/budget_list_item_cell.rb +24 -1
  10. data/app/cells/decidim/budgets/budget_metadata_cell.rb +29 -0
  11. data/app/cells/decidim/budgets/budget_s_cell.rb +15 -0
  12. data/app/cells/decidim/budgets/budgets_header/show.erb +2 -6
  13. data/app/cells/decidim/budgets/budgets_list/card_list.erb +8 -13
  14. data/app/cells/decidim/budgets/budgets_list/main_list.erb +5 -0
  15. data/app/cells/decidim/budgets/budgets_list/show.erb +12 -16
  16. data/app/cells/decidim/budgets/budgets_list/voted.erb +8 -44
  17. data/app/cells/decidim/budgets/budgets_list_cell.rb +34 -0
  18. data/app/cells/decidim/budgets/limit_announcement/show.erb +3 -0
  19. data/app/cells/decidim/budgets/limit_announcement_cell.rb +2 -2
  20. data/app/cells/decidim/budgets/order_activity_cell.rb +1 -4
  21. data/app/cells/decidim/budgets/project_cell.rb +6 -1
  22. data/app/cells/decidim/budgets/project_l/extra_data.erb +6 -0
  23. data/app/cells/decidim/budgets/project_l/metadata.erb +4 -0
  24. data/app/cells/decidim/budgets/project_l_cell.rb +38 -0
  25. data/app/cells/decidim/budgets/project_metadata_cell.rb +78 -0
  26. data/app/cells/decidim/budgets/project_s_cell.rb +21 -0
  27. data/app/cells/decidim/budgets/project_tags/show.erb +1 -0
  28. data/app/cells/decidim/budgets/project_vote_button/show.erb +21 -15
  29. data/app/cells/decidim/budgets/project_vote_button_cell.rb +69 -1
  30. data/app/cells/decidim/budgets/project_voted_hint_cell.rb +1 -1
  31. data/app/cells/decidim/budgets/project_votes_count_cell.rb +9 -8
  32. data/app/commands/decidim/budgets/admin/create_project.rb +0 -1
  33. data/app/commands/decidim/budgets/admin/import_proposals_to_budgets.rb +1 -1
  34. data/app/commands/decidim/budgets/admin/update_project.rb +1 -2
  35. data/app/commands/decidim/budgets/admin/update_project_scope.rb +1 -1
  36. data/app/commands/decidim/budgets/admin/update_project_selection.rb +1 -1
  37. data/app/commands/decidim/budgets/admin/update_projects_budget.rb +57 -0
  38. data/app/controllers/concerns/decidim/budgets/admin/filterable.rb +1 -1
  39. data/app/controllers/concerns/decidim/budgets/needs_current_order.rb +2 -2
  40. data/app/controllers/decidim/budgets/admin/budgets_controller.rb +5 -5
  41. data/app/controllers/decidim/budgets/admin/projects_controller.rb +50 -7
  42. data/app/controllers/decidim/budgets/admin/proposals_imports_controller.rb +1 -1
  43. data/app/controllers/decidim/budgets/application_controller.rb +0 -4
  44. data/app/controllers/decidim/budgets/budgets_controller.rb +9 -0
  45. data/app/controllers/decidim/budgets/line_items_controller.rb +1 -1
  46. data/app/controllers/decidim/budgets/orders_controller.rb +7 -2
  47. data/app/controllers/decidim/budgets/projects_controller.rb +51 -4
  48. data/app/forms/decidim/budgets/admin/project_form.rb +1 -1
  49. data/app/helpers/decidim/budgets/application_helper.rb +4 -0
  50. data/app/helpers/decidim/budgets/projects_helper.rb +89 -33
  51. data/app/jobs/decidim/budgets/send_vote_reminder_job.rb +1 -1
  52. data/app/mailers/decidim/budgets/order_summary_mailer.rb +1 -1
  53. data/app/mailers/decidim/budgets/vote_reminder_mailer.rb +1 -1
  54. data/app/models/decidim/budgets/budget.rb +1 -0
  55. data/app/models/decidim/budgets/project.rb +24 -10
  56. data/app/packs/entrypoints/decidim_budgets.js +2 -0
  57. data/app/packs/src/decidim/budgets/exit_handler.js +10 -7
  58. data/app/packs/src/decidim/budgets/progressFixed.js +25 -11
  59. data/app/packs/src/decidim/budgets/projects.js +15 -10
  60. data/app/packs/stylesheets/budgets.scss +273 -0
  61. data/app/presenters/decidim/budgets/admin_log/budget_presenter.rb +2 -2
  62. data/app/presenters/decidim/budgets/admin_log/project_presenter.rb +2 -2
  63. data/app/services/decidim/budgets/order_reminder_generator.rb +4 -4
  64. data/app/views/decidim/budgets/admin/budgets/_form.html.erb +17 -12
  65. data/app/views/decidim/budgets/admin/budgets/edit.html.erb +16 -6
  66. data/app/views/decidim/budgets/admin/budgets/index.html.erb +59 -61
  67. data/app/views/decidim/budgets/admin/budgets/new.html.erb +16 -6
  68. data/app/views/decidim/budgets/admin/projects/_bulk-actions.html.erb +19 -10
  69. data/app/views/decidim/budgets/admin/projects/_form.html.erb +31 -35
  70. data/app/views/decidim/budgets/admin/projects/_project-tr.html.erb +13 -9
  71. data/app/views/decidim/budgets/admin/projects/bulk_actions/_budget-change.html.erb +22 -0
  72. data/app/views/decidim/budgets/admin/projects/bulk_actions/_change-selected.html.erb +3 -3
  73. data/app/views/decidim/budgets/admin/projects/bulk_actions/_dropdown.html.erb +8 -2
  74. data/app/views/decidim/budgets/admin/projects/bulk_actions/_recategorize.html.erb +3 -3
  75. data/app/views/decidim/budgets/admin/projects/bulk_actions/_scope-change.html.erb +5 -8
  76. data/app/views/decidim/budgets/admin/projects/edit.html.erb +16 -6
  77. data/app/views/decidim/budgets/admin/projects/index.html.erb +25 -28
  78. data/app/views/decidim/budgets/admin/projects/new.html.erb +16 -6
  79. data/app/views/decidim/budgets/admin/projects/update_attribute.js.erb +8 -4
  80. data/app/views/decidim/budgets/admin/proposals_imports/new.html.erb +40 -28
  81. data/app/views/decidim/budgets/budgets/index.html.erb +21 -3
  82. data/app/views/decidim/budgets/budgets/index.js.erb +6 -0
  83. data/app/views/decidim/budgets/line_items/update_budget.js.erb +21 -11
  84. data/app/views/decidim/budgets/projects/_addition_selector.html.erb +16 -0
  85. data/app/views/decidim/budgets/projects/_budget_confirm.html.erb +42 -31
  86. data/app/views/decidim/budgets/projects/_budget_excess.html.erb +12 -12
  87. data/app/views/decidim/budgets/projects/_budget_summary.html.erb +2 -75
  88. data/app/views/decidim/budgets/projects/_exit_modal.html.erb +15 -18
  89. data/app/views/decidim/budgets/projects/_linked_projects.html.erb +3 -12
  90. data/app/views/decidim/budgets/projects/_order.html.erb +1 -0
  91. data/app/views/decidim/budgets/projects/_order_progress_progressbar_marks_right.html.erb +10 -0
  92. data/app/views/decidim/budgets/projects/_order_progress_summary_content.html.erb +113 -0
  93. data/app/views/decidim/budgets/projects/_order_total_budget.html.erb +6 -7
  94. data/app/views/decidim/budgets/projects/_project.html.erb +2 -1
  95. data/app/views/decidim/budgets/projects/_project_budget_button.html.erb +11 -19
  96. data/app/views/decidim/budgets/projects/_projects.html.erb +8 -6
  97. data/app/views/decidim/budgets/projects/_projects_count.html.erb +5 -0
  98. data/app/views/decidim/budgets/projects/_projects_list.html.erb +3 -0
  99. data/app/views/decidim/budgets/projects/index.html.erb +58 -55
  100. data/app/views/decidim/budgets/projects/index.js.erb +5 -4
  101. data/app/views/decidim/budgets/projects/show.html.erb +78 -51
  102. data/config/assets.rb +0 -1
  103. data/config/environment.rb +3 -0
  104. data/config/locales/ar.yml +0 -45
  105. data/config/locales/ca.yml +77 -80
  106. data/config/locales/cs.yml +78 -79
  107. data/config/locales/de.yml +79 -82
  108. data/config/locales/el.yml +34 -72
  109. data/config/locales/en.yml +82 -85
  110. data/config/locales/es-MX.yml +76 -79
  111. data/config/locales/es-PY.yml +76 -79
  112. data/config/locales/es.yml +76 -79
  113. data/config/locales/eu.yml +134 -109
  114. data/config/locales/fi-plain.yml +78 -81
  115. data/config/locales/fi.yml +81 -84
  116. data/config/locales/fr-CA.yml +74 -80
  117. data/config/locales/fr.yml +78 -84
  118. data/config/locales/ga-IE.yml +0 -11
  119. data/config/locales/gl.yml +0 -57
  120. data/config/locales/hu.yml +63 -58
  121. data/config/locales/id-ID.yml +0 -37
  122. data/config/locales/is-IS.yml +0 -21
  123. data/config/locales/it.yml +0 -83
  124. data/config/locales/ja.yml +71 -78
  125. data/config/locales/lb.yml +0 -84
  126. data/config/locales/lt.yml +70 -81
  127. data/config/locales/lv.yml +0 -43
  128. data/config/locales/nl.yml +0 -96
  129. data/config/locales/no.yml +0 -83
  130. data/config/locales/pl.yml +0 -87
  131. data/config/locales/pt-BR.yml +9 -79
  132. data/config/locales/pt.yml +0 -84
  133. data/config/locales/ro-RO.yml +0 -95
  134. data/config/locales/ru.yml +0 -40
  135. data/config/locales/sk.yml +0 -43
  136. data/config/locales/sq-AL.yml +1 -0
  137. data/config/locales/sr-CS.yml +0 -4
  138. data/config/locales/sv.yml +11 -90
  139. data/config/locales/th-TH.yml +1 -0
  140. data/config/locales/tr-TR.yml +2 -81
  141. data/config/locales/uk.yml +0 -40
  142. data/config/locales/zh-CN.yml +0 -64
  143. data/config/locales/zh-TW.yml +13 -59
  144. data/lib/decidim/budgets/admin_engine.rb +3 -2
  145. data/lib/decidim/budgets/component.rb +5 -91
  146. data/lib/decidim/budgets/engine.rb +30 -10
  147. data/lib/decidim/budgets/project_serializer.rb +3 -3
  148. data/lib/decidim/budgets/seeds.rb +69 -0
  149. data/lib/decidim/budgets/test/factories.rb +11 -10
  150. data/lib/decidim/budgets/version.rb +1 -1
  151. data/lib/decidim/budgets/workflows/base.rb +1 -1
  152. metadata +47 -39
  153. data/app/cells/decidim/budgets/budget_m/data.erb +0 -12
  154. data/app/cells/decidim/budgets/budget_m/footer.erb +0 -5
  155. data/app/cells/decidim/budgets/budget_m_cell.rb +0 -16
  156. data/app/cells/decidim/budgets/project_list_item/project_data.erb +0 -19
  157. data/app/cells/decidim/budgets/project_list_item/project_image.erb +0 -5
  158. data/app/cells/decidim/budgets/project_list_item/project_text.erb +0 -23
  159. data/app/cells/decidim/budgets/project_list_item/show.erb +0 -5
  160. data/app/cells/decidim/budgets/project_list_item_cell.rb +0 -70
  161. data/app/cells/decidim/budgets/project_m/data.erb +0 -12
  162. data/app/cells/decidim/budgets/project_m/footer.erb +0 -5
  163. data/app/cells/decidim/budgets/project_m_cell.rb +0 -22
  164. data/app/packs/stylesheets/decidim/budgets/_budgets.scss +0 -3
  165. data/app/packs/stylesheets/decidim/budgets/budget/_budget-list.scss +0 -198
  166. data/app/packs/stylesheets/decidim/budgets/budget/_budget-meter.scss +0 -83
  167. data/app/packs/stylesheets/decidim/budgets/budget/_progress.scss +0 -19
  168. data/app/views/decidim/budgets/admin/projects/proposals_picker.html.erb +0 -1
  169. data/app/views/decidim/budgets/projects/_filters.html.erb +0 -30
  170. data/app/views/decidim/budgets/projects/_filters_small_view.html.erb +0 -18
  171. data/app/views/decidim/budgets/projects/_order_progress.html.erb +0 -32
  172. data/app/views/decidim/budgets/projects/_order_selected_projects.html.erb +0 -27
  173. data/lib/decidim/budgets/seeds/city.jpeg +0 -0
@@ -7,8 +7,9 @@ module Decidim
7
7
  include FilterResource
8
8
  include NeedsCurrentOrder
9
9
  include Decidim::Budgets::Orderable
10
+ include Decidim::IconHelper
10
11
 
11
- helper_method :projects, :project, :budget, :all_geocoded_projects
12
+ helper_method :projects, :project, :budget, :all_geocoded_projects, :tabs, :panels
12
13
 
13
14
  def index
14
15
  raise ActionController::RoutingError, "Not Found" unless budget
@@ -41,15 +42,16 @@ module Decidim
41
42
  end
42
43
 
43
44
  def search_collection
44
- Project.where(budget: budget).includes([:scope, :component, :attachments, :category])
45
+ budget.projects.includes([:scope, :component, :attachments, :category]).with_order(filter_params[:addition_type] == "added" ? current_order : nil)
45
46
  end
46
47
 
47
48
  def default_filter_params
48
49
  {
49
50
  search_text_cont: "",
50
51
  with_any_status: default_filter_status_params,
51
- with_any_scope: default_filter_scope_params,
52
- with_any_category: default_filter_category_params
52
+ with_any_scope: nil,
53
+ with_any_category: nil,
54
+ addition_type: "all"
53
55
  }
54
56
  end
55
57
 
@@ -60,6 +62,51 @@ module Decidim
60
62
  def show_selected_budgets?
61
63
  voting_finished? && budget.projects.selected.any?
62
64
  end
65
+
66
+ def tabs
67
+ @tabs ||= items.map { |item| item.slice(:id, :text, :icon) }
68
+ end
69
+
70
+ def panels
71
+ @panels ||= items.map { |item| item.slice(:id, :method, :args) }
72
+ end
73
+
74
+ def items
75
+ @items ||= [
76
+ {
77
+ enabled: @project.linked_resources(:proposals, "included_proposals").present?,
78
+ id: "included_proposals",
79
+ text: t("decidim/proposals/proposal", scope: "activerecord.models", count: 2),
80
+ icon: resource_type_icon_key("Decidim::Budgets::Project"),
81
+ method: :cell,
82
+ args: ["decidim/linked_resources_for", @project, { type: :proposals, link_name: "included_proposals" }]
83
+ },
84
+ {
85
+ enabled: @project.linked_resources(:results, "included_projects").present?,
86
+ id: "included_results",
87
+ text: t("decidim/accountability/result", scope: "activerecord.models", count: 2),
88
+ icon: resource_type_icon_key("Decidim::Accountability::Result"),
89
+ method: :cell,
90
+ args: ["decidim/linked_resources_for", @project, { type: :results, link_name: "included_projects" }]
91
+ },
92
+ {
93
+ enabled: @project.photos.present?,
94
+ id: "images",
95
+ text: t("decidim.application.photos.photos"),
96
+ icon: resource_type_icon_key("images"),
97
+ method: :cell,
98
+ args: ["decidim/images_panel", @project]
99
+ },
100
+ {
101
+ enabled: @project.documents.present?,
102
+ id: "documents",
103
+ text: t("decidim.application.documents.documents"),
104
+ icon: resource_type_icon_key("documents"),
105
+ method: :cell,
106
+ args: ["decidim/documents_panel", @project]
107
+ }
108
+ ].select { |item| item[:enabled] }
109
+ end
63
110
  end
64
111
  end
65
112
  end
@@ -95,7 +95,7 @@ module Decidim
95
95
 
96
96
  private
97
97
 
98
- # This method will add an error to the `attachment` field only if there's
98
+ # This method will add an error to the `attachment` field only if there is
99
99
  # any error in any other field. This is needed because when the form has
100
100
  # an error, the attachment is lost, so we need a way to inform the user of
101
101
  # this problem.
@@ -19,6 +19,10 @@ module Decidim
19
19
  ]
20
20
  )
21
21
  end
22
+
23
+ def component_name
24
+ (defined?(current_component) && translated_attribute(current_component&.name).presence) || t("decidim.components.budgets.name")
25
+ end
22
26
  end
23
27
  end
24
28
  end
@@ -44,44 +44,61 @@ module Decidim
44
44
  current_order&.can_checkout?
45
45
  end
46
46
 
47
- def current_rule_explanation
48
- return unless current_order
47
+ # Returns false if the current order does not have a rule for minimum budget
48
+ # Returns false if the current order has not reached the minimum budget
49
+ # Otherwhise returns true
50
+ def current_order_minimum_reached?
51
+ return false if current_order.minimum_budget.zero?
49
52
 
50
- if current_order.projects_rule?
51
- if current_order.minimum_projects.positive? && current_order.minimum_projects < current_order.maximum_projects
52
- t(
53
- ".projects_rule.instruction",
54
- minimum_number: current_order.minimum_projects,
55
- maximum_number: current_order.maximum_projects
56
- )
57
- else
58
- t(".projects_rule_maximum_only.instruction", maximum_number: current_order.maximum_projects)
59
- end
60
- elsif current_order.minimum_projects_rule?
61
- t(".minimum_projects_rule.instruction", minimum_number: current_order.minimum_projects)
53
+ current_order.total > current_order.minimum_budget
54
+ end
55
+
56
+ def current_rule_call_for_action_text
57
+ return "" unless current_order
58
+
59
+ if current_order_minimum_reached?
60
+ t("minimum_reached", scope: "decidim.budgets.projects.order_progress.dynamic_help")
61
+ elsif current_order.projects.empty?
62
+ t("start_adding_projects", scope: "decidim.budgets.projects.order_progress.dynamic_help")
62
63
  else
63
- t(".vote_threshold_percent_rule.instruction", minimum_budget: budget_to_currency(current_order.minimum_budget))
64
+ t("keep_adding_projects", scope: "decidim.budgets.projects.order_progress.dynamic_help")
64
65
  end
65
66
  end
66
67
 
67
68
  def current_rule_description
68
69
  return unless current_order
69
70
 
70
- if current_order.projects_rule?
71
- if current_order.minimum_projects.positive? && current_order.minimum_projects < current_order.maximum_projects
72
- t(
73
- ".projects_rule.description",
74
- minimum_number: current_order.minimum_projects,
75
- maximum_number: current_order.maximum_projects
76
- )
77
- else
78
- t(".projects_rule_maximum_only.description", maximum_number: current_order.maximum_projects)
79
- end
80
- elsif current_order.minimum_projects_rule?
81
- t(".minimum_projects_rule.description", minimum_number: current_order.minimum_projects)
82
- else
83
- t(".vote_threshold_percent_rule.description", minimum_budget: budget_to_currency(current_order.minimum_budget))
84
- end
71
+ rule_text = if current_order_minimum_reached?
72
+ ""
73
+ elsif current_order.projects_rule?
74
+ if current_order.minimum_projects.positive? && current_order.minimum_projects < current_order.maximum_projects
75
+ t(
76
+ "projects_rule.description",
77
+ scope: "decidim.budgets.projects.order_progress",
78
+ minimum_number: current_order.minimum_projects,
79
+ maximum_number: current_order.maximum_projects
80
+ )
81
+ else
82
+ t(
83
+ "projects_rule_maximum_only.description",
84
+ scope: "decidim.budgets.projects.order_progress",
85
+ maximum_number: current_order.maximum_projects
86
+ )
87
+ end
88
+ elsif current_order.minimum_projects_rule?
89
+ t(
90
+ "minimum_projects_rule.description",
91
+ scope: "decidim.budgets.projects.order_progress",
92
+ minimum_number: current_order.minimum_projects
93
+ )
94
+ else
95
+ t(
96
+ "vote_threshold_percent_rule.description",
97
+ scope: "decidim.budgets.projects.order_progress",
98
+ minimum_budget: budget_to_currency(current_order.minimum_budget)
99
+ )
100
+ end
101
+ %(<strong>#{current_rule_call_for_action_text}</strong>. #{rule_text}).html_safe
85
102
  end
86
103
 
87
104
  # Serialize a collection of geocoded projects to be used by the dynamic map component
@@ -98,9 +115,8 @@ module Decidim
98
115
  .slice(:latitude, :longitude, :address)
99
116
  .merge(
100
117
  title: decidim_html_escape(translated_attribute(project.title)),
101
- description: html_truncate(decidim_sanitize_editor(translated_attribute(project.description)), length: 100),
102
- icon: icon("project", width: 40, height: 70, remove_icon_class: true),
103
- link: ::Decidim::ResourceLocatorPresenter.new([project.budget, project]).path
118
+ link: ::Decidim::ResourceLocatorPresenter.new([project.budget, project]).path,
119
+ items: cell("decidim/budgets/project_metadata", project).send(:project_items_for_map).to_json
104
120
  )
105
121
  end
106
122
 
@@ -109,6 +125,46 @@ module Decidim
109
125
 
110
126
  project.latitude.present? && project.longitude.present?
111
127
  end
128
+
129
+ def filter_addition_type_values(added_count:)
130
+ return [] if voting_finished?
131
+
132
+ [
133
+ ["all", { text: t("all", scope: "decidim.budgets.projects.project_filter"), count: nil }],
134
+ ["added", { text: t("added", scope: "decidim.budgets.projects.project_filter"), count: added_count }]
135
+ ]
136
+ end
137
+
138
+ def filter_sections
139
+ @filter_sections ||= begin
140
+ items = []
141
+ items.append(method: :with_any_status, collection: filter_status_values, label_scope: "decidim.budgets.projects.filters", id: "status") if voting_finished?
142
+ if current_component.has_subscopes?
143
+ items.append(method: :with_any_scope, collection: resource_filter_scope_values(budget.scope), label_scope: "decidim.budgets.projects.filters", id: "scope")
144
+ end
145
+ if current_participatory_space.categories.any?
146
+ items.append(method: :with_any_category, collection: filter_categories_values, label_scope: "decidim.budgets.projects.filters", id: "category")
147
+ end
148
+ end
149
+
150
+ items.reject { |item| item[:collection].blank? }
151
+ end
152
+
153
+ def budgets_select_tag(name, options: {})
154
+ select_tag(
155
+ name,
156
+ options_for_select(reference_budgets_for_select),
157
+ options.merge(include_blank: I18n.t("decidim.budgets.prompt"))
158
+ )
159
+ end
160
+
161
+ def reference_budgets_for_select
162
+ references = Budget.joins(:component)
163
+ .where(component: { participatory_space: current_participatory_space }).order(weight: :asc)
164
+ references.map do |budget|
165
+ ["#{"&nbsp;" * 4} #{translated_attribute(budget.title)}".html_safe, budget.id]
166
+ end
167
+ end
112
168
  end
113
169
  end
114
170
  end
@@ -8,7 +8,7 @@ module Decidim
8
8
  def perform(reminder)
9
9
  return if reminder.records.active.blank?
10
10
 
11
- ::Decidim::ReminderDelivery.create(reminder: reminder)
11
+ ::Decidim::ReminderDelivery.create(reminder:)
12
12
  ::Decidim::Budgets::VoteReminderMailer.vote_reminder(reminder).deliver_now
13
13
  end
14
14
  end
@@ -28,7 +28,7 @@ module Decidim
28
28
  budget_name: translated_attribute(@budget.title),
29
29
  space_name: translated_attribute(@space.title)
30
30
  )
31
- mail(to: user.email, subject: subject)
31
+ mail(to: user.email, subject:)
32
32
  end
33
33
  end
34
34
  end
@@ -25,7 +25,7 @@ module Decidim
25
25
  count: @orders.count
26
26
  )
27
27
 
28
- mail(to: @user.email, subject: subject)
28
+ mail(to: @user.email, subject:)
29
29
  end
30
30
  end
31
31
 
@@ -8,6 +8,7 @@ module Decidim
8
8
  include Decidim::ScopableResource
9
9
  include Decidim::HasComponent
10
10
  include Decidim::Searchable
11
+ include Decidim::Randomable
11
12
  include Traceable
12
13
  include Loggable
13
14
 
@@ -28,9 +28,17 @@ module Decidim
28
28
  has_many :orders, through: :line_items, foreign_key: "decidim_project_id", class_name: "Decidim::Budgets::Order"
29
29
 
30
30
  delegate :organization, :participatory_space, :can_participate_in_space?, to: :component
31
+ delegate :visible?, to: :budget
31
32
 
32
33
  alias can_participate? can_participate_in_space?
33
34
 
35
+ scope :with_order, lambda { |order|
36
+ if order.present?
37
+ joins(:orders).where(decidim_budgets_orders: { id: order.id })
38
+ else
39
+ all
40
+ end
41
+ }
34
42
  scope :selected, -> { where.not(selected_at: nil) }
35
43
  scope :not_selected, -> { where(selected_at: nil) }
36
44
 
@@ -38,13 +46,15 @@ module Decidim
38
46
 
39
47
  scope_search_multi :with_any_status, [:selected, :not_selected]
40
48
 
41
- searchable_fields(
42
- scope_id: :decidim_scope_id,
43
- participatory_space: { component: :participatory_space },
44
- A: :title,
45
- D: :description,
46
- datetime: :created_at
47
- )
49
+ searchable_fields({
50
+ scope_id: :decidim_scope_id,
51
+ participatory_space: { component: :participatory_space },
52
+ A: :title,
53
+ D: :description,
54
+ datetime: :created_at
55
+ },
56
+ index_on_create: ->(project) { project.visible? },
57
+ index_on_update: ->(project) { project.visible? })
48
58
 
49
59
  def self.ordered_ids(ids)
50
60
  # Make sure each ID in the matching text has a "," character as their
@@ -52,19 +62,23 @@ module Decidim
52
62
  # array. This is why we search for match ",2," instead to get the actual
53
63
  # position for ID 2.
54
64
  concat_ids = connection.quote(",#{ids.join(",")},")
55
- order(Arel.sql("position(concat(',', id::text, ',') in #{concat_ids})"))
65
+ order(Arel.sql("position(concat(',', decidim_budgets_projects.id::text, ',') in #{concat_ids})"))
56
66
  end
57
67
 
58
68
  def self.log_presenter_class_for(_log)
59
69
  Decidim::Budgets::AdminLog::ProjectPresenter
60
70
  end
61
71
 
72
+ def resource_locator
73
+ ::Decidim::ResourceLocatorPresenter.new([budget, self])
74
+ end
75
+
62
76
  def polymorphic_resource_path(url_params)
63
- ::Decidim::ResourceLocatorPresenter.new([budget, self]).path(url_params)
77
+ resource_locator.path(url_params)
64
78
  end
65
79
 
66
80
  def polymorphic_resource_url(url_params)
67
- ::Decidim::ResourceLocatorPresenter.new([budget, self]).url(url_params)
81
+ resource_locator.url(url_params)
68
82
  end
69
83
 
70
84
  # Public: Overrides the `comments_have_votes?` Commentable concern method.
@@ -4,3 +4,5 @@ import "src/decidim/budgets/exit_handler"
4
4
 
5
5
  // Images
6
6
  require.context("../images", true)
7
+
8
+ import "stylesheets/budgets.scss"
@@ -9,7 +9,7 @@ const isSafeUrl = (exitUrl) => {
9
9
  }
10
10
 
11
11
  const safeUrls = [
12
- $(".budget-summary").attr("data-safe-url").split("?")[0],
12
+ $(".budget-summary").attr("data-safe-url").replace(location.origin, ""),
13
13
  `${location.pathname}#`,
14
14
  `${location.href}#`,
15
15
  "#"
@@ -18,7 +18,7 @@ const isSafeUrl = (exitUrl) => {
18
18
  let safe = false;
19
19
  safeUrls.forEach((url) => {
20
20
  if (exitUrl.startsWith(url)) {
21
- safe = true
21
+ safe = true
22
22
  }
23
23
  });
24
24
 
@@ -36,10 +36,12 @@ const allowExitFrom = ($el) => {
36
36
  return true;
37
37
  } else if ($el.attr("id") === "exit-notification-link") {
38
38
  return true;
39
- } else if ($el.parents(".voting-wrapper").length > 0) {
39
+ } else if ($el.parents("main").length > 0) {
40
40
  return true;
41
41
  } else if (isSafeUrl($el.attr("href"))) {
42
42
  return true
43
+ } else if (document.querySelector(".panel-container") && document.querySelector(".panel-container").contains($el[0])) {
44
+ return true
43
45
  }
44
46
 
45
47
  return false;
@@ -50,6 +52,7 @@ $(() => {
50
52
  const $exitLink = $("#exit-notification-link");
51
53
  const defaultExitUrl = $exitLink.attr("href");
52
54
  const defaultExitLinkText = $exitLink.text();
55
+ const signOutPath = window.Decidim.config.get("sign_out_path");
53
56
  let exitLinkText = defaultExitLinkText;
54
57
 
55
58
  if ($exitNotification.length < 1) {
@@ -66,7 +69,7 @@ $(() => {
66
69
 
67
70
  $exitLink.attr("href", url);
68
71
  $exitLink.html(exitLinkText);
69
- $exitNotification.foundation("open");
72
+ window.Decidim.currentDialogs["exit-notification"].open();
70
73
  };
71
74
 
72
75
  $(document).on("click", "a", (event) => {
@@ -78,11 +81,11 @@ $(() => {
78
81
  openExitNotification($link.attr("href"), $link.data("method"));
79
82
  }
80
83
  });
81
- // Custom handling for the header sign out so that it won't trigger the
84
+ // Custom handling for the header sign out so that it will not trigger the
82
85
  // logout form submit and so that it changes the exit link text. This does
83
86
  // not trigger the document link click listener because it has the
84
87
  // data-method attribute to trigger a form submit event.
85
- $(".header a.sign-out-link").on("click", (event) => {
88
+ $(`[href='${signOutPath}']`).on("click", (event) => {
86
89
  event.preventDefault();
87
90
  event.stopPropagation();
88
91
 
@@ -93,7 +96,7 @@ $(() => {
93
96
  // Custom handling for the exit link which needs to change the exit link
94
97
  // text to the default text as this is not handled by the document click
95
98
  // listener.
96
- $("a[data-open='exit-notification']").on("click", () => {
99
+ $("a[data-dialog-open='exit-notification']").on("click", () => {
97
100
  exitLinkText = defaultExitLinkText;
98
101
  openExitNotification(defaultExitUrl);
99
102
  });
@@ -1,18 +1,32 @@
1
1
  $(() => {
2
2
  const checkProgressPosition = () => {
3
- let progressFix = document.querySelector("[data-progressbox-fixed]"),
4
- progressRef = document.querySelector("[data-progress-reference]"),
5
- progressVisibleClass = "is-progressbox-visible";
6
3
 
7
- if (!progressRef) {
8
- return;
9
- }
4
+ const progressRef = document.querySelectorAll("[data-progress-reference]");
5
+ if (progressRef.length) {
6
+ const progressFix = document.querySelectorAll("[data-progressbox-fixed]");
7
+
8
+ let selectedProgressRef = "";
9
+ let selectedProgressFix = "";
10
+ const progressVisibleClass = "is-progressbox-visible";
11
+
12
+ if (window.matchMedia("(min-width: 768px)").matches) {
13
+ selectedProgressRef = progressRef[1];
14
+ selectedProgressFix = progressFix[1];
15
+ } else {
16
+ selectedProgressRef = progressRef[0];
17
+ selectedProgressFix = progressFix[0];
18
+ }
19
+
20
+ if (!progressRef) {
21
+ return;
22
+ }
10
23
 
11
- let progressPosition = progressRef.getBoundingClientRect().bottom;
12
- if (progressPosition > 0) {
13
- progressFix.classList.remove(progressVisibleClass);
14
- } else {
15
- progressFix.classList.add(progressVisibleClass);
24
+ let progressPosition = selectedProgressRef.getBoundingClientRect().bottom;
25
+ if (progressPosition > 0) {
26
+ selectedProgressFix.classList.remove(progressVisibleClass);
27
+ } else {
28
+ selectedProgressFix.classList.add(progressVisibleClass);
29
+ }
16
30
  }
17
31
  }
18
32
 
@@ -1,13 +1,13 @@
1
1
  $(() => {
2
- const $projects = $("#projects, #project");
3
- const $budgetSummaryTotal = $(".budget-summary__total");
4
- const $budgetExceedModal = $("#budget-excess");
2
+ const $projects = $("#projects, #project-item");
3
+ const $budgetSummaryTotal = $(".budget-summary__progressbar-marks_right");
4
+ const selectBudgetSummaryTotal = $budgetSummaryTotal.data("totalAllocation");
5
5
  const $budgetSummary = $(".budget-summary__progressbox");
6
6
  const $voteButton = $(".budget-vote-button");
7
- const totalAllocation = parseInt($budgetSummaryTotal.attr("data-total-allocation"), 10);
7
+ const totalAllocation = parseInt(selectBudgetSummaryTotal, 10);
8
+ const additionSelectorButtons = document.querySelectorAll(".budget__list--header .button__pill")
8
9
 
9
10
  const cancelEvent = (event) => {
10
- $(event.currentTarget).removeClass("loading-spinner");
11
11
  event.stopPropagation();
12
12
  event.preventDefault();
13
13
  };
@@ -21,15 +21,20 @@ $(() => {
21
21
  const $currentTarget = $(event.currentTarget);
22
22
  const projectAllocation = parseInt($currentTarget.attr("data-allocation"), 10);
23
23
 
24
- if (!$currentTarget.attr("data-open")) {
25
- $currentTarget.addClass("loading-spinner");
26
- }
27
-
28
24
  if ($currentTarget.attr("disabled")) {
29
25
  cancelEvent(event);
30
26
  } else if (($currentTarget.attr("data-add") === "true") && ((currentAllocation + projectAllocation) > totalAllocation)) {
31
- $budgetExceedModal.foundation("toggle");
27
+ window.Decidim.currentDialogs["budget-excess"].toggle()
32
28
  cancelEvent(event);
33
29
  }
34
30
  });
31
+
32
+ additionSelectorButtons.forEach(function(button) {
33
+ button.addEventListener("click", function(event) {
34
+ additionSelectorButtons.forEach(function(element) {
35
+ element.classList.remove("button__pill--active")
36
+ })
37
+ event.currentTarget.classList.add("button__pill--active")
38
+ })
39
+ });
35
40
  });