Add OutOfStockModalComponent

It encapsulate the logic for the out of stock modal
This commit is contained in:
Gaetan Craig-Riou
2025-02-17 16:53:59 +11:00
parent 9d59f87b30
commit 4a2f22e56d
5 changed files with 128 additions and 1 deletions

View File

@@ -1,4 +1,4 @@
// please update the modal html in app/view/checkout/edit.html.haml if updating this template
// please update the modal html in app/components/out_of_stock_modal_component/out_of_stock_modal_component.html.haml if updating this template
%a.close-reveal-modal{"ng-click" => "$close()"}
%i.ofn-i_009-close

View File

@@ -0,0 +1,10 @@
# frozen_string_literal: true
class OutOfStockModalComponent < ModalComponent
def initialize(id:, variants: [], redirect: false)
super(id:, modal_class: "medium", instant: true)
@variants = variants
@redirect = redirect
end
end

View File

@@ -0,0 +1,26 @@
%div{ id: @id, "data-controller": "modal out-of-stock-modal", "data-action": "keyup@document->modal#closeIfEscapeKey modal:closing->out-of-stock-modal#redirect", "data-modal-instant-value": @instant, "data-out-of-stock-modal-redirect-value": @redirect }
.reveal-modal-bg.fade{ "data-modal-target": "background", "data-action": "click->modal#close" }
.reveal-modal.fade.modal-component{ "data-modal-target": "modal", class: @modal_class }
- # please update app/assets/javascripts/templates/out_of_stock.html.haml if updating this view
%a.close-reveal-modal{"data-action": "click->modal#close" }
%i.ofn-i_009-close
%h3
= t("js.out_of_stock.reduced_stock_available")
%p
= t("js.out_of_stock.out_of_stock_text")
- @variants.each do |variant|
- if variant.on_hand == 0
%p
%em
= "#{variant.name_to_display} - #{variant.unit_to_display}"
%span
= t("js.out_of_stock.now_out_of_stock")
- if variant.on_hand > 0
%p
%em
= "#{variant.name_to_display} - #{variant.unit_to_display}"
%span
= t("js.out_of_stock.only_n_remaining", num: variant.on_hand)
.text-center
%input{ class: "button icon-plus #{close_button_class}", type: 'button', value: t('js.admin.modals.close'), "data-action": "click->modal#close" }

View File

@@ -0,0 +1,19 @@
import { Controller } from "stimulus";
// This is meant to be used with the "modal:closing" event, ie:
//
// <div data-controller="out-of-stock-modal"
// data-action="moda:closing@out-of-stock-modal#redirect"
// data-out-of-stock-modal-redirect-value="true"
// >
// </div>
//
export default class extends Controller {
static values = { redirect: { type: Boolean, default: false } };
redirect() {
if (this.redirectValue) {
window.location.pathname = "/shop";
}
}
}

View File

@@ -0,0 +1,72 @@
/**
* @jest-environment jsdom
*/
import { Application } from "stimulus";
import out_of_stock_modal_controller from "../../../app/webpacker/controllers/out_of_stock_modal_controller";
describe("OutOfStockModalController", () => {
beforeAll(() => {
const application = Application.start();
application.register("out-of-stock-modal", out_of_stock_modal_controller);
});
let originalWindowLocation = window.location;
beforeEach(() => {
Object.defineProperty(window, "location", {
configurable: true,
enumerable: true,
value: new URL(window.location.href),
});
});
afterEach(() => {
Object.defineProperty(window, "location", {
configurable: true,
enumerable: true,
value: originalWindowLocation,
});
});
// We use window to dispatch the closing event so we don't need to set up another controller
describe("#redirect", () => {
describe("when redirect value is false", () => {
beforeEach(() => {
document.body.innerHTML = `
<div data-controller="out-of-stock-modal"
data-action="closing@window->out-of-stock-modal#redirect"
data-out-of-stock-modal-redirect-value="false"
>
</div>
`;
});
it("does not redirect", () => {
const event = new Event("closing");
window.dispatchEvent(event);
expect(window.location.href).not.toBe("/shop");
});
});
describe("when redirect value is true", () => {
beforeEach(() => {
document.body.innerHTML = `
<div data-controller="out-of-stock-modal"
data-action="closing@window->out-of-stock-modal#redirect"
data-out-of-stock-modal-redirect-value="true"
>
</div>
`;
});
it("redirects to /shop", () => {
const event = new Event("closing");
window.dispatchEvent(event);
expect(window.location.pathname).toBe("/shop");
});
});
});
});