diff --git a/app/controllers/product_drive_participants_controller.rb b/app/controllers/product_drive_participants_controller.rb index 9925d4a05d..211287394f 100644 --- a/app/controllers/product_drive_participants_controller.rb +++ b/app/controllers/product_drive_participants_controller.rb @@ -3,14 +3,12 @@ class ProductDriveParticipantsController < ApplicationController include Importable - # TODO: Should there be a :destroy action for this? - def index - @product_drive_participants = current_organization.product_drive_participants.includes(:donations).with_volumes.order(:business_name) + @products = View::ProductDriveParticipants.new(params: params, organization: current_organization) respond_to do |format| format.html - format.csv { send_data ProductDriveParticipant.generate_csv(@product_drive_participants), filename: "ProductDriveParticipants-#{Time.zone.today}.csv" } + format.csv { send_data ProductDriveParticipant.generate_csv(@products.participants), filename: "ProductDriveParticipants-#{Time.zone.today}.csv" } end end @@ -65,6 +63,8 @@ def product_drive_participant_params helper_method \ def filter_params - {} + return {} unless params.key?(:filters) + + params.require(:filters).permit(:by_business_name, :by_contact_name) end end diff --git a/app/models/product_drive_participant.rb b/app/models/product_drive_participant.rb index dc1ab6823e..7606c6798d 100644 --- a/app/models/product_drive_participant.rb +++ b/app/models/product_drive_participant.rb @@ -18,8 +18,9 @@ class ProductDriveParticipant < ApplicationRecord has_paper_trail - include Provideable + include Filterable include Geocodable + include Provideable has_many :donations, inverse_of: :product_drive_participant, dependent: :destroy @@ -30,6 +31,8 @@ class ProductDriveParticipant < ApplicationRecord validates :comment, length: { maximum: 500 } scope :alphabetized, -> { order(:contact_name) } + scope :by_business_name, ->(business_name) { where("business_name ILIKE ?", "%#{business_name}%") } + scope :by_contact_name, ->(contact_name) { where("contact_name ILIKE ?", "%#{contact_name}%") } scope :with_volumes, -> { left_joins(donations: :line_items) .select("product_drive_participants.*, SUM(COALESCE(line_items.quantity, 0)) AS volume") diff --git a/app/models/view/product_drive_participants.rb b/app/models/view/product_drive_participants.rb new file mode 100644 index 0000000000..95287cf4ed --- /dev/null +++ b/app/models/view/product_drive_participants.rb @@ -0,0 +1,33 @@ +module View + class ProductDriveParticipants + attr_reader :filters, :params, :participants + + def initialize(params:, organization:) + @params = params + @filters = filter_params(params) + + @participants = organization + .product_drive_participants + .includes(:donations) + .with_volumes + .class_filter(filters) + .order(:business_name) + end + + def filter_params(params = {}) + if params.key?(:filters) + params.require(:filters).permit(:by_business_name, :by_contact_name) + else + {} + end + end + + def selected_business_name + filters[:by_business_name] + end + + def selected_contact_name + filters[:by_contact_name] + end + end +end diff --git a/app/views/product_drive_participants/index.html.erb b/app/views/product_drive_participants/index.html.erb index 8fe5864221..2e471df069 100644 --- a/app/views/product_drive_participants/index.html.erb +++ b/app/views/product_drive_participants/index.html.erb @@ -22,6 +22,36 @@ +
+
+
+
+
+

Product Drive Participants Filters

+
+
+ <%= form_tag(product_drive_participants_path, method: :get) do |f| %> +
+
+ <%= filter_text(label: "Filter By Business Name", scope: :by_business_name, selected: @products.selected_business_name) %> +
+
+ <%= filter_text(label: "Filter By Contact Name", scope: :by_contact_name, selected: @products.selected_contact_name) %> +
+
+
+ + <% end %> +
+
+
+
+
+
+
@@ -31,8 +61,8 @@
diff --git a/spec/models/product_drive_participant_spec.rb b/spec/models/product_drive_participant_spec.rb index 94abe444bd..6af8b0b7d8 100644 --- a/spec/models/product_drive_participant_spec.rb +++ b/spec/models/product_drive_participant_spec.rb @@ -49,6 +49,26 @@ expect(subject.first.volume).to eq(10) end end + + describe ".by_business_name" do + it "returns the product drive participant with a given business name" do + cats_biz = create(:product_drive_participant, business_name: "Cats") + another_cats_biz = create(:product_drive_participant, business_name: "I like cats") + create(:product_drive_participant, business_name: "Dogs") + + expect(ProductDriveParticipant.by_business_name("Cats")).to match_array([cats_biz, another_cats_biz]) + end + end + + describe ".by_contact_name" do + it "returns the product drive participant with a given contact name" do + eleanor = create(:product_drive_participant, contact_name: "Eleanor Shellstrop") + donna = create(:product_drive_participant, contact_name: "Donna Shellstrop") + create(:product_drive_participant, contact_name: "Jason Mendoza") + + expect(ProductDriveParticipant.by_contact_name("Shellstrop")).to match_array([eleanor, donna]) + end + end end context "Methods" do diff --git a/spec/models/view/product_drive_participants_spec.rb b/spec/models/view/product_drive_participants_spec.rb new file mode 100644 index 0000000000..7e295f0f14 --- /dev/null +++ b/spec/models/view/product_drive_participants_spec.rb @@ -0,0 +1,21 @@ +RSpec.describe View::ProductDriveParticipants do + describe "selected filter params" do + it "returns the given filter params" do + organization = build(:organization) + build(:product_drive_participant, organization:) + params = ActionController::Parameters.new( + { + filters: { + by_business_name: "The Good Place", + by_contact_name: "Jason Mendoza" + } + } + ).permit! + + requests = View::ProductDriveParticipants.new(params:, organization:) + + expect(requests.selected_business_name).to eq("The Good Place") + expect(requests.selected_contact_name).to eq("Jason Mendoza") + end + end +end diff --git a/spec/requests/product_drive_participants_requests_spec.rb b/spec/requests/product_drive_participants_requests_spec.rb index 54b17fccee..aef3edf32d 100644 --- a/spec/requests/product_drive_participants_requests_spec.rb +++ b/spec/requests/product_drive_participants_requests_spec.rb @@ -2,7 +2,7 @@ let(:organization) { create(:organization) } let(:user) { create(:user, organization: organization) } - context "While signed in" do + context "when signed in" do before do sign_in(user) end @@ -25,6 +25,44 @@ let(:response_format) { 'csv' } it { is_expected.to be_successful } + + it "exports the filtered results" do + create(:product_drive_participant, business_name: "A business named after cats") + create(:product_drive_participant, business_name: "Dogs are cool") + + get product_drive_participants_path(format: :csv, params: {filters: { by_business_name: 'cats'}}) + + csv = CSV.parse(response.body, headers: true) + + expect(csv.count).to eq(1) + expect(csv.first["Business Name"]).to eq("A business named after cats") + end + end + + context "when filtering by business name" do + it 'displays only results that matches the business name' do + create(:product_drive_participant, business_name: "A business named after cats") + create(:product_drive_participant, business_name: "Dogs are cool") + + get product_drive_participants_path(filters: {by_business_name: 'Cats'}) + + expect(response).to be_successful + expect(response.body).to include("Cats") + expect(response.body).not_to include("Dogs") + end + end + + context "when filtering by contact name" do + it 'displays only results that matches the contact name' do + create(:product_drive_participant, contact_name: "Bob Cat") + create(:product_drive_participant, contact_name: "Freddie the dog") + + get product_drive_participants_path(filters: {by_contact_name: 'Cats'}) + + expect(response).to be_successful + expect(response.body).to include("Cats") + expect(response.body).not_to include("Dogs") + end end end