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