From 4b2ef07d4ea450281f3b14345269f3beefa5a9be Mon Sep 17 00:00:00 2001 From: Antti Hukkanen Date: Tue, 16 Jan 2024 15:28:30 +0200 Subject: [PATCH] New voting layout --- .../admin_create_budget_extensions.rb | 4 +- .../admin_update_budget_extensions.rb | 4 +- .../budgeting_pipeline/authorizable.rb | 31 +++++ .../line_items_controller_extensions.rb | 4 + .../projects_controller_extensions.rb | 8 +- .../decidim/budgets/votes_controller.rb | 53 ++++---- .../admin_budget_form_extensions.rb | 6 + .../projects_helper_extensions.rb | 11 ++ .../authorization_helper.rb | 52 ++++++++ app/helpers/decidim/budgets/votes_helper.rb | 81 +++--------- .../budgeting_pipeline/budget_extensions.rb | 18 +++ .../budgeting_pipeline/project_extensions.rb | 4 + .../decidim/budgeting_pipeline/projects.js | 53 +++++--- .../budgeting_pipeline/project_search.rb | 18 +-- .../decidim/budgets/budget_image_uploader.rb | 16 +++ .../budgets/admin/budgets/_form.html.erb | 4 + .../line_items/_error_message.html.erb | 8 -- .../budgets/line_items/update_budget.js.erb | 58 ++++----- .../line_items/update_budget_error.js.erb | 5 + .../budgets/orders/_orders_info.html.erb | 62 +++++----- .../decidim/budgets/orders/index.html.erb | 28 +++-- .../budgets/projects/_filters.html.erb | 107 ++++++---------- .../budgets/projects/_project.html.erb | 6 +- .../projects/_project_budget_button.html.erb | 6 +- .../decidim/budgets/projects/index.html.erb | 26 +++- .../results/_vote_finished_modal.html.erb | 22 ++-- .../budgets/votes/_budget_selector.html.erb | 54 ++------ .../decidim/budgets/votes/_filters.html.erb | 96 +++------------ .../_finished_content.html.erb} | 0 .../budgets/votes/_identify_options.html.erb | 60 ++++----- .../budgets/votes/_identify_user.html.erb | 4 +- .../budgets/votes/_order_items.html.erb | 42 ++----- .../votes/_order_notifications.html.erb | 77 ------------ .../budgets/votes/_order_progress.html.erb | 65 +++------- .../budgets/votes/_orders_summary.html.erb | 55 ++++++--- .../budgets/votes/_preview_modal.html.erb | 41 +++++++ .../votes/_projects_continue_button.html.erb | 10 +- .../decidim/budgets/votes/_projects_list.erb | 82 +++++++++++++ app/views/decidim/budgets/votes/_top.html.erb | 28 +---- .../decidim/budgets/votes/budgets.html.erb | 92 ++++++-------- .../decidim/budgets/votes/finished.html.erb | 36 ++++++ .../decidim/budgets/votes/preview.js.erb | 11 ++ .../decidim/budgets/votes/projects.html.erb | 66 +++------- .../decidim/budgets/votes/projects.js.erb | 7 +- app/views/decidim/budgets/votes/show.html.erb | 48 ++++---- config/locales/en.yml | 114 ++++++++++------- config/locales/fi.yml | 115 +++++++++++------- config/locales/sv.yml | 99 ++++++++++----- lib/decidim/budgeting_pipeline/engine.rb | 13 +- .../budgeting_pipeline/test/factories.rb | 4 - 50 files changed, 986 insertions(+), 928 deletions(-) create mode 100644 app/controllers/concerns/decidim/budgeting_pipeline/authorizable.rb create mode 100644 app/helpers/decidim/budgeting_pipeline/authorization_helper.rb create mode 100644 app/model/concerns/decidim/budgeting_pipeline/budget_extensions.rb create mode 100644 app/uploaders/decidim/budgets/budget_image_uploader.rb rename app/views/decidim/budgets/{results/_vote_finished_modal_content.html.erb => votes/_finished_content.html.erb} (100%) delete mode 100644 app/views/decidim/budgets/votes/_order_notifications.html.erb create mode 100644 app/views/decidim/budgets/votes/_preview_modal.html.erb create mode 100644 app/views/decidim/budgets/votes/_projects_list.erb create mode 100644 app/views/decidim/budgets/votes/finished.html.erb create mode 100644 app/views/decidim/budgets/votes/preview.js.erb diff --git a/app/commands/concerns/decidim/budgeting_pipeline/admin_create_budget_extensions.rb b/app/commands/concerns/decidim/budgeting_pipeline/admin_create_budget_extensions.rb index 3bdef58..7c4173f 100644 --- a/app/commands/concerns/decidim/budgeting_pipeline/admin_create_budget_extensions.rb +++ b/app/commands/concerns/decidim/budgeting_pipeline/admin_create_budget_extensions.rb @@ -6,6 +6,8 @@ module BudgetingPipeline module AdminCreateBudgetExtensions extend ActiveSupport::Concern + include Decidim::AttachmentAttributesMethods + included do def create_budget! attributes = { @@ -17,7 +19,7 @@ def create_budget! total_budget: form.total_budget, center_latitude: form.center_latitude, center_longitude: form.center_longitude - } + }.merge(attachment_attributes(:list_image)) @budget = Decidim.traceability.create!( Decidim::Budgets::Budget, diff --git a/app/commands/concerns/decidim/budgeting_pipeline/admin_update_budget_extensions.rb b/app/commands/concerns/decidim/budgeting_pipeline/admin_update_budget_extensions.rb index 6a1dc7c..09a9994 100644 --- a/app/commands/concerns/decidim/budgeting_pipeline/admin_update_budget_extensions.rb +++ b/app/commands/concerns/decidim/budgeting_pipeline/admin_update_budget_extensions.rb @@ -6,6 +6,8 @@ module BudgetingPipeline module AdminUpdateBudgetExtensions extend ActiveSupport::Concern + include Decidim::AttachmentAttributesMethods + included do def update_budget! attributes = { @@ -16,7 +18,7 @@ def update_budget! total_budget: form.total_budget, center_latitude: form.center_latitude, center_longitude: form.center_longitude - } + }.merge(attachment_attributes(:list_image)) Decidim.traceability.update!( budget, diff --git a/app/controllers/concerns/decidim/budgeting_pipeline/authorizable.rb b/app/controllers/concerns/decidim/budgeting_pipeline/authorizable.rb new file mode 100644 index 0000000..355689d --- /dev/null +++ b/app/controllers/concerns/decidim/budgeting_pipeline/authorizable.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Decidim + module BudgetingPipeline + module Authorizable + extend ActiveSupport::Concern + + # This ensures that only people eligible to vote can enter the voting + # pipeline after the authorization step. The authorization conditions + # should be used to control user's ability to vote (e.g. where they live, + # how old they are, etc.). + def user_authorized? + @user_authorized ||= user_signed_in? && action_authorized_to("vote").ok? + end + + def authorization_required? + @authorization_required ||= begin + permission = current_component.permissions&.fetch("vote", nil) + handlers = permission&.fetch("authorization_handlers", nil)&.keys + if handlers && handlers.any? + providers = Decidim::BudgetingPipeline.authorization_providers + providers = providers.call(current_organization) if providers.respond_to?(:call) + (handlers & providers).any? + else + false + end + end + end + end + end +end diff --git a/app/controllers/concerns/decidim/budgeting_pipeline/line_items_controller_extensions.rb b/app/controllers/concerns/decidim/budgeting_pipeline/line_items_controller_extensions.rb index ecaf27a..267e8c5 100644 --- a/app/controllers/concerns/decidim/budgeting_pipeline/line_items_controller_extensions.rb +++ b/app/controllers/concerns/decidim/budgeting_pipeline/line_items_controller_extensions.rb @@ -11,9 +11,13 @@ module LineItemsControllerExtensions include Decidim::BudgetingPipeline::ProjectItemUtilities # Overrides the `voted_for?` method for multiple orders. included do + helper Decidim::Budgets::VotesHelper + def create enforce_permission_to :vote, :project, project: project, budget: budget, workflow: current_workflow + @added = true + respond_to do |format| Decidim::Budgets::AddLineItem.call(persisted_current_order, project, current_user) do on(:ok) do |order| diff --git a/app/controllers/concerns/decidim/budgeting_pipeline/projects_controller_extensions.rb b/app/controllers/concerns/decidim/budgeting_pipeline/projects_controller_extensions.rb index 5fcacc9..3049951 100644 --- a/app/controllers/concerns/decidim/budgeting_pipeline/projects_controller_extensions.rb +++ b/app/controllers/concerns/decidim/budgeting_pipeline/projects_controller_extensions.rb @@ -8,10 +8,13 @@ module ProjectsControllerExtensions include Decidim::Paginable include Decidim::BudgetingPipeline::VoteUtilities + include Decidim::BudgetingPipeline::Authorizable include Decidim::BudgetingPipeline::Orderable included do - helper_method :help_sections, :geocoded_projects, :budgets, :maximum_project_budget, :statuses_available?, :vote_success? + helper_method :authorization_required?, :user_authorized?, :help_sections, :geocoded_projects, :budgets, :maximum_project_budget, :statuses_available?, :vote_success? + + helper Decidim::BudgetingPipeline::AuthorizationHelper def index; end @@ -28,7 +31,8 @@ def default_filter_params decidim_budgets_budget_id_eq: nil, budget_amount_gteq: 0, budget_amount_lteq: maximum_project_budget, - activity: "all" + favorites: nil, + selected: nil } end diff --git a/app/controllers/decidim/budgets/votes_controller.rb b/app/controllers/decidim/budgets/votes_controller.rb index e5ec26d..9d6fabc 100644 --- a/app/controllers/decidim/budgets/votes_controller.rb +++ b/app/controllers/decidim/budgets/votes_controller.rb @@ -7,13 +7,17 @@ class VotesController < ApplicationController include Decidim::FormFactory include Decidim::FilterResource include Decidim::Paginable + include Decidim::TranslatableAttributes include Decidim::Budgets::Orderable + include Decidim::BudgetingPipeline::Authorizable include Decidim::BudgetingPipeline::Orderable include Decidim::BudgetingPipeline::OrdersUtilities include Decidim::BudgetingPipeline::VoteUtilities + helper Decidim::BudgetingPipeline::AuthorizationHelper + helper_method( - :authorization_required?, + :user_authorized?, :help_sections, :voting_steps, :current_step, @@ -29,7 +33,7 @@ class VotesController < ApplicationController before_action :ensure_voting_open! before_action :ensure_authorized! - before_action :ensure_not_voted! + before_action :ensure_not_voted!, except: [:finished] before_action :ensure_orders!, only: [:projects, :preview, :create] before_action :ensure_orders_valid!, only: [:preview, :create] before_action :set_current_step @@ -38,9 +42,12 @@ class VotesController < ApplicationController skip_before_action :ensure_not_voted!, only: [:show] def show + return redirect_to(routes_proxy.projects_path) unless user_signed_in? + define_step(authorization_required? ? :authorization : :login) return unless user_authorized? return ensure_not_voted! if user_voted? + return if current_workflow.progress.blank? && translated_attribute(component_settings.vote_privacy_content).present? redirect_to routes_proxy.budgets_vote_path end @@ -66,8 +73,7 @@ def start end def projects - @projects = search.result.page(params[:page]).per(current_component.settings.vote_projects_per_page) - @projects = reorder(@projects) + @projects = reorder(search.result) end def create @@ -78,11 +84,11 @@ def create # popup which is displayed after a successful vote. This is # important for screen reader users who need to hear the modal # content when it is displayed. - session["decidim-budgets.voted"] = true + # session["decidim-budgets.voted"] = true if current_settings.show_votes? redirect_to routes_proxy.results_path else - redirect_to routes_proxy.projects_path + redirect_to routes_proxy.finished_vote_path end end @@ -93,6 +99,10 @@ def create end end + def finished + redirect_to(routes_proxy.projects_path) if !user_signed_in? || !user_voted? + end + private attr_accessor :current_step, :prev_step, :next_step @@ -142,28 +152,6 @@ def ensure_orders_valid! redirect_to routes_proxy.projects_vote_path end - # This ensures that only people eligible to vote can enter the voting - # pipeline after the authorization step. The authorization conditions - # should be used to control user's ability to vote (e.g. where they live, - # how old they are, etc.). - def user_authorized? - @user_authorized ||= user_signed_in? && action_authorized_to("vote").ok? - end - - def authorization_required? - @authorization_required ||= begin - permission = current_component.permissions&.fetch("vote", nil) - handlers = permission&.fetch("authorization_handlers", nil)&.keys - if handlers && handlers.any? - providers = Decidim::BudgetingPipeline.authorization_providers - providers = providers.call(current_organization) if providers.respond_to?(:call) - (handlers & providers).any? - else - false - end - end - end - def set_current_step define_step(action_name.to_sym) end @@ -193,9 +181,9 @@ def help_sections # one(s) that will be automatically selected. def choose_budgets @choose_budgets ||= begin - sticky_ids = sticky_budgets.map(&:id) - current_workflow.allowed.reject do |budget| - sticky_ids.include?(budget.id) + suggested_ids = suggested_budgets.map(&:id) + current_workflow.budgets.reject do |budget| + suggested_ids.include?(budget.id) end end end @@ -290,7 +278,8 @@ def default_filter_params decidim_budgets_budget_id_eq: nil, budget_amount_gteq: 0, budget_amount_lteq: maximum_project_budget, - activity: "all" + favorites: nil, + selected: nil } end diff --git a/app/forms/concerns/decidim/budgeting_pipeline/admin_budget_form_extensions.rb b/app/forms/concerns/decidim/budgeting_pipeline/admin_budget_form_extensions.rb index 0421ed2..bfa4f86 100644 --- a/app/forms/concerns/decidim/budgeting_pipeline/admin_budget_form_extensions.rb +++ b/app/forms/concerns/decidim/budgeting_pipeline/admin_budget_form_extensions.rb @@ -9,6 +9,12 @@ module AdminBudgetFormExtensions included do attribute :center_latitude, Float attribute :center_longitude, Float + attribute :list_image, Decidim::Attributes::Blob + + validates :list_image, passthru: { + to: Decidim::Budgets::Budget, + with: { component: ->(form) { form.current_component } } + } def geocoded? center_latitude.present? && center_longitude.present? diff --git a/app/helpers/concerns/decidim/budgeting_pipeline/projects_helper_extensions.rb b/app/helpers/concerns/decidim/budgeting_pipeline/projects_helper_extensions.rb index 827f809..4a29d3f 100644 --- a/app/helpers/concerns/decidim/budgeting_pipeline/projects_helper_extensions.rb +++ b/app/helpers/concerns/decidim/budgeting_pipeline/projects_helper_extensions.rb @@ -33,6 +33,17 @@ def projects_data_for_map(geocoded_projects_data) end end + def identity_providers + providers = Decidim::BudgetingPipeline.identity_providers + return providers unless providers.respond_to?(:call) + + providers.call(current_organization) + end + + def identity_provider_name(provider) + Decidim::BudgetingPipeline.identity_provider_name.call(provider) + end + def landing_page_content translated_attribute(current_settings.landing_page_content).presence || translated_attribute(component_settings.landing_page_content) diff --git a/app/helpers/decidim/budgeting_pipeline/authorization_helper.rb b/app/helpers/decidim/budgeting_pipeline/authorization_helper.rb new file mode 100644 index 0000000..7f4fe12 --- /dev/null +++ b/app/helpers/decidim/budgeting_pipeline/authorization_helper.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +module Decidim + module BudgetingPipeline + module AuthorizationHelper + include Decidim::BudgetingPipeline::ProjectsHelperExtensions + include Decidim::BudgetingPipeline::ProjectItemUtilities + include Decidim::BudgetingPipeline::TextUtilities + + def available_authorization_provider_keys + providers = Decidim::BudgetingPipeline.authorization_providers + providers = providers.call(current_organization) if providers.respond_to?(:call) + providers + end + + def authorization_providers + Verifications::Adapter.from_collection( + available_authorization_provider_keys - user_authorizations.pluck(:name) + ) + end + + def user_authorizations(type = :all) + base = Decidim::Authorization.where( + name: available_authorization_provider_keys, + user: current_user + ) + return base.where.not(granted_at: nil) if type == :granted + return base.where(granted_at: nil) if type == :pending + + base + end + + def authorization_provider_name(provider) + Decidim::BudgetingPipeline.authorization_provider_name.call(provider) + end + + def invalid_authorization_title + translated_attribute(component_settings.vote_identify_invalid_authorization_title) + end + + def invalid_authorization_content + translated_attribute(component_settings.vote_identify_invalid_authorization_content) + end + + # This is for the projects view that displays the project filters that + # refers the `budgets` variable. + def budgets + selected_budgets + end + end + end +end diff --git a/app/helpers/decidim/budgets/votes_helper.rb b/app/helpers/decidim/budgets/votes_helper.rb index a0f7601..192fd40 100644 --- a/app/helpers/decidim/budgets/votes_helper.rb +++ b/app/helpers/decidim/budgets/votes_helper.rb @@ -3,60 +3,30 @@ module Decidim module Budgets module VotesHelper - include Decidim::BudgetingPipeline::ProjectsHelperExtensions - include Decidim::BudgetingPipeline::ProjectItemUtilities - include Decidim::BudgetingPipeline::TextUtilities - - def identity_providers - providers = Decidim::BudgetingPipeline.identity_providers - return providers unless providers.respond_to?(:call) - - providers.call(current_organization) - end - - def identity_provider_name(provider) - Decidim::BudgetingPipeline.identity_provider_name.call(provider) - end - - def available_authorization_provider_keys - providers = Decidim::BudgetingPipeline.authorization_providers - providers = providers.call(current_organization) if providers.respond_to?(:call) - providers - end - - def authorization_providers - Verifications::Adapter.from_collection( - available_authorization_provider_keys - user_authorizations.pluck(:name) - ) - end + def voting_step_link(step) + mobile_tag = content_tag :span, class: "step-selector hide-for-mediumlarge" do + yield + end + desktop_tag = begin + attributes = { class: "step-selector show-for-mediumlarge" } + attributes[:aria] = { current: "step" } if step.key == current_step - def user_authorizations(type = :all) - base = Decidim::Authorization.where( - name: available_authorization_provider_keys, - user: current_user - ) - return base.where.not(granted_at: nil) if type == :granted - return base.where(granted_at: nil) if type == :pending + link_to step.link, attributes do + yield + end + end - base + mobile_tag + desktop_tag end - def authorization_provider_name(provider) - Decidim::BudgetingPipeline.authorization_provider_name.call(provider) + def privacy_content + translated_attribute(component_settings.vote_privacy_content) end def display_more_information? translated_attribute(component_settings.more_information_modal).present? end - def invalid_authorization_title - translated_attribute(component_settings.vote_identify_invalid_authorization_title) - end - - def invalid_authorization_content - translated_attribute(component_settings.vote_identify_invalid_authorization_content) - end - def more_information_label label = translated_attribute(component_settings.more_information_modal_label) return label if label.present? @@ -64,26 +34,11 @@ def more_information_label t("decidim.budgets.votes.budgets.show_more_information_default") end - def voting_step_link(step) - mobile_tag = content_tag :span, class: "step-selector hide-for-mediumlarge" do - yield - end - desktop_tag = begin - attributes = { class: "step-selector show-for-mediumlarge" } - attributes[:aria] = { current: "step" } if step.key == current_step - - link_to step.link, attributes do - yield - end - end - - mobile_tag + desktop_tag - end + def project_selected?(project) + order = current_orders.find_by(budget: project.budget) + return false unless order - # This is for the projects view that displays the project filters that - # refers the `budgets` variable. - def budgets - selected_budgets + order.projects.include?(project) end end end diff --git a/app/model/concerns/decidim/budgeting_pipeline/budget_extensions.rb b/app/model/concerns/decidim/budgeting_pipeline/budget_extensions.rb new file mode 100644 index 0000000..b8cf780 --- /dev/null +++ b/app/model/concerns/decidim/budgeting_pipeline/budget_extensions.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Decidim + module BudgetingPipeline + # Extends the budget class with some options. + module BudgetExtensions + extend ActiveSupport::Concern + + include Decidim::HasUploadValidations + include Decidim::Stats::Measurable + + included do + validates_upload :list_image, uploader: Decidim::Budgets::BudgetImageUploader + has_one_attached :list_image + end + end + end +end diff --git a/app/model/concerns/decidim/budgeting_pipeline/project_extensions.rb b/app/model/concerns/decidim/budgeting_pipeline/project_extensions.rb index 413be32..c09795c 100644 --- a/app/model/concerns/decidim/budgeting_pipeline/project_extensions.rb +++ b/app/model/concerns/decidim/budgeting_pipeline/project_extensions.rb @@ -75,6 +75,10 @@ def locale_case(column) validates_upload :main_image, uploader: Decidim::Budgets::ProjectImageUploader has_one_attached :main_image + scope :voted_by, lambda { |user| + joins(:orders).where(decidim_budgets_orders: { decidim_user_id: user }) + } + scope :order_by_most_voted, lambda { |only_voted: false| scope = joins( <<~SQLJOIN.squish diff --git a/app/packs/src/decidim/budgeting_pipeline/projects.js b/app/packs/src/decidim/budgeting_pipeline/projects.js index cde0cb0..6b69693 100644 --- a/app/packs/src/decidim/budgeting_pipeline/projects.js +++ b/app/packs/src/decidim/budgeting_pipeline/projects.js @@ -5,24 +5,43 @@ import "src/decidim/budgeting_pipeline/exit_handler"; const $ = exports.$; // eslint-disable-line id-length const Rails = exports.Rails; - $(() => { - const $form = $("form.new_filter"); - - $form.on("reset.budgets", () => { - // Give the browser a bit of time to clear the fields - setTimeout(() => { - Rails.fire($form[0], "submit"); - }, 100); + window.initializeProjects = () => { + const loadingProjects = []; + document.querySelectorAll("[data-project-selector] input[type='checkbox']").forEach((el) => { + el.addEventListener("change", () => { + loadingProjects.push(el.value); + document.body.classList.add("loading"); + Rails.ajax({ + url: el.dataset.selectUrl, + type: el.checked ? "POST" : "DELETE", + success: () => { + loadingProjects.shift(); + if (loadingProjects.length < 1) { + document.body.classList.remove("loading"); + } + }, + error: () => { + loadingProjects.shift(); + if (loadingProjects.length < 1) { + document.body.classList.remove("loading"); + } + } + }); + }); }); - // Unregister the history callbacks for the filter forms because they cause - // the form to be sent when anchor links are clicked. This would cause the - // results to flash and also causes the screen reader to announce the number - // of results. They would also never trigger because the change events are - // disabled for all filter inputs. - $form.each((_i, el) => { - const $currentForm = $(el); - unregisterCallback(`filters-${$currentForm.attr("id")}`); + document.querySelectorAll(".projects-table__row").forEach((el) => { + el.querySelector(".projects-table__row__data").addEventListener("click", (ev) => { + ev.preventDefault(); + + if (el.dataset.open) { + el.removeAttribute("data-open"); + } else { + el.setAttribute("data-open", true); + } + }); }); - }); + }; + + window.initializeProjects(); })(window); diff --git a/app/services/decidim/budgeting_pipeline/project_search.rb b/app/services/decidim/budgeting_pipeline/project_search.rb index c76f774..2be5f79 100644 --- a/app/services/decidim/budgeting_pipeline/project_search.rb +++ b/app/services/decidim/budgeting_pipeline/project_search.rb @@ -9,16 +9,18 @@ class ProjectSearch < ResourceSearch def build(params) @activity = params[:activity] - if activity && user - case activity - when "own" - # TODO: Filter by related records that the user has coauthored. - when "favorites" - add_scope(:user_favorites, user) - end + if user + add_scope(:user_favorites, user) if params[:favorites] == "1" + add_scope(:voted_by, user) if params[:selected] == "1" end - super + search_text = params[:search_text_cont] + if search_text && (id_match = search_text.match(/\A#([0-9]+)\z/)) + params.delete(:search_text_cont) + params[:id_eq] = id_match[1] + end + + super(params) end end end diff --git a/app/uploaders/decidim/budgets/budget_image_uploader.rb b/app/uploaders/decidim/budgets/budget_image_uploader.rb new file mode 100644 index 0000000..00f5f63 --- /dev/null +++ b/app/uploaders/decidim/budgets/budget_image_uploader.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Decidim + module Budgets + # This class deals with uploading images to budgets. + class BudgetImageUploader < Decidim::ImageUploader + def content_type_allowlist + %w(image/jpeg image/png image/svg+xml) + end + + def extension_allowlist + %w(jpeg jpg png svg) + end + end + end +end diff --git a/app/views/decidim/budgets/admin/budgets/_form.html.erb b/app/views/decidim/budgets/admin/budgets/_form.html.erb index 1f928ee..6c95c6b 100644 --- a/app/views/decidim/budgets/admin/budgets/_form.html.erb +++ b/app/views/decidim/budgets/admin/budgets/_form.html.erb @@ -11,6 +11,10 @@ <%= form.translated :editor, :description %> +
+ <%= form.upload :list_image %> +
+ <%= form.number_field :total_budget %> <% if current_component.settings.geocoding_enabled %> diff --git a/app/views/decidim/budgets/line_items/_error_message.html.erb b/app/views/decidim/budgets/line_items/_error_message.html.erb index d1dcf99..ceec604 100644 --- a/app/views/decidim/budgets/line_items/_error_message.html.erb +++ b/app/views/decidim/budgets/line_items/_error_message.html.erb @@ -4,12 +4,4 @@ <%= t(".error.#{@error_reason}.title") %>

<%= t(".error.#{@error_reason}.description") %>

-

- <%= link_to "#orders", data: { close: "order-update-error" }, aria: { - label: t("decidim.budgets.projects.projects.show_orders") - } do %> - <%= icon "cart", role: "img", "aria-hidden": true %> - <%= t("decidim.budgets.projects.projects.show_orders") %> » - <% end %> -

diff --git a/app/views/decidim/budgets/line_items/update_budget.js.erb b/app/views/decidim/budgets/line_items/update_budget.js.erb index 81926af..12d9d96 100644 --- a/app/views/decidim/budgets/line_items/update_budget.js.erb +++ b/app/views/decidim/budgets/line_items/update_budget.js.erb @@ -1,51 +1,37 @@ -<% amount = current_orders.map { |o| o.line_items.count }.inject(0, :+) %> - -var $projectCard = $("#project_<%= project.id %> .card"); -var $projectBudgetButton = $("#project-<%= project.id %>-budget-button"); var $continueButton = $("#projects_continue_button"); -var $continueButtonOrders = $("#projects_continue_button_orders"); -var $cartButton = $("#cart-button"); -var voted = <%= voted_for?(project).to_json %>; -var amount = <%= amount %>; -var amountText = "<%= j(t("decidim.budgets.projects.projects.order_items_amount", count: amount)) %>"; - -if (voted) { - $projectCard.addClass("selected"); -} else { - $projectCard.removeClass("selected"); -} - -if ($projectBudgetButton.length > 0) { - $projectBudgetButton.replaceWith('<%= j(render partial: "decidim/budgets/projects/project_budget_button", locals: { project: project }).strip.html_safe %>'); -} +var $continueButtonMobile = $("#projects_continue_button_mobile"); if ($continueButton.length > 0) { $continueButton.html('<%= j(render partial: "decidim/budgets/votes/projects_continue_button").strip.html_safe %>'); } - -if ($continueButtonOrders.length > 0) { - $continueButtonOrders.html('<%= j(render partial: "decidim/budgets/orders/continue_button").strip.html_safe %>'); -} - -if ($cartButton.length > 0) { - $(".amount", $cartButton).text("(" + amount + ")"); - $(".amount", $cartButton).attr("aria-label", amountText); +if ($continueButtonMobile.length > 0) { + $continueButtonMobile.html('<%= j(render partial: "decidim/budgets/votes/projects_continue_button", locals: { mobile: true }).strip.html_safe %>'); } -var $orderProgress; -var $orderNotifications; -var $orderItems; <% current_orders.each do |order| %> -$orderProgress = $("#order-progress-<%= order.budget.id %>"); +var $orderProgress = $("#order-progress-<%= order.budget.id %>"); if ($orderProgress.length > 0) { morphdom($orderProgress[0], '<%= j(render partial: "decidim/budgets/votes/order_progress", locals: { order: order }).strip.html_safe %>'); } -$orderNotifications = $("#order-notifications-<%= order.budget.id %>"); -if ($orderNotifications.length > 0) { - $orderNotifications.html('<%= j(render partial: "decidim/budgets/votes/order_notifications", locals: { order: order }).strip.html_safe %>'); -} -$orderItems = $("#order-items-<%= order.budget.id %>"); + +var $orderItems = $("#order-items-<%= order.budget.id %>"); if ($orderItems.length > 0) { morphdom($orderItems[0], '<%= j(render partial: "decidim/budgets/votes/order_items", locals: { order: order }).strip.html_safe %>'); } <% end %> + +var $project = $("[data-project-id='<%= project.id %>']"); +if ($project.length > 0) { + <% if @added %> + $("input[type='checkbox']", $project).prop("checked", true); + <% else %> + $("input[type='checkbox']", $project).prop("checked", false); + <% end %> +} + +var $nonSeleceted = $(".projects-table__row .input-checkbox input[type='checkbox']:not(:checked)"); +<% if current_orders.first.projects_rule? && current_orders.all? { |o| o.unused_allocation < 1 } %> +$nonSeleceted.attr("disabled", true); +<% else %> +$nonSeleceted.removeAttr("disabled"); +<% end %> diff --git a/app/views/decidim/budgets/line_items/update_budget_error.js.erb b/app/views/decidim/budgets/line_items/update_budget_error.js.erb index 1a7e52d..849f299 100644 --- a/app/views/decidim/budgets/line_items/update_budget_error.js.erb +++ b/app/views/decidim/budgets/line_items/update_budget_error.js.erb @@ -10,3 +10,8 @@ $(".error-message", $modal).html('<%= j(render partial: "error_message").strip.h $(".error-details", $modal).html('<%= j(render partial: "error_details").strip.html_safe %>'); $modal.foundation("open"); + +var $project = $("[data-project-id='<%= project.id %>']"); +if ($project.length > 0) { + $("input[type='checkbox']", $project).prop("checked", false); +} diff --git a/app/views/decidim/budgets/orders/_orders_info.html.erb b/app/views/decidim/budgets/orders/_orders_info.html.erb index 151cd19..d9fd831 100644 --- a/app/views/decidim/budgets/orders/_orders_info.html.erb +++ b/app/views/decidim/budgets/orders/_orders_info.html.erb @@ -8,41 +8,37 @@

<%= t(".total_budget") %>: <%= nonbreaking_text(budget_to_currency(order.available_allocation)) %>

<% end %> -
-
- <% if order.line_items.any? %> - - - <% order.line_items.order_by_projects.each do |item| %> - - - - - <% end %> - -
- <%= link_to budget_project_path(item.project.budget, item.project), data: { remote: true } do %> - <%= translated_attribute(item.project.title) %> - <% end %> - - <% if item.project.budget_amount > 0 %> - <%= nonbreaking_text(budget_to_currency(item.project.budget_amount)) %> - <% end %> -
-
-
- <% if order.projects_rule? %> - <%= t(".allocated_projects") %>: -   <%= order.total %> - <% else %> - <%= t(".allocated_budget") %>: -   <%= nonbreaking_text(budget_to_currency(order.total)) %> - <% end %> -
+ <% if order.line_items.any? %> + + + <% order.line_items.order_by_projects.each do |item| %> + + + + + <% end %> + +
+ <%= link_to budget_project_path(item.project.budget, item.project), data: { remote: true } do %> + <%= translated_attribute(item.project.title) %> + <% end %> + + <% if item.project.budget_amount > 0 %> + <%= nonbreaking_text(budget_to_currency(item.project.budget_amount)) %> + <% end %> +
+
+
+ <% if order.projects_rule? %> + <%= t(".allocated_projects") %>: +   <%= order.total %> <% else %> -

<%= t(".empty_order", name: translated_attribute(order.budget.title)) %>

+ <%= t(".allocated_budget") %>: +   <%= nonbreaking_text(budget_to_currency(order.total)) %> <% end %>
-
+ <% else %> +

<%= t(".empty_order", name: translated_attribute(order.budget.title)) %>

+ <% end %>
<% end %> diff --git a/app/views/decidim/budgets/orders/index.html.erb b/app/views/decidim/budgets/orders/index.html.erb index 7691a50..d4f32ab 100644 --- a/app/views/decidim/budgets/orders/index.html.erb +++ b/app/views/decidim/budgets/orders/index.html.erb @@ -1,18 +1,11 @@ -
- <%= link_to projects_path, class: "small hollow" do %> - <%= icon "chevron-left", class: "icon--small" %> - <%= t(".back") %> - <% end %> -
-
-
-

<%= t(".title") %>

+
+

<%= t(".title") %>

-
-
+
+
<%== t(".description_html") %> @@ -25,6 +18,15 @@
-
- <%= render partial: "orders_info" %> +
+
+ <%= render partial: "orders_info" %> +
+
+ +
+ <%= link_to projects_path, class: "action-link" do %> + <%= icon "arrow-left", class: "icon--small" %> + <%= t(".back") %> + <% end %>
diff --git a/app/views/decidim/budgets/projects/_filters.html.erb b/app/views/decidim/budgets/projects/_filters.html.erb index 5fc3c61..fd37ff0 100644 --- a/app/views/decidim/budgets/projects/_filters.html.erb +++ b/app/views/decidim/budgets/projects/_filters.html.erb @@ -3,52 +3,33 @@ type_suffix = defined?(type) ? "_#{type}" : "" %> <%= filter_form_for filter, projects_path, role: "region", "aria-label": t(".label") do |form| %> -
-
-
-
-

<%= t(".title") %>

-
-
-
-
-
-
-
-
- <%= t(".term") %> - <%= form.search_field :search_text_cont, label: false, placeholder: t(".term"), title: t(".term"), "aria-label": t(".term"), data: { disable_dynamic_change: true } %> -
+
+
+ <%= form.search_field :search_text_cont, label: t(".term"), placeholder: t(".term"), data: { disable_dynamic_change: true } %>
+ <% if display_budgets_filter? %> -
-
-
- <%= t(".budget") %> - <%= form.select(:decidim_budgets_budget_id_eq, filter_budgets_values, { label: false, include_blank: filter_budgets_label }, "aria-label": t(".budget"), data: { disable_dynamic_change: true }) %> -
+
+
+ <%= form.select(:decidim_budgets_budget_id_eq, filter_budgets_values, { label: t(".budget"), include_blank: filter_budgets_label }, data: { disable_dynamic_change: true }) %>
<% end %> + <% if display_category_filter? %> -
-
-
- <%= t(".category") %> - <%= form.select(:with_any_category, filter_categories_values, { label: false, include_blank: t(".categories_values.all") }, "aria-label": t(".category"), data: { disable_dynamic_change: true }) %> -
+
+
+ <%= form.select(:with_any_category, filter_categories_values, { label: t(".category"), include_blank: t(".categories_values.all") }, data: { disable_dynamic_change: true }) %>
<% end %> + <% if display_status_filter? %> -
-
-
- <%= t(".status") %> - <%= form.select(:with_any_status, filter_status_values, { label: false, include_blank: t(".status_values.all") }, "aria-label": t(".status"), data: { disable_dynamic_change: true }) %> -
+
+
+ <%= form.select(:with_any_status, filter_status_values, { label: t(".status"), include_blank: t(".status_values.all") }, data: { disable_dynamic_change: true }) %>
<% end %> @@ -73,54 +54,44 @@ type_suffix = defined?(type) ? "_#{type}" : ""