Add filters on budget investments index page

Now it's easier to change the investments filter. Previously we had to
go back to the budget index page, change the filter there, and then
select one heading.

Now the links to change the current filter in the budget index page
aren't needed anymore.
This commit is contained in:
decabeza
2020-05-06 15:06:40 +02:00
committed by Javi Martín
parent f5c1cfbf8c
commit 04605d5d5b
16 changed files with 132 additions and 79 deletions

View File

@@ -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();

View File

@@ -0,0 +1,8 @@
(function() {
"use strict";
App.FilterSelector = {
initialize: function() {
App.Forms.submitOnChange(".filter-selector select");
}
};
}).call(this);

View File

@@ -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();

View File

@@ -12,6 +12,7 @@
@import "milestones";
@import "pages";
@import "dashboard";
@import "filter_selector";
@import "legislation";
@import "legislation_process";
@import "legislation_process_form";

View File

@@ -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;
}
}

View File

@@ -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 %>

View File

@@ -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

View File

@@ -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]

View File

@@ -55,29 +55,6 @@
<h3><%= t("budgets.index.map") %></h3>
<%= render_map(nil, "budgets", false, nil, @budgets_coordinates) %>
</div>
<ul class="no-bullet margin-top">
<% show_links = show_links_to_budget_investments(current_budget) %>
<% if show_links %>
<li>
<%= link_to budget_path(current_budget) do %>
<small><%= t("budgets.index.investment_proyects") %></small>
<% end %>
</li>
<% end %>
<li>
<%= link_to budget_path(current_budget, filter: "unfeasible") do %>
<small><%= t("budgets.index.unfeasible_investment_proyects") %></small>
<% end %>
</li>
<% if show_links %>
<li>
<%= link_to budget_path(current_budget, filter: "unselected") do %>
<small><%= t("budgets.index.not_selected_investment_proyects") %></small>
<% end %>
</li>
<% end %>
</ul>
<% end %>
</div>
</div>

View File

@@ -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| %>

View File

@@ -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.*"

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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")