diff --git a/app/assets/stylesheets/admin/search.css b/app/assets/stylesheets/admin/search.css index f4e818abd..0ece75fc5 100644 --- a/app/assets/stylesheets/admin/search.css +++ b/app/assets/stylesheets/admin/search.css @@ -1,6 +1,25 @@ .admin [role=search] { display: flex; + &.complex { + @include breakpoint(small only) { + flex-direction: column; + } + + @include breakpoint(medium) { + select { + height: $line-height * 2; + margin: 0 rem-calc(12); + } + } + } + + &:not(.complex) { + @include breakpoint(medium) { + width: 50%; + } + } + [type="submit"] { @include button($background: $link); border-radius: 0; @@ -10,8 +29,4 @@ @include button-disabled; } } - - @include breakpoint(medium) { - width: 50%; - } } diff --git a/app/components/admin/search_component.html.erb b/app/components/admin/search_component.html.erb index 0caf05d0e..0286dcb48 100644 --- a/app/components/admin/search_component.html.erb +++ b/app/components/admin/search_component.html.erb @@ -1,4 +1,5 @@ <%= form_tag(url, options) do |f| %> <%= text_field_tag :search, search_terms.to_s, placeholder: label, "aria-label": label %> + <%= content %> <%= submit_tag t("admin.shared.search.search") %> <% end %> diff --git a/app/components/sdg_management/relations/index_component.html.erb b/app/components/sdg_management/relations/index_component.html.erb index 43ba44b12..2cf9ca2be 100644 --- a/app/components/sdg_management/relations/index_component.html.erb +++ b/app/components/sdg_management/relations/index_component.html.erb @@ -1,6 +1,10 @@ <%= header %> -<%= render Admin::SearchComponent.new(label: search_label) %> +<%= render Admin::SearchComponent.new(label: search_label, class: "complex") do |component| %> + <%= component.select_tag :goal_code, goal_options, + include_blank: goal_blank_option, + "aria-label": goal_label %> +<% end %> diff --git a/app/components/sdg_management/relations/index_component.rb b/app/components/sdg_management/relations/index_component.rb index 16a49194c..97d3cb49d 100644 --- a/app/components/sdg_management/relations/index_component.rb +++ b/app/components/sdg_management/relations/index_component.rb @@ -29,4 +29,16 @@ class SDGManagement::Relations::IndexComponent < ApplicationComponent def search_label t("admin.shared.search.label.#{model_class.table_name}") end + + def goal_label + t("admin.shared.search.advanced_filters.sdg_goals.label") + end + + def goal_blank_option + t("admin.shared.search.advanced_filters.sdg_goals.all") + end + + def goal_options + options_from_collection_for_select(SDG::Goal.all, :code, :code_and_title, params[:goal_code]) + end end diff --git a/app/controllers/sdg_management/relations_controller.rb b/app/controllers/sdg_management/relations_controller.rb index 870dc5fd2..aa03f5d26 100644 --- a/app/controllers/sdg_management/relations_controller.rb +++ b/app/controllers/sdg_management/relations_controller.rb @@ -3,7 +3,11 @@ class SDGManagement::RelationsController < SDGManagement::BaseController before_action :load_record, only: [:edit, :update] def index - @records = relatable_class.accessible_by(current_ability).order(:id).page(params[:page]) + @records = relatable_class + .accessible_by(current_ability) + .by_goal(params[:goal_code]) + .order(:id) + .page(params[:page]) @records = @records.search(params[:search]) if params[:search].present? end diff --git a/app/models/concerns/sdg/relatable.rb b/app/models/concerns/sdg/relatable.rb index 50f9b0183..e552fbd96 100644 --- a/app/models/concerns/sdg/relatable.rb +++ b/app/models/concerns/sdg/relatable.rb @@ -12,6 +12,14 @@ module SDG::Relatable end end + class_methods do + def by_goal(code) + return all if code.blank? + + joins(:sdg_goals).merge(SDG::Goal.where(code: code)) + end + end + def related_sdgs sdg_relations.map(&:related_sdg) end diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml index 2acfdce7a..21041e674 100644 --- a/config/locales/en/admin.yml +++ b/config/locales/en/admin.yml @@ -1253,6 +1253,10 @@ en: true_value: "Yes" false_value: "No" search: + advanced_filters: + sdg_goals: + all: "All goals" + label: "By goal" label: booths: "Search booth by name or location" budget_investments: "Search investments by title, description or heading" diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml index 62bca513c..6ea9c3505 100644 --- a/config/locales/es/admin.yml +++ b/config/locales/es/admin.yml @@ -1252,6 +1252,10 @@ es: true_value: "Sí" false_value: "No" search: + advanced_filters: + sdg_goals: + all: "Todos los objetivos" + label: "Por objetivo" label: booths: "Buscar urna por nombre" budget_investments: "Buscar proyectos por título, descripción o partida" diff --git a/spec/models/sdg/relatable_spec.rb b/spec/models/sdg/relatable_spec.rb index d161d4ddb..8f1e210d9 100644 --- a/spec/models/sdg/relatable_spec.rb +++ b/spec/models/sdg/relatable_spec.rb @@ -116,4 +116,25 @@ describe SDG::Relatable do expect(relatable.reload.sdg_goals).to match_array [SDG::Goal[1], SDG::Goal[2]] end end + + describe ".by_goal" do + it "returns everything if no code is provided" do + expect(relatable.class.by_goal("")).to eq [relatable] + expect(relatable.class.by_goal(nil)).to eq [relatable] + end + + it "returns records associated with that goal" do + same_association = create(:proposal, sdg_goals: [goal]) + both_associations = create(:proposal, sdg_goals: [goal, another_goal]) + + expect(relatable.class.by_goal(goal.code)).to match_array [same_association, both_associations] + end + + it "does not return records not associated with that goal" do + create(:proposal) + create(:proposal, sdg_goals: [another_goal]) + + expect(relatable.class.by_goal(goal.code)).to be_empty + end + end end diff --git a/spec/system/sdg_management/relations_spec.rb b/spec/system/sdg_management/relations_spec.rb index c3c2bbb3f..3518617cd 100644 --- a/spec/system/sdg_management/relations_spec.rb +++ b/spec/system/sdg_management/relations_spec.rb @@ -88,17 +88,31 @@ describe "SDG Relations", :js do expect(page).to have_css "h2", exact_text: "Build a hospital" end - scenario "search" do - create(:poll, name: "Internet speech freedom") - create(:poll, name: "SDG interest") + describe "search" do + scenario "search by terms" do + create(:poll, name: "Internet speech freedom") + create(:poll, name: "SDG interest") - visit sdg_management_polls_path + visit sdg_management_polls_path - fill_in "search", with: "speech" - click_button "Search" + fill_in "search", with: "speech" + click_button "Search" - expect(page).to have_content "Internet speech freedom" - expect(page).not_to have_content "SDG interest" + expect(page).to have_content "Internet speech freedom" + expect(page).not_to have_content "SDG interest" + end + + scenario "goal filter" do + create(:budget_investment, title: "School", sdg_goals: [SDG::Goal[4]]) + create(:budget_investment, title: "Hospital", sdg_goals: [SDG::Goal[3]]) + + visit sdg_management_budget_investments_path + select "4. Quality Education", from: "goal_code" + click_button "Search" + + expect(page).to have_content "School" + expect(page).not_to have_content "Hospital" + end end end