diff --git a/app/views/admin/products_v3/_variant_row.html.haml b/app/views/admin/products_v3/_variant_row.html.haml index 7136d16b79..7255683347 100644 --- a/app/views/admin/products_v3/_variant_row.html.haml +++ b/app/views/admin/products_v3/_variant_row.html.haml @@ -69,5 +69,5 @@ = t('admin.products_page.actions.delete') - else = f.hidden_field :_destroy - %a{ 'data-action': "nested-form#remove" } + %a{ 'data-action': "nested-form#remove bulk-form#remove", class: 'delete', 'data-temp_id': f.field_id(:remove_link) } = t('admin.products_page.actions.remove') diff --git a/app/webpacker/controllers/bulk_form_controller.js b/app/webpacker/controllers/bulk_form_controller.js index 54a8a812df..c3c73294ae 100644 --- a/app/webpacker/controllers/bulk_form_controller.js +++ b/app/webpacker/controllers/bulk_form_controller.js @@ -91,6 +91,40 @@ export default class BulkFormController extends Controller { } } + // Removes tr from DOM as well as corresponding elmnts from recordElement + // when clicking on 'Remove' button. For not persisted rows removed by + // stimulus components lib. + remove(event) { + // We need the temp id for the newly non persisted variant + let elmnt = event.target; + const recordContainer = elmnt.closest("[data-record-id]"); + let recordId = recordContainer.dataset.recordId; + let elmnt_temp_id = elmnt.dataset.temp_id; + const re = /([0-9]*)_remove_link/; + let temp_id = elmnt_temp_id.match(re)[1] + + // Store indexes and not elements + let elmntsToDelete = []; + this.recordElements[recordId].forEach((item, index) => { + if ((item.id).includes(temp_id)) { + elmntsToDelete.push(index); + } + }); + + + // Want to delete ary.last - ary.first ie from to first up to last index + // In this way, we also delete unnecessary elements without reference to temp variant(id) + // like buttons but nonetheless part of the elements to be removed. + this.recordElements[recordId] + .splice(elmntsToDelete[0], elmntsToDelete[elmntsToDelete.length - 1] - elmntsToDelete[0] + 1); + this.toggleFormChanged(); + + // Otherwise, elements within tr may be re-added to recordElements. + // With the nested-form-wrapper(stimulus components) class added to a tr. + let tr = document.querySelector('.nested-form-wrapper[style="display: none;"]') + tr.remove(); + } + // private #registerSubmit() { diff --git a/spec/system/admin/products_v3/products_spec.rb b/spec/system/admin/products_v3/products_spec.rb index 5ed433daa3..8665039568 100644 --- a/spec/system/admin/products_v3/products_spec.rb +++ b/spec/system/admin/products_v3/products_spec.rb @@ -216,6 +216,16 @@ RSpec.describe 'As an enterprise user, I can manage my products', feature: :admi create(:simple_product, name: "Apples", sku: "APL-00", variant_unit: "weight", variant_unit_scale: 1) # Grams } + let(:variant_b1) { + product_b.variants.first.tap{ |v| + v.update! display_name: "Medium box", sku: "TMT-01", price: 5, on_hand: 5, + on_demand: false + } + } + let(:product_b) { + create(:simple_product, name: "Tomatoes", sku: "TMT-01", + variant_unit: "weight", variant_unit_scale: 1) # Grams + } before do visit admin_products_url end @@ -553,11 +563,98 @@ RSpec.describe 'As an enterprise user, I can manage my products', feature: :admi fill_in "Name", with: "Large box" fill_in "SKU", with: "APL-02" expect(page).to have_field("Name", placeholder: "Apples", with: "Large box") + end + + expect(page).to have_text("1 product modified.") + expect(page).to have_css('form.disabled-section#filters') # ie search/sort disabled + + within new_variant_row do page.find(".vertical-ellipsis-menu").click page.find('a', text: 'Remove').click end expect(page).not_to have_field("Name", placeholder: "Apples", with: "Large box") + expect(page).not_to have_text("1 product modified.") + expect(page).not_to have_css('form.disabled-section#filters') + end + + it "removes newly added not persistent Variants one at a time" do + click_on "New variant" + + first_new_variant_row = find_field("Name", placeholder: "Apples", with: "").ancestor("tr") + within first_new_variant_row do + fill_in "Name", with: "Large box" + end + + click_on "New variant" + second_new_variant_row = find_field("Name", placeholder: "Apples", with: "").ancestor("tr") + within second_new_variant_row do + fill_in "Name", with: "Huge box" + end + + expect(page).to have_text("1 product modified.") + expect(page).to have_css('form.disabled-section#filters') + + within first_new_variant_row do + page.find(".vertical-ellipsis-menu").click + page.find('a', text: 'Remove').click + end + + expect(page).to have_text("1 product modified.") + + within second_new_variant_row do + page.find(".vertical-ellipsis-menu").click + page.find('a', text: 'Remove').click + end + # Only when all non persistent variants are gone that product is non modified + expect(page).not_to have_text("1 product modified.") + expect(page).not_to have_css('form.disabled-section#filters') + end + + context "With 2 products" do + before do + variant_b1 + # To add 2nd product on page + page.refresh + end + + it "removes newly added Variants across products" do + click_on "New variant" + apples_new_variant_row = + find_field("Name", placeholder: "Apples", with: "").ancestor("tr") + within apples_new_variant_row do + fill_in "Name", with: "Large box" + end + + tomatoes_part = page.all('tbody')[1] + within tomatoes_part do + click_on "New variant" + end + tomatoes_new_variant_row = + find_field("Name", placeholder: "Tomatoes", with: "").ancestor("tr") + within tomatoes_new_variant_row do + fill_in "Name", with: "Huge box" + end + expect(page).to have_text("2 products modified.") + expect(page).to have_css('form.disabled-section#filters') # ie search/sort disabled + + within apples_new_variant_row do + page.find(".vertical-ellipsis-menu").click + page.find('a', text: 'Remove').click + end + # New variant for apples is no more, expect only 1 modified product + expect(page).to have_text("1 product modified.") + # search/sort still disabled + expect(page).to have_css('form.disabled-section#filters') + + within tomatoes_new_variant_row do + page.find(".vertical-ellipsis-menu").click + page.find('a', text: 'Remove').click + end + # Back to page without any alteration + expect(page).not_to have_text("1 product modified.") + expect(page).not_to have_css('form.disabled-section#filters') + end end context "with invalid data" do