diff --git a/app/views/admin/products_v3/_product_row.html.haml b/app/views/admin/products_v3/_product_row.html.haml index 1d2c68eca3..e30b5200f9 100644 --- a/app/views/admin/products_v3/_product_row.html.haml +++ b/app/views/admin/products_v3/_product_row.html.haml @@ -10,6 +10,8 @@ = f.text_field :sku, 'aria-label': t('admin.products_page.columns.sku') = error_message_on product, :sku %td.multi-field{ 'data-controller': 'toggle-control', 'data-toggle-control-match-value': 'items' } + = f.hidden_field :variant_unit + = f.hidden_field :variant_unit_scale = f.select :variant_unit_with_scale, options_for_select(WeightsAndMeasures.variant_unit_options, product.variant_unit_with_scale), {}, diff --git a/app/views/admin/products_v3/_table.html.haml b/app/views/admin/products_v3/_table.html.haml index 5095f63a03..412bd5a2ce 100644 --- a/app/views/admin/products_v3/_table.html.haml +++ b/app/views/admin/products_v3/_table.html.haml @@ -54,7 +54,7 @@ - products.each_with_index do |product, product_index| = form.fields_for("products", product, index: product_index) do |product_form| %tbody.relaxed.naked_inputs{ data: { 'record-id': product_form.object.id, - controller: "nested-form", + controller: "nested-form product", action: 'rails-nested-form:add->bulk-form#registerElements' } } %tr = render partial: 'product_row', locals: { product:, f: product_form } diff --git a/app/webpacker/controllers/product_controller.js b/app/webpacker/controllers/product_controller.js new file mode 100644 index 0000000000..cb66b34d65 --- /dev/null +++ b/app/webpacker/controllers/product_controller.js @@ -0,0 +1,36 @@ +import { Controller } from "stimulus"; + +// Dynamically update related Product unit fields (expected to move to Variant due to Product Refactor) +// +export default class ProductController extends Controller { + connect() { + // idea: create a helper that includes a nice getter/setter for Rails model attr values, just pass it the attribute name. + // It could automatically find (and cache a ref to) each dom element and get/set the values. + this.variantUnit = this.element.querySelector('[name$="[variant_unit]"]'); + this.variantUnitScale = this.element.querySelector('[name$="[variant_unit_scale]"]'); + this.variantUnitWithScale = this.element.querySelector('[name$="[variant_unit_with_scale]"]'); + + // on variant_unit_with_scale changed; update variant_unit and variant_unit_scale + this.variantUnitWithScale.addEventListener("change", this.#updateUnitAndScale.bind(this), { + passive: true, + }); + } + + // private + + // Extract variant_unit and variant_unit_scale from dropdown variant_unit_with_scale, + // and update hidden product fields + #updateUnitAndScale(event) { + const variant_unit_with_scale = this.variantUnitWithScale.value; + const match = variant_unit_with_scale.match(/^([^_]+)_([\d\.]+)$/); // eg "weight_1000" + + if (match) { + this.variantUnit.value = match[1]; + this.variantUnitScale.value = parseFloat(match[2]); + } else { + // "items" + this.variantUnit.value = variant_unit_with_scale; + this.variantUnitScale.value = ""; + } + } +} diff --git a/spec/javascripts/stimulus/product_controller_test.js b/spec/javascripts/stimulus/product_controller_test.js new file mode 100644 index 0000000000..bcd4f8bdad --- /dev/null +++ b/spec/javascripts/stimulus/product_controller_test.js @@ -0,0 +1,56 @@ +/** + * @jest-environment jsdom + */ + +import { Application } from "stimulus"; +import product_controller from "../../../app/webpacker/controllers/product_controller"; + +describe("ProductController", () => { + beforeAll(() => { + const application = Application.start(); + application.register("product", product_controller); + }); + + describe("variant_unit_with_scale", () => { + beforeEach(() => { + document.body.innerHTML = ` +
+ + + +
+ `; + }); + + describe("change", () => { + it("weight_1000", () => { + variant_unit_with_scale.selectedIndex = 1; + variant_unit_with_scale.dispatchEvent(new Event("change")); + + expect(variant_unit.value).toBe("weight"); + expect(variant_unit_scale.value).toBe("1000"); + }); + + it("volume_4.54609", () => { + variant_unit_with_scale.selectedIndex = 2; + variant_unit_with_scale.dispatchEvent(new Event("change")); + + expect(variant_unit.value).toBe("volume"); + expect(variant_unit_scale.value).toBe("4.54609"); + }); + + it("items", () => { + variant_unit_with_scale.selectedIndex = 3; + variant_unit_with_scale.dispatchEvent(new Event("change")); + + expect(variant_unit.value).toBe("items"); + expect(variant_unit_scale.value).toBe(""); + }); + }) + }); +});