mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-27 06:05:19 +00:00
Listen for changes on added fields
Finally, we can add new variants! Requires updated stimulus-rails-nested-form
This commit is contained in:
@@ -46,7 +46,8 @@
|
||||
%th.align-right= t('admin.products_page.columns.actions')
|
||||
- products.each_with_index do |product, product_index|
|
||||
= form.fields_for("products", product, index: product_index) do |product_form|
|
||||
%tbody.relaxed{ 'data-record-id': product_form.object.id, 'data-controller': "nested-form" }
|
||||
%tbody.relaxed{ data: { 'record-id': product_form.object.id, controller: "nested-form",
|
||||
action: 'nested-form:add->bulk-form#registerElements' } }
|
||||
%tr
|
||||
= render partial: 'product_row', locals: { product:, f: product_form }
|
||||
|
||||
|
||||
@@ -24,6 +24,15 @@ export default class BulkFormController extends Controller {
|
||||
window.removeEventListener("beforeunload", this.preventLeavingBulkForm);
|
||||
}
|
||||
|
||||
// Register any new elements (may be called by another controller after dynamically adding fields)
|
||||
registerElements() {
|
||||
const registeredElements = Object.values(this.recordElements).flat();
|
||||
// Select only elements that haven't been registered yet
|
||||
const newElements = Array.from(this.form.elements).filter(n => !registeredElements.includes(n));
|
||||
|
||||
this.#registerElements(newElements);
|
||||
}
|
||||
|
||||
toggleChanged(e) {
|
||||
const element = e.target;
|
||||
element.classList.toggle("changed", this.#isChanged(element));
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"shortcut-buttons-flatpickr": "^0.4.0",
|
||||
"stimulus": "^3.2.2",
|
||||
"stimulus-flatpickr": "^1.4.0",
|
||||
"stimulus-rails-nested-form": "https://github.com/dacook/stimulus-rails-nested-form.git#dist",
|
||||
"stimulus-rails-nested-form": "https://github.com/openfoodfoundation/stimulus-rails-nested-form.git#dist",
|
||||
"stimulus_reflex": "3.5.0-rc3",
|
||||
"tom-select": "^2.3.1",
|
||||
"trix": "^2.0.10",
|
||||
|
||||
@@ -181,6 +181,48 @@ describe("BulkFormController", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("Adding new fields", () => {
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML = `
|
||||
<form id="form" data-controller="bulk-form" data-action="custom-event->bulk-form#registerElements",
|
||||
<div data-record-id="1">
|
||||
<input id="input1a" type="text" value="initial1a">
|
||||
<template id="template">
|
||||
<input id="input1b" type="text" value="initial1b">
|
||||
</template>
|
||||
</div>
|
||||
<div data-record-id="2">
|
||||
<input id="input2" type="text" value="initial2">
|
||||
</div>
|
||||
<input type="submit">
|
||||
</form>
|
||||
`;
|
||||
});
|
||||
|
||||
describe("registerElements", () => {
|
||||
beforeEach(() => {
|
||||
// Add new field after controller has initialised
|
||||
input1a.insertAdjacentHTML("afterend", template.innerHTML);
|
||||
|
||||
// Trigger bulk-form#registerElements
|
||||
form.dispatchEvent(new Event("custom-event"));
|
||||
});
|
||||
|
||||
it("onInput", () => {
|
||||
input1b.value = 'updated1b';
|
||||
input1b.dispatchEvent(new Event("input"));
|
||||
// Expect only updated field to show changed
|
||||
expect(input1b.classList).toContain('changed');
|
||||
expect(input2.classList).not.toContain('changed');
|
||||
|
||||
// Change back to original value
|
||||
input1b.value = 'initial1b';
|
||||
input1b.dispatchEvent(new Event("input"));
|
||||
expect(input1b.classList).not.toContain('changed');
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
// unable to test disconnect at this stage
|
||||
// describe("disconnect()", () => {
|
||||
// it("resets other elements", () => {
|
||||
|
||||
@@ -357,7 +357,6 @@ describe 'As an admin, I can manage products', feature: :admin_style_v3 do
|
||||
fill_in "On Hand", with: "3"
|
||||
|
||||
expect {
|
||||
pending "changes are not detected"
|
||||
click_button "Save changes"
|
||||
|
||||
expect(page).to have_content "Changes saved"
|
||||
@@ -432,7 +431,6 @@ describe 'As an admin, I can manage products', feature: :admin_style_v3 do
|
||||
|
||||
it "saves changes after fixing errors" do
|
||||
expect {
|
||||
pending "changes are not detected"
|
||||
click_button "Save changes"
|
||||
|
||||
variant_a1.reload
|
||||
@@ -459,6 +457,125 @@ describe 'As an admin, I can manage products', feature: :admin_style_v3 do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "adding variants" do
|
||||
it "creates a new variant" do
|
||||
click_on "New variant"
|
||||
|
||||
# find empty row for Apples
|
||||
new_variant_row = find_field("Name", placeholder: "Apples", with: "").ancestor("tr")
|
||||
expect(new_variant_row).to be_present
|
||||
|
||||
within new_variant_row do
|
||||
fill_in "Name", with: "Large box"
|
||||
fill_in "SKU", with: "APL-02"
|
||||
fill_in "Unit", with: 1000
|
||||
fill_in "Price", with: 10.25
|
||||
click_on "On Hand" # activate popout
|
||||
end
|
||||
fill_in "On Hand", with: "3"
|
||||
|
||||
expect {
|
||||
click_button "Save changes"
|
||||
|
||||
expect(page).to have_content "Changes saved"
|
||||
product_a.reload
|
||||
}.to change { product_a.variants.count }.by(1)
|
||||
|
||||
new_variant = product_a.variants.last
|
||||
expect(new_variant.display_name).to eq "Large box"
|
||||
expect(new_variant.sku).to eq "APL-02"
|
||||
expect(new_variant.price).to eq 10.25
|
||||
expect(new_variant.unit_value).to eq 1000
|
||||
expect(new_variant.on_hand).to eq 3
|
||||
|
||||
within row_containing_name("Large box") do
|
||||
expect(page).to have_field "Name", with: "Large box"
|
||||
expect(page).to have_field "SKU", with: "APL-02"
|
||||
expect(page).to have_field "Price", with: "10.25"
|
||||
expect(page).to have_content "1kg"
|
||||
expect(page).to have_css "button[aria-label='On Hand']", text: "3"
|
||||
end
|
||||
end
|
||||
|
||||
context "with invalid data" do
|
||||
before do
|
||||
click_on "New variant"
|
||||
|
||||
# find empty row for Apples
|
||||
new_variant_row = find_field("Name", placeholder: "Apples", with: "").ancestor("tr")
|
||||
expect(new_variant_row).to be_present
|
||||
|
||||
within new_variant_row do
|
||||
fill_in "Name", with: "N" * 256 # too long
|
||||
fill_in "SKU", with: "n" * 256
|
||||
fill_in "Unit", with: "" # can't be blank
|
||||
fill_in "Price", with: "10.25" # valid
|
||||
end
|
||||
end
|
||||
|
||||
it "shows errors for both existing and new variant fields" do
|
||||
# Update existing variant with invalid data too
|
||||
within row_containing_name("Medium box") do
|
||||
fill_in "Name", with: "M" * 256
|
||||
fill_in "SKU", with: "m" * 256
|
||||
fill_in "Price", with: "10.25"
|
||||
end
|
||||
|
||||
expect {
|
||||
click_button "Save changes"
|
||||
|
||||
expect(page).to have_content "1 product could not be saved"
|
||||
expect(page).to have_content "Please review the errors and try again"
|
||||
variant_a1.reload
|
||||
}.to_not change { variant_a1.display_name }
|
||||
|
||||
# New variant
|
||||
within row_containing_name("N" * 256) do
|
||||
expect(page).to have_field "Name", with: "N" * 256
|
||||
expect(page).to have_field "SKU", with: "n" * 256
|
||||
expect(page).to have_content "is too long"
|
||||
expect(page).to have_field "Unit", with: ""
|
||||
expect(page).to have_content "can't be blank"
|
||||
expect(page).to have_field "Price", with: "10.25" # other updated value is retained
|
||||
end
|
||||
|
||||
# Existing variant
|
||||
within row_containing_name("M" * 256) do
|
||||
expect(page).to have_field "Name", with: "M" * 256
|
||||
expect(page).to have_field "SKU", with: "m" * 256
|
||||
expect(page).to have_content "is too long"
|
||||
end
|
||||
end
|
||||
|
||||
it "saves changes after fixing errors" do
|
||||
expect {
|
||||
click_button "Save changes"
|
||||
|
||||
variant_a1.reload
|
||||
}.to_not change { variant_a1.display_name }
|
||||
|
||||
within row_containing_name("N" * 256) do
|
||||
fill_in "Name", with: "Nice box"
|
||||
fill_in "SKU", with: "APL-02"
|
||||
fill_in "Unit", with: "200"
|
||||
end
|
||||
|
||||
expect {
|
||||
click_button "Save changes"
|
||||
|
||||
expect(page).to have_content "Changes saved"
|
||||
product_a.reload
|
||||
}.to change { product_a.variants.count }.by(1)
|
||||
|
||||
new_variant = product_a.variants.last
|
||||
expect(new_variant.display_name).to eq "Nice box"
|
||||
expect(new_variant.sku).to eq "APL-02"
|
||||
expect(new_variant.price).to eq 10.25
|
||||
expect(new_variant.unit_value).to eq 200
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "edit image" do
|
||||
|
||||
@@ -8350,9 +8350,9 @@ stimulus-flatpickr@^1.4.0:
|
||||
resolved "https://registry.yarnpkg.com/stimulus-flatpickr/-/stimulus-flatpickr-1.4.0.tgz#a41071a3e69cfc50b7eaaacf356fc0ab1ab0543c"
|
||||
integrity sha512-rcC/c9+E+f5W2kOjaaLShtf3i+p95ACqt+oGzSAgeuZh2YeIN8gW4EWO7h0STBLzSVPl6BjIfPWP7upMPavIVQ==
|
||||
|
||||
"stimulus-rails-nested-form@https://github.com/dacook/stimulus-rails-nested-form.git#dist":
|
||||
"stimulus-rails-nested-form@https://github.com/openfoodfoundation/stimulus-rails-nested-form.git#dist":
|
||||
version "4.1.0"
|
||||
resolved "https://github.com/dacook/stimulus-rails-nested-form.git#d3b82ea638a7156f1122736cf739ab1821a1817e"
|
||||
resolved "https://github.com/openfoodfoundation/stimulus-rails-nested-form.git#d3b82ea638a7156f1122736cf739ab1821a1817e"
|
||||
|
||||
stimulus@^3.2.2:
|
||||
version "3.2.2"
|
||||
|
||||
Reference in New Issue
Block a user