From a9d999fb230002883a629b87daa1863e84734d19 Mon Sep 17 00:00:00 2001 From: Josue Granados Date: Fri, 13 Oct 2023 17:47:46 -0600 Subject: [PATCH] Fix [Search pills] Counter bug and "All" buttons removed. (#478) * Fix (Search pills): All button. Removed all button feature because of users feedback. * Fix (Search pills): Pills counter bug. Refactored how pills were counted, added target to make the feature more roubust. * Removed select-all-checkbox yarn package. --- .../search_pills/button/component.rb | 1 + .../search_pills/component.html.slim | 104 +++++++++--------- app/components/search_pills/component.rb | 12 -- app/components/search_pills/pill/component.rb | 7 +- .../checkbox_select_all_controller.js | 20 ---- .../controllers/search_controller.js | 23 ++-- app/views/searches/_preview.html.slim | 2 +- package.json | 3 +- yarn.lock | 5 - 9 files changed, 69 insertions(+), 108 deletions(-) delete mode 100644 app/javascript/controllers/checkbox_select_all_controller.js diff --git a/app/components/search_pills/button/component.rb b/app/components/search_pills/button/component.rb index de6c433e6..c97945469 100644 --- a/app/components/search_pills/button/component.rb +++ b/app/components/search_pills/button/component.rb @@ -11,6 +11,7 @@ def initialize(name:, value:, checked:, copy:, options: {}) class: "hidden pill", id: SecureRandom.alphanumeric, data: { + search_target: "pill", action: "click->search#toggleRadioButton change->search#updateFiltersState change->search#submitForm", } } diff --git a/app/components/search_pills/component.html.slim b/app/components/search_pills/component.html.slim index 916b8442c..7c24fac11 100644 --- a/app/components/search_pills/component.html.slim +++ b/app/components/search_pills/component.html.slim @@ -1,56 +1,52 @@ div class="w-full bg-gray-9" - div data-search-target="pills" - div data-controller="tabs" data-tabs-active-tab=("border-b-4 border-blue-medium") - div class="flex" - / Clear-Counter button - span class="flex justify-center items-center w-14 pl-5 py-3 pr-2 text-xs bg-blue-pale" - span class="inline-flex hidden items-center px-1 py-0.5 border border-blue-medium rounded-full bg-white" data-search-target="pillsCounterWrapper" - span data-search-target="pillsCounter" class="mr-0.5" - button type="button" data-action="search#clearCheckedPills" - = inline_svg_tag "x-icon.svg", class: 'h-2 w-2 fill-current stroke-current stroke-1 text-blue-medium ml-1 relative' - = inline_svg_tag "solid_filters.svg", class: 'h-4 w-4 fill-current text-gray-2 -ml-0.5 relative', data: { 'search-target': "filtersIcon" } - / Tabs - ul class="flex flex-1 gap-x-6 pl-5 pr-6 text-sm list-none overflow-x-auto overflow-y-hidden bg-blue-pale text-gray-2" - - @tabs_labels.each do |tab_label| - li data-action="click->tabs#change" data-tabs-target="tab" - a class="inline-block py-3 whitespace-nowrap" href="#" = tab_label - li data-action="click->modal#open" - button class="inline-block py-3 whitespace-nowrap" type="button" id="advanced-filters-button" - | Advanced Filters - span class="relative hidden w-2 h-2 rounded-full bg-salmon ml-1 mb-2" id="appliedIcon" + div data-controller="tabs" data-tabs-active-tab=("border-b-4 border-blue-medium") + div class="flex" + / Clear-Counter button + span class="flex justify-center items-center w-14 pl-5 py-3 pr-2 text-xs bg-blue-pale" + span class="inline-flex hidden items-center px-1 py-0.5 border border-blue-medium rounded-full bg-white" data-search-target="pillsCounterWrapper" + span data-search-target="pillsCounter" class="mr-0.5" + button type="button" data-action="search#clearCheckedPills" + = inline_svg_tag "x-icon.svg", class: 'h-2 w-2 fill-current stroke-current stroke-1 text-blue-medium ml-1 relative' + = inline_svg_tag "solid_filters.svg", class: 'h-4 w-4 fill-current text-gray-2 -ml-0.5 relative', data: { 'search-target': "filtersIcon" } + / Tabs + ul class="flex flex-1 gap-x-6 pl-5 pr-6 text-sm list-none overflow-x-auto overflow-y-hidden bg-blue-pale text-gray-2" + - @tabs_labels.each do |tab_label| + li data-action="click->tabs#change" data-tabs-target="tab" + a class="inline-block py-3 whitespace-nowrap" href="#" = tab_label + li data-action="click->modal#open" + button class="inline-block py-3 whitespace-nowrap" type="button" id="advanced-filters-button" + | Advanced Filters + span class="relative hidden w-2 h-2 rounded-full bg-salmon ml-1 mb-2" id="appliedIcon" - / Panels - div class="bg-white" - / Causes - div class="flex flex-wrap gap-x-2 gap-y-3 hidden max-h-28 py-4 px-6 border-l border-b border-r overflow-y-auto" data-controller="checkbox-select-all" data-tabs-target="panel" - = render SearchPills::Pill::Component.new(name: "causes_all", value: 'All', checked: all_causes_checked?, options: { data: { checkbox_select_all_target: "checkboxAll", action: "change->checkbox-select-all#toggle" }}) - - @causes.each do |cause| - = render SearchPills::Pill::Component.new(name: "search[causes][]", value: cause.name, checked: @params.dig(:search, :causes)&.include?(cause.name), options: { multiple: true, data: { action: "change->checkbox-select-all#refresh", checkbox_select_all_target: "checkbox"}}) - = render SearchPills::MoreFiltersButton::Component.new - / Location - div class="flex flex-col hidden border-b md:flex-row md:items-center" data-tabs-target="panel" - div class="py-4 pl-6 text-gray-2 text-sm" - span class="inline-flex items-center" - = inline_svg_tag "location-dot.svg", class: "h-3 w-3 fill-current text-blue-medium mr-1" - | Nashville - div class="flex w-full md:w-auto md:py-3.5 md:pl-7" - - @radii_in_miles.each do |radius| - = render SearchPills::Button::Component.new(name: "search[distance]", value: miles_to_km(radius), checked: @params.dig(:search, :distance) == miles_to_km(radius).to_s, copy: radius == "Any" ? radius : "#{radius} mi") - / Services - div class="flex flex-wrap gap-x-2 gap-y-3 hidden max-h-28 py-4 px-6 border-l border-b border-r overflow-y-auto" data-controller="checkbox-select-all" data-tabs-target="panel" - = render SearchPills::Pill::Component.new(name: "services_all", value: 'All', checked: all_services_checked?, options: { data: { checkbox_select_all_target: "checkboxAll", action: "change->checkbox-select-all#toggle" }}) - - @services.each do |service| - = render SearchPills::Pill::Component.new(name: "search[services][#{service.cause.name}][]", value: service.name, checked: @params.dig('search', 'services', service.cause.name)&.include?(service.name), options: { multiple: true, data: { action: 'change->checkbox-select-all#refresh', checkbox_select_all_target: 'checkbox'}}) - = render SearchPills::MoreFiltersButton::Component.new - / Populations Served - div class="flex flex-wrap gap-x-2 gap-y-3 hidden max-h-28 py-4 px-6 border-l border-b border-r overflow-y-auto" data-controller="checkbox-select-all" data-tabs-target="panel" - = render SearchPills::Pill::Component.new(name: "groups_all", value: 'All', checked: all_beneficiary_subcategories_checked?, options: { data: { checkbox_select_all_target: "checkboxAll", action: "change->checkbox-select-all#toggle" }}) - - @beneficiary_subcategories.each do |subcategory| - = render SearchPills::Pill::Component.new(name: "search[beneficiary_groups][#{subcategory.beneficiary_group.name}][]", value: subcategory.name, checked: @params.dig('search', 'beneficiary_groups', subcategory.beneficiary_group.name)&.include?(subcategory.name), options: { multiple: true, data: { action: 'change->checkbox-select-all#refresh', checkbox_select_all_target: 'checkbox'}}) - = render SearchPills::MoreFiltersButton::Component.new - / Hours - div class="flex hidden gap-x-2 w-full py-4 px-6 border-l border-b border-r" data-tabs-target="panel" - = render SearchPills::Pill::Component.new(name: "search[open_now]", value: true, checked: @params.dig('search', 'open_now') == 'true') do - | Open Now - = render SearchPills::Pill::Component.new(name: "search[open_weekends]", value: true, checked: @params.dig('search', 'open_weekends') == 'true') do - | Open Weekends + / Panels + div class="bg-white" + / Causes + div class="flex flex-wrap gap-x-2 gap-y-3 hidden max-h-28 py-4 px-6 border-l border-b border-r overflow-y-auto" data-tabs-target="panel" + - @causes.each do |cause| + = render SearchPills::Pill::Component.new(name: "search[causes][]", value: cause.name, checked: @params.dig(:search, :causes)&.include?(cause.name), options: { multiple: true }) + = render SearchPills::MoreFiltersButton::Component.new + / Location + div class="flex flex-col hidden border-b md:flex-row md:items-center" data-tabs-target="panel" + div class="py-4 pl-6 text-gray-2 text-sm" + span class="inline-flex items-center" + = inline_svg_tag "location-dot.svg", class: "h-3 w-3 fill-current text-blue-medium mr-1" + | Nashville + div class="flex w-full md:w-auto md:py-3.5 md:pl-7" + - @radii_in_miles.each do |radius| + = render SearchPills::Button::Component.new(name: "search[distance]", value: miles_to_km(radius), checked: @params.dig(:search, :distance) == miles_to_km(radius).to_s, copy: radius == "Any" ? radius : "#{radius} mi") + / Services + div class="flex flex-wrap gap-x-2 gap-y-3 hidden max-h-28 py-4 px-6 border-l border-b border-r overflow-y-auto" data-tabs-target="panel" + - @services.each do |service| + = render SearchPills::Pill::Component.new(name: "search[services][#{service.cause.name}][]", value: service.name, checked: @params.dig('search', 'services', service.cause.name)&.include?(service.name), options: { multiple: true }) + = render SearchPills::MoreFiltersButton::Component.new + / Populations Served + div class="flex flex-wrap gap-x-2 gap-y-3 hidden max-h-28 py-4 px-6 border-l border-b border-r overflow-y-auto" data-tabs-target="panel" + - @beneficiary_subcategories.each do |subcategory| + = render SearchPills::Pill::Component.new(name: "search[beneficiary_groups][#{subcategory.beneficiary_group.name}][]", value: subcategory.name, checked: @params.dig('search', 'beneficiary_groups', subcategory.beneficiary_group.name)&.include?(subcategory.name), options: { multiple: true }) + = render SearchPills::MoreFiltersButton::Component.new + / Hours + div class="flex hidden gap-x-2 w-full py-4 px-6 border-l border-b border-r" data-tabs-target="panel" + = render SearchPills::Pill::Component.new(name: "search[open_now]", value: true, checked: @params.dig('search', 'open_now') == 'true') do + | Open Now + = render SearchPills::Pill::Component.new(name: "search[open_weekends]", value: true, checked: @params.dig('search', 'open_weekends') == 'true') do + | Open Weekends diff --git a/app/components/search_pills/component.rb b/app/components/search_pills/component.rb index 5fe666419..731619b41 100644 --- a/app/components/search_pills/component.rb +++ b/app/components/search_pills/component.rb @@ -9,18 +9,6 @@ def initialize(causes:, services:, beneficiary_subcategories:, params:) @radii_in_miles = [2, 5, 15, 30, 60, 180, "Any"] end - def all_causes_checked? - @causes.all? { |cause| @params.dig(:search, :causes)&.include?(cause.name) } - end - - def all_services_checked? - @services.all? { |service| @params.dig(:search, :services, service.cause.name)&.include?(service.name) } - end - - def all_beneficiary_subcategories_checked? - @beneficiary_subcategories.all? { |subcategory| @params.dig(:search, :beneficiary_groups, subcategory.beneficiary_group.name)&.include?(subcategory.name) } - end - def miles_to_km(miles) miles == "Any" ? 1_000_000 : (miles * 1.609344).round(3) end diff --git a/app/components/search_pills/pill/component.rb b/app/components/search_pills/pill/component.rb index b1f0d10ee..698ddece3 100644 --- a/app/components/search_pills/pill/component.rb +++ b/app/components/search_pills/pill/component.rb @@ -8,9 +8,12 @@ def initialize(name:, value: , checked:, options: { data: {action: ''}}) @options = options.merge( { class: 'hidden pill', - id: SecureRandom.alphanumeric + id: SecureRandom.alphanumeric, + data: { + search_target: "pill", + action: "change->places#hidePopup change->search#updateFiltersState change->search#submitForm" + } } ) - @options[:data][:action] << ' change->places#hidePopup change->search#updateFiltersState change->search#submitForm' end end diff --git a/app/javascript/controllers/checkbox_select_all_controller.js b/app/javascript/controllers/checkbox_select_all_controller.js deleted file mode 100644 index 5e2d4e2cf..000000000 --- a/app/javascript/controllers/checkbox_select_all_controller.js +++ /dev/null @@ -1,20 +0,0 @@ -import CheckboxSelectAll from 'stimulus-checkbox-select-all' - -export default class extends CheckboxSelectAll { - - connect() { - } - - disconnect() { - } - - toggle(e) { - this.checkboxTargets.forEach(checkbox => { - checkbox.checked = e.target.checked - }) - } - - refresh() { - this.checkboxAllTarget.checked = this.checked.length === this.checkboxTargets.length - } -} diff --git a/app/javascript/controllers/search_controller.js b/app/javascript/controllers/search_controller.js index 08f365fee..e75716321 100644 --- a/app/javascript/controllers/search_controller.js +++ b/app/javascript/controllers/search_controller.js @@ -7,7 +7,7 @@ export default class extends Controller { "input", "customInput", "form", - "pills", + "pill", "advancedFilters", "pillsCounter", "pillsCounterWrapper", @@ -34,10 +34,10 @@ export default class extends Controller { // Unchecks applied advanced filters firing their data-actions, // which clear displayed badges (see select_multiple_controller.js:15 and select-multiple component). this.advancedFiltersTarget.querySelectorAll("input:checked").forEach(input => input.click()) - this.pillsTarget.querySelectorAll("input:checked").forEach(input => { - input.checked = false - input.removeAttribute('checked') - }) + this.pillTargets.forEach(input => { + input.checked = false; + input.removeAttribute('checked'); + }); this.updateFiltersState() this.submitForm() @@ -54,17 +54,17 @@ export default class extends Controller { } countPills() { - // selects all checked inputs that are not checkboxAll - this.totalChecked = document.querySelectorAll("input:checked").length - 1; - this.pillsCounterTarget.textContent = this.totalChecked + const checkedPills = this.pillTargets.filter(pill => pill.checked); + this.pillsCounterTarget.textContent = checkedPills.length; + return checkedPills.length; } submitForm() { this.formTarget.requestSubmit() } - displayPillsCounter() { - if (this.totalChecked > 0) { + displayPillsCounter(checkedPillsCount) { + if (checkedPillsCount > 0) { this.pillsCounterWrapperTarget.classList.remove("hidden") this.filtersIconTarget.classList.add("hidden") } @@ -75,8 +75,7 @@ export default class extends Controller { } updatePillsCounter() { - this.countPills() - this.displayPillsCounter() + this.displayPillsCounter(this.countPills()); } updateFiltersState() { diff --git a/app/views/searches/_preview.html.slim b/app/views/searches/_preview.html.slim index 5d961d02f..efe0cfd00 100644 --- a/app/views/searches/_preview.html.slim +++ b/app/views/searches/_preview.html.slim @@ -11,7 +11,7 @@ = render SearchBar::Component.new(form: f, search: @search) = turbo_frame_tag "search-pills", src: local_assigns[:src] do div class="w-full bg-gray-9" - div data-search-target="pills" + div div data-tabs-active-tab=("border-b-4 border-blue-medium") div class="flex pb-14 bg-white border-b" / Clear-Counter button diff --git a/package.json b/package.json index 8bdcafb90..a912625f6 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,6 @@ "postcss": "^8", "selectize": "0.12.4", "stimulus-carousel": "^4.0.0", - "stimulus-checkbox-select-all": "^5.1.0", "stimulus-use": "^0.50.0-2", "swiper": "6.8.4", "tailwindcss": "npm:@tailwindcss/postcss7-compat", @@ -30,4 +29,4 @@ "devDependencies": { "webpack-dev-server": "^3.11.2" } -} \ No newline at end of file +} diff --git a/yarn.lock b/yarn.lock index 4744be308..ae775a8ea 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6777,11 +6777,6 @@ stimulus-carousel@^4.0.0: dependencies: swiper "^7.4.1" -stimulus-checkbox-select-all@^5.1.0: - version "5.1.0" - resolved "https://registry.npmjs.org/stimulus-checkbox-select-all/-/stimulus-checkbox-select-all-5.1.0.tgz" - integrity sha512-YXhPEhvEN81+d2nYhEe9ZLxuHTWw+R57q/AOip0T8kpnPCIWM3cezIYFZK5HNNLf2XpkfPCzuM7bQI8b/xkfGg== - stimulus-use@^0.50.0-2: version "0.50.0-2" resolved "https://registry.npmjs.org/stimulus-use/-/stimulus-use-0.50.0-2.tgz"