decidim-budgets 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +23 -0
  3. data/Rakefile +2 -0
  4. data/app/assets/config/decidim_budgets_manifest.js +1 -0
  5. data/app/assets/images/decidim/budgets/icon.svg +4 -0
  6. data/app/assets/javascripts/decidim/budgets/projects.js.es6 +28 -0
  7. data/app/assets/stylesheets/decidim/budgets/_budgets.scss +1 -0
  8. data/app/assets/stylesheets/decidim/budgets/budget/_budget-list.scss +32 -0
  9. data/app/assets/stylesheets/decidim/budgets/budget/_budget-meter.scss +78 -0
  10. data/app/assets/stylesheets/decidim/budgets/budget/_progress.scss +17 -0
  11. data/app/commands/decidim/budgets/add_line_item.rb +43 -0
  12. data/app/commands/decidim/budgets/admin/create_project.rb +52 -0
  13. data/app/commands/decidim/budgets/admin/update_project.rb +56 -0
  14. data/app/commands/decidim/budgets/cancel_order.rb +36 -0
  15. data/app/commands/decidim/budgets/checkout.rb +34 -0
  16. data/app/commands/decidim/budgets/remove_line_item.rb +35 -0
  17. data/app/controllers/concerns/decidim/budgets/needs_current_order.rb +27 -0
  18. data/app/controllers/decidim/budgets/admin/application_controller.rb +14 -0
  19. data/app/controllers/decidim/budgets/admin/projects_controller.rb +69 -0
  20. data/app/controllers/decidim/budgets/application_controller.rb +13 -0
  21. data/app/controllers/decidim/budgets/line_items_controller.rb +43 -0
  22. data/app/controllers/decidim/budgets/orders_controller.rb +38 -0
  23. data/app/controllers/decidim/budgets/projects_controller.rb +44 -0
  24. data/app/forms/decidim/budgets/admin/project_form.rb +44 -0
  25. data/app/helpers/decidim/budgets/application_helper.rb +12 -0
  26. data/app/helpers/decidim/budgets/projects_helper.rb +29 -0
  27. data/app/models/decidim/budgets/application_record.rb +9 -0
  28. data/app/models/decidim/budgets/line_item.rb +20 -0
  29. data/app/models/decidim/budgets/order.rb +52 -0
  30. data/app/models/decidim/budgets/project.rb +15 -0
  31. data/app/services/decidim/budgets/project_search.rb +58 -0
  32. data/app/views/decidim/budgets/admin/projects/_form.html.erb +31 -0
  33. data/app/views/decidim/budgets/admin/projects/edit.html.erb +9 -0
  34. data/app/views/decidim/budgets/admin/projects/index.html.erb +27 -0
  35. data/app/views/decidim/budgets/admin/projects/new.html.erb +9 -0
  36. data/app/views/decidim/budgets/line_items/update_budget.js.erb +21 -0
  37. data/app/views/decidim/budgets/projects/_budget_confirm.html.erb +30 -0
  38. data/app/views/decidim/budgets/projects/_budget_excess.html.erb +14 -0
  39. data/app/views/decidim/budgets/projects/_budget_summary.html.erb +46 -0
  40. data/app/views/decidim/budgets/projects/_count.html.erb +1 -0
  41. data/app/views/decidim/budgets/projects/_filters.html.erb +24 -0
  42. data/app/views/decidim/budgets/projects/_linked_projects.html.erb +12 -0
  43. data/app/views/decidim/budgets/projects/_order_progress.html.erb +34 -0
  44. data/app/views/decidim/budgets/projects/_order_selected_projects.html.erb +25 -0
  45. data/app/views/decidim/budgets/projects/_order_total_budget.html.erb +1 -0
  46. data/app/views/decidim/budgets/projects/_project.html.erb +40 -0
  47. data/app/views/decidim/budgets/projects/_project_budget_button.html.erb +9 -0
  48. data/app/views/decidim/budgets/projects/_projects.html.erb +8 -0
  49. data/app/views/decidim/budgets/projects/_tags.html.erb +10 -0
  50. data/app/views/decidim/budgets/projects/index.html.erb +26 -0
  51. data/app/views/decidim/budgets/projects/index.js.erb +2 -0
  52. data/app/views/decidim/budgets/projects/show.html.erb +48 -0
  53. data/config/i18n-tasks.yml +4 -0
  54. data/config/locales/ca.yml +84 -0
  55. data/config/locales/en.yml +95 -0
  56. data/config/locales/es.yml +84 -0
  57. data/db/migrate/20170127114122_create_projects.rb +15 -0
  58. data/db/migrate/20170130095615_create_orders.rb +13 -0
  59. data/db/migrate/20170130101825_create_line_items.rb +10 -0
  60. data/lib/decidim/budgets/admin.rb +9 -0
  61. data/lib/decidim/budgets/admin_engine.rb +22 -0
  62. data/lib/decidim/budgets/feature.rb +59 -0
  63. data/lib/decidim/budgets/list_engine.rb +30 -0
  64. data/lib/decidim/budgets/test/factories.rb +43 -0
  65. data/lib/decidim/budgets.rb +11 -0
  66. metadata +210 -0
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Budgets
5
+ # Exposes the project resource so users can view them
6
+ class ProjectsController < Decidim::Budgets::ApplicationController
7
+ include FilterResource
8
+ include NeedsCurrentOrder
9
+
10
+ helper_method :projects, :random_seed, :project
11
+
12
+ private
13
+
14
+ def projects
15
+ @projects ||= search.results.page(params[:page]).per(12)
16
+ end
17
+
18
+ def random_seed
19
+ @random_seed ||= search.random_seed
20
+ end
21
+
22
+ def project
23
+ @project ||= projects.find(params[:id])
24
+ end
25
+
26
+ def search_klass
27
+ ProjectSearch
28
+ end
29
+
30
+ def default_filter_params
31
+ {
32
+ search_text: "",
33
+ scope_id: "",
34
+ category_id: "",
35
+ random_seed: params[:random_seed]
36
+ }
37
+ end
38
+
39
+ def context_params
40
+ { feature: current_feature, organization: current_organization }
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ module Budgets
4
+ module Admin
5
+ # This class holds a Form to create/update projects from Decidim's admin panel.
6
+ class ProjectForm < Decidim::Form
7
+ include TranslatableAttributes
8
+ include TranslationsHelper
9
+
10
+ translatable_attribute :title, String
11
+ translatable_attribute :short_description, String
12
+ translatable_attribute :description, String
13
+ attribute :budget, Integer
14
+ attribute :decidim_scope_id, Integer
15
+ attribute :decidim_category_id, Integer
16
+ attribute :proposal_ids, Array[Integer]
17
+
18
+ validates :title, translatable_presence: true
19
+ validates :short_description, translatable_presence: true
20
+ validates :description, translatable_presence: true
21
+ validates :budget, presence: true, numericality: { greater_than: 0 }
22
+
23
+ validates :scope, presence: true, if: ->(form) { form.decidim_scope_id.present? }
24
+ validates :category, presence: true, if: ->(form) { form.decidim_category_id.present? }
25
+
26
+ def map_model(model)
27
+ self.proposal_ids = model.linked_resources(:proposals, "included_proposals").pluck(:id)
28
+ end
29
+
30
+ def proposals
31
+ @proposals ||= Decidim.find_resource_manifest(:proposals).try(:resource_scope, context.current_feature)&.order(title: :asc)&.pluck(:title, :id)
32
+ end
33
+
34
+ def scope
35
+ @scope ||= context.current_feature.scopes.where(id: decidim_scope_id).first
36
+ end
37
+
38
+ def category
39
+ @category ||= context.current_feature.categories.where(id: decidim_category_id).first
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ module Budgets
4
+ # Custom helpers, scoped to the budgets engine.
5
+ #
6
+ module ApplicationHelper
7
+ include PaginateHelper
8
+ include Decidim::Comments::CommentsHelper
9
+ include ProjectsHelper
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ module Budgets
4
+ # A helper to render order and budgets actions
5
+ module ProjectsHelper
6
+ # Render a budget as a currency
7
+ #
8
+ # budget - A integer to represent a budget
9
+ def budget_to_currency(budget)
10
+ number_to_currency budget, unit: Decidim.currency_unit, precision: 0
11
+ end
12
+
13
+ # Return a percentage of the current order budget from the total budget
14
+ def current_order_budget_percent
15
+ current_order&.budget_percent.to_f.floor
16
+ end
17
+
18
+ # Return true if the current order is checked out
19
+ def current_order_checked_out?
20
+ current_order&.checked_out?
21
+ end
22
+
23
+ # Return true if the user can continue to the checkout process
24
+ def current_order_can_be_checked_out?
25
+ current_order&.can_checkout?
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ module Budgets
4
+ # Abstract class from which all models in this engine inherit.
5
+ class ApplicationRecord < ActiveRecord::Base
6
+ self.abstract_class = true
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ module Budgets
4
+ # The data store for a LineItem in the Decidim::Budgets component. It describes an
5
+ # association between an order and a project.
6
+ class LineItem < Budgets::ApplicationRecord
7
+ belongs_to :order, class_name: Decidim::Budgets::Order, foreign_key: "decidim_order_id"
8
+ belongs_to :project, class_name: Decidim::Budgets::Project, foreign_key: "decidim_project_id"
9
+
10
+ validates :order, presence: true, uniqueness: { scope: :project }
11
+ validates :project, presence: true
12
+ validate :same_feature
13
+
14
+ def same_feature
15
+ return unless order && project
16
+ errors.add(:order, :invalid) unless order.feature == project.feature
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ module Budgets
4
+ # The data store for a Order in the Decidim::Budgets component. It is unique for each
5
+ # user and feature and contains a collection of projects
6
+ class Order < Budgets::ApplicationRecord
7
+ include Decidim::HasFeature
8
+
9
+ feature_manifest_name "budgets"
10
+
11
+ belongs_to :user, class_name: Decidim::User, foreign_key: "decidim_user_id"
12
+
13
+ has_many :projects, through: :line_items, class_name: Decidim::Budgets::Project, foreign_key: "decidim_project_id"
14
+ has_many :line_items, class_name: Decidim::Budgets::LineItem, foreign_key: "decidim_order_id", dependent: :destroy
15
+
16
+ validates :user, presence: true, uniqueness: { scope: :feature }
17
+ validate :user_belongs_to_organization
18
+
19
+ # Public: Returns the sum of project budgets
20
+ def total_budget
21
+ @total_budget ||= projects.sum(&:budget)
22
+ end
23
+
24
+ # Public: Returns true if the order has been checked out
25
+ def checked_out?
26
+ checked_out_at.present?
27
+ end
28
+
29
+ # Public: Check if the order total budget is enough to checkout
30
+ def can_checkout?
31
+ total_budget.to_f >= minimum_budget
32
+ end
33
+
34
+ # Public: Returns the order budget percent from the settings total budget
35
+ def budget_percent
36
+ (total_budget.to_f / feature.settings.total_budget.to_f) * 100
37
+ end
38
+
39
+ # Public: Returns the required minimum budget to checkout
40
+ def minimum_budget
41
+ feature.settings.total_budget.to_f * (feature.settings.vote_threshold_percent.to_f / 100)
42
+ end
43
+
44
+ private
45
+
46
+ def user_belongs_to_organization
47
+ return if !user || !organization
48
+ errors.add(:user, :invalid) unless user.organization == organization
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ module Budgets
4
+ # The data store for a Project in the Decidim::Budgets component. It stores a
5
+ # title, description and any other useful information to render a custom project.
6
+ class Project < Budgets::ApplicationRecord
7
+ include Decidim::Resourceable
8
+ include Decidim::HasFeature
9
+ include Decidim::HasScope
10
+ include Decidim::HasCategory
11
+
12
+ feature_manifest_name "budgets"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ module Budgets
4
+ # This class handles search and filtering of projects. Needs a
5
+ # `current_feature` param with a `Decidim::Feature` in order to
6
+ # find the projects.
7
+ class ProjectSearch < ResourceSearch
8
+ # Public: Initializes the service.
9
+ # feature - A Decidim::Feature to get the projects from.
10
+ def initialize(options = {})
11
+ super(Project.all, options)
12
+ @random_seed = options[:random_seed].to_f
13
+ end
14
+
15
+ # Handle the search_text filter
16
+ def search_search_text
17
+ query
18
+ .where(localized_search_text_in(:title), text: "%#{search_text}%")
19
+ .or(query.where(localized_search_text_in(:description), text: "%#{search_text}%"))
20
+ .or(query.where(localized_search_text_in(:short_description), text: "%#{search_text}%"))
21
+ end
22
+
23
+ # Handle the scope_id filter
24
+ def search_scope_id
25
+ query.where(decidim_scope_id: scope_id)
26
+ end
27
+
28
+ # Returns the random projects for the current page.
29
+ def results
30
+ @projects ||= Project.transaction do
31
+ Project.connection.execute("SELECT setseed(#{Project.connection.quote(random_seed)})")
32
+ super.reorder("RANDOM()").load
33
+ end
34
+ end
35
+
36
+ # Returns the random seed used to randomize the proposals.
37
+ def random_seed
38
+ @random_seed = (rand * 2 - 1) if @random_seed == 0.0 || @random_seed > 1 || @random_seed < -1
39
+ @random_seed
40
+ end
41
+
42
+ private
43
+
44
+ # Internal: builds the needed query to search for a text in the organization's
45
+ # available locales. Note that it is intended to be used as follows:
46
+ #
47
+ # Example:
48
+ # Resource.where(localized_search_text_for(:title, text: "my_query"))
49
+ #
50
+ # The Hash with the `:text` key is required or it won't work.
51
+ def localized_search_text_in(field)
52
+ options[:organization].available_locales.map do |l|
53
+ "#{field} ->> '#{l}' ILIKE :text"
54
+ end.join(" OR ")
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,31 @@
1
+ <div class="field" >
2
+ <%= form.translated :text_field, :title, autofocus: true %>
3
+ </div>
4
+
5
+ <div class="field" >
6
+ <%= form.translated :editor, :short_description %>
7
+ </div>
8
+
9
+ <div class="field" >
10
+ <%= form.translated :editor, :description %>
11
+ </div>
12
+
13
+ <div class="field" >
14
+ <%= form.number_field :budget %>
15
+ </div>
16
+
17
+ <div class="field" >
18
+ <%= form.collection_select :decidim_scope_id, current_organization.scopes, :id, :name, include_blank: true %>
19
+ </div>
20
+
21
+ <div class="field" >
22
+ <%= form.categories_select :decidim_category_id, current_participatory_process.categories, include_blank: true, disable_parents: false %>
23
+ </div>
24
+
25
+ <% if @form.proposals %>
26
+ <%= form.select :proposal_ids,
27
+ @form.proposals,
28
+ {},
29
+ { multiple: true, class: "chosen-select" }
30
+ %>
31
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <h3><%= t ".title" %></h3>
2
+
3
+ <%= form_for(@form) do |f| %>
4
+ <%= render partial: 'form', object: f %>
5
+
6
+ <div class="actions">
7
+ <%= f.submit t(".update") %>
8
+ </div>
9
+ <% end %>
@@ -0,0 +1,27 @@
1
+ <h2><%= t(".title") %></h2>
2
+
3
+ <div class="actions title">
4
+ <%= link_to t("actions.new", scope: "decidim.budgets", name: t("models.project.name", scope: "decidim.budgets.admin")), new_project_path, class: 'new' if can? :manage, current_feature %>
5
+ </div>
6
+
7
+ <table class="stack">
8
+ <thead>
9
+ <tr>
10
+ <th><%= t("models.project.fields.title", scope: "decidim.budgets") %></th>
11
+ <th class="actions"><%= t("actions.title", scope: "decidim.budgets") %></th>
12
+ </tr>
13
+ </thead>
14
+ <tbody>
15
+ <% projects.each do |project| %>
16
+ <tr data-id="<%= project.id %>">
17
+ <td>
18
+ <%= link_to translated_attribute(project.title), decidim_budgets.project_path(id: project, feature_id: current_feature, participatory_process_id: current_participatory_process), target: :blank %><br />
19
+ </td>
20
+ <td class="actions">
21
+ <%= link_to t("actions.edit", scope: "decidim.budgets"), edit_project_path(project) if can? :update, current_feature %>
22
+ <%= link_to t("actions.destroy", scope: "decidim.budgets"), project_path(project), method: :delete, class: "small alert button", data: { confirm: t("actions.confirm_destroy", scope: "decidim.budgets") } if can? :destroy, current_feature %>
23
+ </td>
24
+ </tr>
25
+ <% end %>
26
+ </tbody>
27
+ </table>
@@ -0,0 +1,9 @@
1
+ <h3><%= t ".title" %></h3>
2
+
3
+ <%= form_for(@form) do |f| %>
4
+ <%= render partial: 'form', object: f %>
5
+
6
+ <div class="actions">
7
+ <%= f.submit t(".create") %>
8
+ </div>
9
+ <% end %>
@@ -0,0 +1,21 @@
1
+ var $orderTotalBudget = $('#order-total-budget');
2
+ var $orderSelectedProjects = $('#order-selected-projects');
3
+ var $orderProgress = $('#order-progress');
4
+ var $projectItem = $('#project-<%= project.id %>-item');
5
+ var $projectBudgetButton = $('#project-<%= project.id %>-budget-button');
6
+ var $budgetConfirm = $('#budget-confirm');
7
+
8
+ $orderTotalBudget.html('<%= j(render partial: 'decidim/budgets/projects/order_total_budget') %>');
9
+ $orderSelectedProjects.html('<%= j(render partial: 'decidim/budgets/projects/order_selected_projects') %>');
10
+ $orderProgress.html('<%= j(render partial: 'decidim/budgets/projects/order_progress') %>');
11
+ $budgetConfirm.html('<%= j(render partial: 'decidim/budgets/projects/budget_confirm') %>')
12
+
13
+ $(document).foundation();
14
+
15
+ if ($projectItem.length > 0) {
16
+ $projectItem.html('<%= j(render partial: 'decidim/budgets/projects/project', locals: { project: project }) %>');
17
+ }
18
+
19
+ if ($projectBudgetButton.length > 0) {
20
+ $projectBudgetButton.html('<%= j(render partial: 'decidim/budgets/projects/project_budget_button', locals: { project: project }) %>');
21
+ }
@@ -0,0 +1,30 @@
1
+ <% if current_order.present? %>
2
+ <div class="reveal__header">
3
+ <h3 class="reveal__title"><%= t('.title') %></h3>
4
+ <button class="close-button" data-close aria-label="<%= t('.cancel') %>" type="button">
5
+ <span aria-hidden="true">&times;</span>
6
+ </button>
7
+ </div>
8
+ <p><%= t('.description') %></p>
9
+ <div class="card card--secondary">
10
+ <ul class="card__content">
11
+ <% current_order.projects.each do |project| %>
12
+ <li class="budget-summary__selected-item">
13
+ <%= link_to translated_attribute(project.title), project %>
14
+ <strong class="budget-summary__selected-number">
15
+ <%= budget_to_currency project.budget %>
16
+ </strong>
17
+ </li>
18
+ <% end %>
19
+ </ul>
20
+ </div>
21
+ <p class="text-center"><%= t('.are_you_sure') %></p>
22
+ <div class="row">
23
+ <div class="columns medium-8 medium-offset-2">
24
+ <%= button_to t('.confirm'), checkout_order_path, class: "button expanded" %>
25
+ </div>
26
+ </div>
27
+ <div class="text-center">
28
+ <button class="link" data-close><%= t('.cancel') %></button>
29
+ </div>
30
+ <% end %>
@@ -0,0 +1,14 @@
1
+ <div class="reveal" data-reveal id="budget-excess">
2
+ <div class="reveal__header">
3
+ <h3 class="reveal__title"><%= t('.title') %></h3>
4
+ <button class="close-button" data-close aria-label="<%= t('.close') %>" type="button">
5
+ <span aria-hidden="true">&times;</span>
6
+ </button>
7
+ </div>
8
+ <p><%= t('.description') %></p>
9
+ <div class="row">
10
+ <div class="columns medium-8 medium-offset-2">
11
+ <button data-close class="button expanded"><%= t('.ok') %></button>
12
+ </div>
13
+ </div>
14
+ </div>
@@ -0,0 +1,46 @@
1
+ <div class="card budget-summary" data-progress-reference>
2
+ <div class="card__content">
3
+ <% if include_heading %>
4
+ <% if current_order_checked_out? %>
5
+ <h3 class="heading3"><%= t('.checked_out.title') %></h3>
6
+ <p>
7
+ <%= raw t('.checked_out.description', cancel_link: link_to(t('.cancel_order'), order_path, method: :delete, class: 'cancel-order', data: { confirm: t('.are_you_sure') })) %>
8
+ </p>
9
+ <% else %>
10
+ <h3 class="heading3"><%= t('.title') %></h3>
11
+ <p><%= t('.description', minimum_budget: budget_to_currency(current_order&.minimum_budget)) %></p>
12
+ <% end %>
13
+ <% end %>
14
+
15
+ <div class="budget-summary__total" data-total-budget="<%= feature_settings.total_budget %>">
16
+ <span class="mini-title"><%= t('total_budget') %>
17
+ <strong class="mini-title__strong mini-title__strong--highlight">
18
+ <%= budget_to_currency(feature_settings.total_budget) %>
19
+ </strong>
20
+ </span>
21
+ </div>
22
+
23
+ <div id="order-progress">
24
+ <%= render partial: 'order_progress' %>
25
+ </div>
26
+
27
+ <div>
28
+ <span class="mini-title">
29
+ <%= t('.assigned') %>
30
+ <strong id="order-total-budget" class="mini-title__strong">
31
+ <%= render partial: 'order_total_budget' %>
32
+ </strong>
33
+ </span>
34
+ </div>
35
+ </div>
36
+
37
+ <div id="order-selected-projects">
38
+ <%= render partial: 'order_selected_projects' %>
39
+ </div>
40
+ </div>
41
+
42
+ <%= render partial: "budget_excess" %>
43
+
44
+ <div class="reveal" data-reveal id="budget-confirm">
45
+ <%= render partial: "budget_confirm" %>
46
+ </div>
@@ -0,0 +1 @@
1
+ <%= t(".projects_count", count: projects.total_count) %>
@@ -0,0 +1,24 @@
1
+ <%= filter_form_for filter do |form| %>
2
+ <div class="filters__section">
3
+ <div class="filters__search">
4
+ <div class="input-group">
5
+ <%= form.search_field :search_text, label: false, class: "input-group-field", placeholder: t('.search') %>
6
+ <div class="input-group-button">
7
+ <button type="submit" class="button button--muted">
8
+ <%= icon "magnifying-glass", aria_label: t('.search') %>
9
+ </button>
10
+ </div>
11
+ </div>
12
+ </div>
13
+ </div>
14
+
15
+ <% if current_organization.scopes.any? %>
16
+ <%= form.collection_check_boxes :scope_id, current_organization.scopes, lambda {|scope| scope.id.to_s}, :name, legend_title: t('.scopes') %>
17
+ <% end %>
18
+
19
+ <% if current_feature.categories.any? %>
20
+ <%= form.categories_select :category_id, current_feature.categories, legend_title: t('.category'), disable_parents: false, label: false, include_blank: true %>
21
+ <% end %>
22
+
23
+ <%= form.hidden_field :random_seed %>
24
+ <% end %>
@@ -0,0 +1,12 @@
1
+ <div class="card card--action card--list">
2
+ <% resources.each do |project| %>
3
+ <div class="card--list__item">
4
+ <%= icon "actions", class: "card--list__icon", remove_icon_class: true %>
5
+ <%= link_to decidim_resource_path(project), class: "card--list__text card__link card__link--block" do %>
6
+ <h5 class="card--list__heading">
7
+ <%= translated_attribute(project.title) %>
8
+ </h5>
9
+ <% end %>
10
+ </div>
11
+ <% end %>
12
+ </div>
@@ -0,0 +1,34 @@
1
+ <div class="budget-summary__progressbox" data-current-budget="<%= current_order ? current_order.total_budget : 0 %>">
2
+ <div class="progress budget-progress" role="progressbar" tabindex="0" aria-valuenow="<%= current_order_budget_percent %>" aria-valuemin="<%= feature_settings.vote_threshold_percent %>" aria-valuetext="<%= current_order_budget_percent %>%" aria-valuemax="100">
3
+ <div class="progress-meter progress-meter--minimum" style="width: <%= 100 - current_order_budget_percent %>%"></div>
4
+ <!--Change width and text dynamically.-->
5
+ <div class="progress-meter budget-progress__meter" style="width: <%= current_order_budget_percent %>%">
6
+ <p class="progress-meter-text progress-meter-text--right"><%= current_order_budget_percent %>%</p>
7
+ </div>
8
+ </div>
9
+ <% unless current_order_checked_out? %>
10
+ <% if current_order_can_be_checked_out? %>
11
+ <button class="button small button--sc" data-toggle="budget-confirm"><%= t('.vote') %></button>
12
+ <% else %>
13
+ <button class="button small button--sc" data-toggle="budget-confirm" disabled><%= t('.vote') %></button>
14
+ <% end %>
15
+ <% end %>
16
+ </div>
17
+
18
+ <div class="progressbox-fixed-wrapper" data-progressbox-fixed>
19
+ <div class="budget-summary__progressbox budget-summary__progressbox--fixed">
20
+ <div class="progress budget-progress budget-progress--fixed" role="progressbar" tabindex="0" aria-valuenow="<%= current_order_budget_percent %>" aria-valuemin="<%= feature_settings.vote_threshold_percent %>" aria-valuetext="<%= current_order_budget_percent %>%" aria-valuemax="100">
21
+ <div class="progress-meter progress-meter--minimum" style="width: <%= 100 - current_order_budget_percent %>%"></div>
22
+ <div class="progress-meter budget-progress__meter" style="width: <%= current_order_budget_percent %>%">
23
+ <p class="progress-meter-text progress-meter-text--right"><%= current_order_budget_percent %>%</p>
24
+ </div>
25
+ </div>
26
+ <% unless current_order_checked_out? %>
27
+ <% if current_order_can_be_checked_out? %>
28
+ <button class="button small button--sc" data-toggle="budget-confirm"><%= t('.vote') %></button>
29
+ <% else %>
30
+ <button class="button small button--sc" data-toggle="budget-confirm" disabled><%= t('.vote') %></button>
31
+ <% end %>
32
+ <% end %>
33
+ </div>
34
+ </div>
@@ -0,0 +1,25 @@
1
+ <% if current_order&.projects&.any? %>
2
+ <div class="card__content budget-summary__selected">
3
+ <button data-toggle="reveal-selected">
4
+ <strong><%= current_order.projects.size %> </strong><%= t('.selected_projects', count: current_order.projects.size) %>
5
+ <%= icon("caret-bottom", class:"icon--small", aria_label: t('.view'), role: "img") %>
6
+ </button>
7
+ <div id="reveal-selected" class="hide" data-toggler=".hide">
8
+ <ul class="budget-summary__selected-list">
9
+ <% current_order.projects.each do |project| %>
10
+ <li class="budget-summary__selected-item">
11
+ <%= link_to translated_attribute(project.title), project %>
12
+ <strong class="budget-summary__selected-number">
13
+ <%= budget_to_currency project.budget %>
14
+ </strong>
15
+ <% unless current_order_checked_out? %>
16
+ <%= button_to order_line_item_path(project_id: project), method: :delete, remote: true, data: { disable: true }, form: { style: "display: inline" } do %>
17
+ <%= icon("trash", aria_label: t('.remove'), role: "img") %>
18
+ <% end %>
19
+ <% end %>
20
+ </li>
21
+ <% end %>
22
+ </ul>
23
+ </div>
24
+ </div>
25
+ <% end %>
@@ -0,0 +1 @@
1
+ <%= budget_to_currency current_order&.total_budget.to_f %>
@@ -0,0 +1,40 @@
1
+ <div class="card--list__text">
2
+ <div>
3
+ <%= link_to project, class: "card__link" do %>
4
+ <h5 class="card__title budget-list__title">
5
+ <%= translated_attribute project.title %>
6
+ </h5>
7
+ <% end %>
8
+ <%= render partial: "decidim/budgets/projects/tags", locals: { project: project } %>
9
+ </div>
10
+ </div>
11
+ <% if current_user.present? %>
12
+ <% if current_order && current_order.projects.include?(project) %>
13
+ <div class="card--list__data budget-list__data budget-list__data--added">
14
+ <span class="card--list__data__number budget-list__number">
15
+ <%= budget_to_currency(project.budget) %>
16
+ </span>
17
+ <%= button_to order_line_item_path(project_id: project), method: :delete, remote: true, data: { disable: true, budget: project.budget }, disabled: current_order_checked_out?, class: "button tiny budget--list__action success" do %>
18
+ <%= icon("check", class: "icon--small", aria_label: t('.remove'), role: "img") %>
19
+ <% end %>
20
+ </div>
21
+ <% else %>
22
+ <div class="card--list__data budget-list__data">
23
+ <span class="card--list__data__number budget-list__number">
24
+ <%= budget_to_currency(project.budget) %>
25
+ </span>
26
+ <%= button_to order_line_item_path(project_id: project), method: :post, remote: true, data: { disable: true, budget: project.budget, add: true }, disabled: current_order_checked_out?, class: "button tiny hollow budget--list__action" do %>
27
+ <%= icon("check", class: "icon--small", aria_label: t('.add'), role: "img") %>
28
+ <% end %>
29
+ </div>
30
+ <% end %>
31
+ <% else %>
32
+ <div class="card--list__data budget-list__data">
33
+ <span class="card--list__data__number budget-list__number">
34
+ <%= budget_to_currency(project.budget) %>
35
+ </span>
36
+ <a href="#" class="button tiny hollow budget--list__action disabled" data-toggle="loginModal">
37
+ <%= icon("check", class: "icon--small", aria_label: t('.add'), role: "img") %>
38
+ </a>
39
+ </div>
40
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <% if current_user.present? %>
2
+ <% if current_order && current_order.projects.include?(project) %>
3
+ <%= button_to t('.added'), order_line_item_path(project_id: project), method: :delete, remote: true, data: { disable: true, budget: project.budget }, disabled: current_order_checked_out?, class: "button expanded button--sc success budget--list__action" %>
4
+ <% else %>
5
+ <%= button_to t('.add'), order_line_item_path(project_id: project), method: :post, remote: true, data: { disable: true, budget: project.budget, add: true }, disabled: current_order_checked_out?, class: "button expanded button--sc budget--list__action" %>
6
+ <% end %>
7
+ <% else %>
8
+ <button class="button expanded button--sc disabled" data-toggle="loginModal"><%= t('.add') %></button>
9
+ <% end %>