diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index f66510049..774ea5c78 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -70,6 +70,7 @@
//= require advanced_search
//= require registration_form
//= require suggest
+//= require filter_selector
//= require forms
//= require valuation_budget_investment_form
//= require embed_video
@@ -133,6 +134,7 @@ var initialize_modules = function() {
App.RegistrationForm.initialize();
App.Suggest.initialize();
App.Forms.initialize();
+ App.FilterSelector.initialize();
App.ValuationBudgetInvestmentForm.initialize();
App.EmbedVideo.initialize();
App.FixedBar.initialize();
diff --git a/app/assets/javascripts/filter_selector.js b/app/assets/javascripts/filter_selector.js
new file mode 100644
index 000000000..5f35db45c
--- /dev/null
+++ b/app/assets/javascripts/filter_selector.js
@@ -0,0 +1,8 @@
+(function() {
+ "use strict";
+ App.FilterSelector = {
+ initialize: function() {
+ App.Forms.submitOnChange(".filter-selector select");
+ }
+ };
+}).call(this);
diff --git a/app/assets/javascripts/forms.js b/app/assets/javascripts/forms.js
index 822b2391b..0a2dfe107 100644
--- a/app/assets/javascripts/forms.js
+++ b/app/assets/javascripts/forms.js
@@ -8,8 +8,8 @@
}
});
},
- submitOnChange: function() {
- $("body").on("change", ".js-submit-on-change", function() {
+ submitOnChange: function(selector) {
+ $("body").on("change", selector, function() {
$(this).closest("form").submit();
return false;
});
@@ -58,7 +58,7 @@
},
initialize: function() {
App.Forms.disableEnter();
- App.Forms.submitOnChange();
+ App.Forms.submitOnChange(".js-submit-on-change");
App.Forms.toggleLink();
App.Forms.synchronizeInputs();
App.Forms.hideOrShowFieldsAfterSelection();
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index 6ce3e2ede..e71bfaf26 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -12,6 +12,7 @@
@import "milestones";
@import "pages";
@import "dashboard";
+@import "filter_selector";
@import "legislation";
@import "legislation_process";
@import "legislation_process_form";
diff --git a/app/assets/stylesheets/filter_selector.scss b/app/assets/stylesheets/filter_selector.scss
new file mode 100644
index 000000000..10de18b25
--- /dev/null
+++ b/app/assets/stylesheets/filter_selector.scss
@@ -0,0 +1,14 @@
+.filter-selector {
+ text-align: right;
+
+ label {
+ display: inline-block;
+ font-size: $small-font-size;
+ margin-right: $line-height / 2;
+ padding-top: $line-height / 2;
+ }
+
+ select {
+ width: auto;
+ }
+}
diff --git a/app/components/shared/filter_selector_component.html.erb b/app/components/shared/filter_selector_component.html.erb
new file mode 100644
index 000000000..f8cdd6dee
--- /dev/null
+++ b/app/components/shared/filter_selector_component.html.erb
@@ -0,0 +1,5 @@
+<%= form_tag({}, method: :get, enforce_utf8: false, class: "filter-selector") do %>
+ <%= query_parameters_tags %>
+ <%= label_tag "filter_selector_filter", t("#{i18n_namespace}.filter") %>
+ <%= select_tag "filter", options_for_select(filter_options, current_filter), id: "filter_selector_filter" %>
+<% end %>
diff --git a/app/components/shared/filter_selector_component.rb b/app/components/shared/filter_selector_component.rb
new file mode 100644
index 000000000..6ea316a62
--- /dev/null
+++ b/app/components/shared/filter_selector_component.rb
@@ -0,0 +1,22 @@
+class Shared::FilterSelectorComponent < ApplicationComponent
+ delegate :valid_filters, :current_filter, to: :helpers
+ attr_reader :i18n_namespace
+
+ def initialize(i18n_namespace:)
+ @i18n_namespace = i18n_namespace
+ end
+
+ private
+
+ def query_parameters_tags
+ safe_join(request.query_parameters.reject do |name, _|
+ ["page", "filter"].include?(name)
+ end.map do |name, value|
+ hidden_field_tag name, value, id: "filter_selector_#{name}"
+ end)
+ end
+
+ def filter_options
+ valid_filters.map { |filter| [t("#{i18n_namespace}.filters.#{filter}"), filter] }
+ end
+end
diff --git a/app/helpers/budgets_helper.rb b/app/helpers/budgets_helper.rb
index d27fec415..fcf937fa0 100644
--- a/app/helpers/budgets_helper.rb
+++ b/app/helpers/budgets_helper.rb
@@ -1,8 +1,4 @@
module BudgetsHelper
- def show_links_to_budget_investments(budget)
- ["balloting", "reviewing_ballots", "finished"].include? budget.phase
- end
-
def budget_voting_styles_select_options
Budget::VOTING_STYLES.map do |style|
[Budget.human_attribute_name("voting_style_#{style}"), style]
diff --git a/app/views/budgets/index.html.erb b/app/views/budgets/index.html.erb
index 73f53bbd9..bdd3d3504 100644
--- a/app/views/budgets/index.html.erb
+++ b/app/views/budgets/index.html.erb
@@ -55,29 +55,6 @@
<%= t("budgets.index.map") %>
<%= render_map(nil, "budgets", false, nil, @budgets_coordinates) %>
-
-
- <% show_links = show_links_to_budget_investments(current_budget) %>
- <% if show_links %>
- -
- <%= link_to budget_path(current_budget) do %>
- <%= t("budgets.index.investment_proyects") %>
- <% end %>
-
- <% end %>
- -
- <%= link_to budget_path(current_budget, filter: "unfeasible") do %>
- <%= t("budgets.index.unfeasible_investment_proyects") %>
- <% end %>
-
- <% if show_links %>
- -
- <%= link_to budget_path(current_budget, filter: "unselected") do %>
- <%= t("budgets.index.not_selected_investment_proyects") %>
- <% end %>
-
- <% end %>
-
<% end %>
diff --git a/app/views/budgets/investments/index.html.erb b/app/views/budgets/investments/index.html.erb
index c1cca7353..b8013cf14 100644
--- a/app/views/budgets/investments/index.html.erb
+++ b/app/views/budgets/investments/index.html.erb
@@ -70,6 +70,8 @@
<%= render("shared/order_links", i18n_namespace: "budgets.investments.index") %>
<% end %>
+ <%= render Shared::FilterSelectorComponent.new(i18n_namespace: "budgets.investments.index") %>
+
<% if investments_default_view? %>
<% @investments.each do |investment| %>
diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml
index dd76cacec..71933acf9 100644
--- a/config/i18n-tasks.yml
+++ b/config/i18n-tasks.yml
@@ -127,6 +127,7 @@ ignore_missing:
## Consider these keys used:
ignore_unused:
- "budgets.phase.*"
+ - "budgets.investments.index.filter*"
- "budgets.investments.index.orders.*"
- "budgets.index.section_header.*"
- "budgets.ballots.show.amount_available.*"
diff --git a/config/locales/en/budgets.yml b/config/locales/en/budgets.yml
index 97468dd92..7931cc773 100644
--- a/config/locales/en/budgets.yml
+++ b/config/locales/en/budgets.yml
@@ -69,9 +69,6 @@ en:
prev_phase: Previous phase
current_phase: Current phase
map: Budget investments' proposals located geographically
- investment_proyects: List of all investment projects
- unfeasible_investment_proyects: List of all unfeasible investment projects
- not_selected_investment_proyects: List of all investment projects not selected for balloting
finished_budgets: Finished participatory budgets
see_results: See results
section_footer:
@@ -120,6 +117,13 @@ en:
verified_only: "To create a new budget investment %{verify}."
create: "Create a budget investment"
not_logged_in: "To create a new budget investment you must %{sign_in} or %{sign_up}."
+ filter: "Filtering projects by"
+ filters:
+ not_unfeasible: "Not unfeasible"
+ selected: "Selected"
+ unfeasible: "Unfeasible"
+ unselected: "Unselected"
+ winners: "Winners"
orders:
random: random
confidence_score: highest rated
diff --git a/config/locales/es/budgets.yml b/config/locales/es/budgets.yml
index 76a71eb2a..98eda05f9 100644
--- a/config/locales/es/budgets.yml
+++ b/config/locales/es/budgets.yml
@@ -69,9 +69,6 @@ es:
prev_phase: Fase anterior
current_phase: Fase actual
map: Proyectos localizables geográficamente
- investment_proyects: Ver lista completa de proyectos de gasto
- unfeasible_investment_proyects: Ver lista de proyectos de gasto inviables
- not_selected_investment_proyects: Ver lista de proyectos de gasto no seleccionados para la votación final
finished_budgets: Presupuestos participativos terminados
see_results: Ver resultados
section_footer:
@@ -120,6 +117,13 @@ es:
verified_only: "Para crear un nuevo proyecto de gasto %{verify}."
create: "Crear proyecto de gasto"
not_logged_in: "Para crear un nuevo proyecto de gasto debes %{sign_in} o %{sign_up}."
+ filter: "Filtrando proyectos"
+ filters:
+ not_unfeasible: "No inviables"
+ selected: "Seleccionados"
+ unfeasible: "Inviables"
+ unselected: "No seleccionados"
+ winners: "Ganadores"
orders:
random: Aleatorios
confidence_score: Mejor valorados
diff --git a/spec/components/shared/filter_selector_component_spec.rb b/spec/components/shared/filter_selector_component_spec.rb
new file mode 100644
index 000000000..6943a1a9e
--- /dev/null
+++ b/spec/components/shared/filter_selector_component_spec.rb
@@ -0,0 +1,15 @@
+require "rails_helper"
+
+describe Shared::FilterSelectorComponent, type: :component do
+ it "renders a form with a select" do
+ component = Shared::FilterSelectorComponent.new(i18n_namespace: "budgets.investments.index")
+ allow(component).to receive(:url_for).and_return("/")
+ allow(component).to receive(:valid_filters).and_return(["unfeasible", "winners"])
+ allow(component).to receive(:current_filter).and_return(nil)
+
+ render_inline component
+
+ expect(page).to have_select "Filtering projects by"
+ expect(page).to have_selector "form[method='get'].filter-selector select"
+ end
+end
diff --git a/spec/system/budgets/budgets_spec.rb b/spec/system/budgets/budgets_spec.rb
index f3e0ba3a2..022ad0693 100644
--- a/spec/system/budgets/budgets_spec.rb
+++ b/spec/system/budgets/budgets_spec.rb
@@ -139,53 +139,10 @@ describe "Budgets" do
expect(page).not_to have_link "#{heading.name} €1,000,000"
expect(page).to have_content "#{heading.name} €1,000,000"
- expect(page).to have_link "List of all investment projects",
- href: budget_path(budget)
-
- expect(page).to have_link "List of all unfeasible investment projects",
- href: budget_path(budget, filter: "unfeasible")
-
- expect(page).to have_link "List of all investment projects not selected for balloting",
- href: budget_path(budget, filter: "unselected")
-
expect(page).to have_css("div.map")
end
end
- scenario "Show investment links only on balloting or later" do
- budget = create(:budget)
- create(:budget_heading, budget: budget)
-
- allowed_phase_list.each do |phase|
- budget.update!(phase: phase)
-
- visit budgets_path
-
- expect(page).to have_content(I18n.t("budgets.index.investment_proyects"))
- expect(page).to have_content(I18n.t("budgets.index.unfeasible_investment_proyects"))
- expect(page).to have_content(I18n.t("budgets.index.not_selected_investment_proyects"))
- end
- end
-
- scenario "Not show investment links earlier of balloting " do
- budget = create(:budget)
- create(:budget_heading, budget: budget)
- phases_without_links = ["informing"]
- not_allowed_phase_list = Budget::Phase::PHASE_KINDS -
- phases_without_links -
- allowed_phase_list
-
- not_allowed_phase_list.each do |phase|
- budget.update!(phase: phase)
-
- visit budgets_path
-
- expect(page).not_to have_content(I18n.t("budgets.index.investment_proyects"))
- expect(page).to have_content(I18n.t("budgets.index.unfeasible_investment_proyects"))
- expect(page).not_to have_content(I18n.t("budgets.index.not_selected_investment_proyects"))
- end
- end
-
scenario "No budgets" do
Budget.destroy_all
diff --git a/spec/system/budgets/investments_spec.rb b/spec/system/budgets/investments_spec.rb
index 73555d56a..a93c5a276 100644
--- a/spec/system/budgets/investments_spec.rb
+++ b/spec/system/budgets/investments_spec.rb
@@ -151,6 +151,51 @@ describe "Budget Investments" do
end
end
+ scenario "Index filter by status", :js do
+ budget.update!(phase: "finished")
+
+ create(:budget_investment, :feasible, heading: heading, title: "Feasible investment")
+ create(:budget_investment, :unfeasible, heading: heading, title: "Unfeasible investment")
+ create(:budget_investment, :unselected, heading: heading, title: "Unselected investment")
+ create(:budget_investment, :selected, heading: heading, title: "Selected investment")
+ create(:budget_investment, :winner, heading: heading, title: "Winner investment")
+
+ visit budget_investments_path(budget, heading_id: heading.id)
+
+ expect(page).to have_select "Filtering projects by",
+ options: ["Not unfeasible", "Unfeasible", "Unselected", "Selected", "Winners"]
+
+ select "Unfeasible", from: "Filtering projects by"
+
+ expect(page).to have_css ".budget-investment", count: 1
+ expect(page).to have_content "Unfeasible investment"
+
+ select "Unselected", from: "Filtering projects by"
+
+ expect(page).to have_css ".budget-investment", count: 2
+ expect(page).to have_content "Unselected investment"
+ expect(page).to have_content "Feasible investment"
+
+ select "Selected", from: "Filtering projects by"
+
+ expect(page).to have_css ".budget-investment", count: 2
+ expect(page).to have_content "Selected investment"
+ expect(page).to have_content "Winner investment"
+
+ select "Winners", from: "Filtering projects by"
+
+ expect(page).to have_css ".budget-investment", count: 1
+ expect(page).to have_content "Winner investment"
+
+ select "Not unfeasible", from: "Filtering projects by"
+
+ expect(page).to have_css ".budget-investment", count: 4
+ expect(page).to have_content "Selected investment"
+ expect(page).to have_content "Unselected investment"
+ expect(page).to have_content "Feasible investment"
+ expect(page).to have_content "Winner investment"
+ end
+
context("Search") do
scenario "Search by text" do
investment1 = create(:budget_investment, heading: heading, title: "Get Schwifty")