diff --git a/admin/app/components/solidus_admin/layout/confirm/component.js b/admin/app/components/solidus_admin/layout/confirm/component.js
new file mode 100644
index 00000000000..49e447b0b86
--- /dev/null
+++ b/admin/app/components/solidus_admin/layout/confirm/component.js
@@ -0,0 +1,21 @@
+import { Controller } from "@hotwired/stimulus"
+
+export default class extends Controller {
+ static targets = ["accept"]
+
+ open(message, { details = "", buttonText } = {}) {
+ const dialog = this.element.querySelector("dialog")
+
+ dialog.querySelector(".modal-title").textContent = message
+ dialog.querySelector(".modal-body").textContent = details
+ if (buttonText) this.acceptTarget.textContent = buttonText
+
+ dialog.showModal()
+
+ return new Promise((resolve) => {
+ const controller = new AbortController()
+ this.acceptTarget.addEventListener("click", () => { resolve(true); controller.abort(); dialog.close() }, { signal: controller.signal })
+ dialog.addEventListener("close", () => { resolve(false); controller.abort() }, { signal: controller.signal })
+ })
+ }
+}
diff --git a/admin/app/components/solidus_admin/layout/confirm/component.rb b/admin/app/components/solidus_admin/layout/confirm/component.rb
new file mode 100644
index 00000000000..a8582c42ef9
--- /dev/null
+++ b/admin/app/components/solidus_admin/layout/confirm/component.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+# Component wrapper for confirmation dialog. This component uses a modal which
+# is rendered in the layout initially hidden. To have it open to confirm a
+# user's action, place the "data-turbo-confirm" on the submitter (or any other
+# element that supports "data-turbo-confirm" attribute: form, link with
+# "data-turbo-method") with the text you want to have in the modal title:
+#
+#
+#
+#
+#
+# You can add more details in the body of the modal using "data-confirm-details"
+# attribute:
+#
+#
+#
+# To customize "Confirm" button text use "data-confirm-button" attribute:
+#
+#
+#
+class SolidusAdmin::Layout::Confirm::Component < SolidusAdmin::BaseComponent
+end
diff --git a/admin/app/components/solidus_admin/layout/confirm/component.yml b/admin/app/components/solidus_admin/layout/confirm/component.yml
new file mode 100644
index 00000000000..88d249a4706
--- /dev/null
+++ b/admin/app/components/solidus_admin/layout/confirm/component.yml
@@ -0,0 +1,4 @@
+en:
+ cancel: "Cancel"
+ confirm: "Confirm"
+ title: "Are you sure?"
diff --git a/admin/app/components/solidus_admin/orders/cart/component.html.erb b/admin/app/components/solidus_admin/orders/cart/component.html.erb
index e290d3b719f..c866af803d4 100644
--- a/admin/app/components/solidus_admin/orders/cart/component.html.erb
+++ b/admin/app/components/solidus_admin/orders/cart/component.html.erb
@@ -61,8 +61,7 @@
size: :s,
title: t("spree.delete"),
icon: 'close-line',
- "data-controller": "confirm",
- "data-confirm-text-value": t("spree.are_you_sure"),
+ "data-turbo-confirm": t("spree.are_you_sure")
) %>
<% end %>
diff --git a/admin/app/components/solidus_admin/products/show/component.html.erb b/admin/app/components/solidus_admin/products/show/component.html.erb
index d30146e7e5c..a88917e1eca 100644
--- a/admin/app/components/solidus_admin/products/show/component.html.erb
+++ b/admin/app/components/solidus_admin/products/show/component.html.erb
@@ -155,8 +155,7 @@
tag: :button,
text: t(".delete"),
scheme: :danger,
- "data-action": "click->#{stimulus_id}#confirmDelete",
- "data-#{stimulus_id}-message-param": t(".delete_confirmation"),
+ "data-turbo-confirm": t(".delete_confirmation")
) %>
<% end %>
<% end %>
diff --git a/admin/app/components/solidus_admin/products/show/component.js b/admin/app/components/solidus_admin/products/show/component.js
deleted file mode 100644
index fd490e3c1b7..00000000000
--- a/admin/app/components/solidus_admin/products/show/component.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import { Controller } from "@hotwired/stimulus"
-
-export default class extends Controller {
- confirmDelete(event) {
- if (!confirm(event.params.message)) {
- event.preventDefault()
- }
- }
-}
diff --git a/admin/app/components/solidus_admin/ui/modal/component.html.erb b/admin/app/components/solidus_admin/ui/modal/component.html.erb
index bf301c6cf51..4e6480dc5c9 100644
--- a/admin/app/components/solidus_admin/ui/modal/component.html.erb
+++ b/admin/app/components/solidus_admin/ui/modal/component.html.erb
@@ -11,7 +11,7 @@
-
+
<%= @title %>
-
- <%= content %>
-
+
<%= content %>
<% if actions? %>
diff --git a/admin/app/components/solidus_admin/users/edit/api_access/component.js b/admin/app/components/solidus_admin/users/edit/api_access/component.js
deleted file mode 100644
index 910294c5462..00000000000
--- a/admin/app/components/solidus_admin/users/edit/api_access/component.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import { Controller } from "@hotwired/stimulus"
-
-export default class extends Controller {
- confirm(event) {
- if (!confirm(event.params.message)) {
- event.preventDefault()
- }
- }
-}
diff --git a/admin/app/components/solidus_admin/users/edit/api_access/component.yml b/admin/app/components/solidus_admin/users/edit/api_access/component.yml
index e865ba47c30..820fa4832c2 100644
--- a/admin/app/components/solidus_admin/users/edit/api_access/component.yml
+++ b/admin/app/components/solidus_admin/users/edit/api_access/component.yml
@@ -6,5 +6,11 @@ en:
clear_key: Clear key
regenerate_key: Regenerate key
hidden: Hidden
- confirm_clear_key: Are you sure you want to clear this user's API key? It will invalidate the existing key.
- confirm_regenerate_key: Are you sure you want to regenerate this user's API key? It will invalidate the existing key.
+ confirm:
+ title: Are you sure?
+ clear:
+ details: Are you sure you want to clear this user's API key? It will invalidate the existing key.
+ button: Clear
+ regenerate:
+ details: Are you sure you want to regenerate this user's API key? It will invalidate the existing key.
+ button: Regenerate
diff --git a/admin/app/javascript/solidus_admin/application.js b/admin/app/javascript/solidus_admin/application.js
index 7e7a85ebe4a..2a8d70652d6 100644
--- a/admin/app/javascript/solidus_admin/application.js
+++ b/admin/app/javascript/solidus_admin/application.js
@@ -1,4 +1,11 @@
-import "@hotwired/turbo-rails"
+import { Turbo } from "@hotwired/turbo-rails"
import "vendor/custom_elements"
import "solidus_admin/controllers"
+import { openConfirmModal } from "solidus_admin/confirm_modal"
import "solidus_admin/web_components/solidus_select"
+
+if (Turbo.config) {
+ Turbo.config.forms.confirm = openConfirmModal
+} else {
+ window.Turbo.setConfirmMethod(openConfirmModal)
+}
diff --git a/admin/app/javascript/solidus_admin/confirm_modal.js b/admin/app/javascript/solidus_admin/confirm_modal.js
new file mode 100644
index 00000000000..a4741280a81
--- /dev/null
+++ b/admin/app/javascript/solidus_admin/confirm_modal.js
@@ -0,0 +1,24 @@
+import { application } from "solidus_admin/controllers/application"
+
+/*
+ * Opens a confirmation modal with the given message and options.
+ * This is used as the Turbo confirm modal replacement. It returns a
+ * Promise that resolves to true if the user confirms, or false if
+ * the user cancels.
+ *
+ * @param {string} message - The message to display in the confirmation modal.
+ * @param {HTMLFormElement} formElement - Form element that triggered the
+ * confirmation.
+ * @param {HTMLElement} submitter - The element that triggered the form
+ * submission.
+ * @returns {Promise} - A promise that resolves to true if the user
+ * confirms, or false if the user cancels.
+ */
+export function openConfirmModal(message, formElement, submitter) {
+ const element = document.getElementById("confirm")
+ const controller = application.getControllerForElementAndIdentifier(element, "layout--confirm")
+ const details = submitter?.dataset.confirmDetails ?? formElement?.dataset.confirmDetails ?? ""
+ const buttonText = submitter?.dataset.confirmButton ?? formElement?.dataset.confirmButton
+
+ return controller.open(message, { details, buttonText })
+}
diff --git a/admin/app/javascript/solidus_admin/controllers/confirm_controller.js b/admin/app/javascript/solidus_admin/controllers/confirm_controller.js
deleted file mode 100644
index 60e5f3c0a6f..00000000000
--- a/admin/app/javascript/solidus_admin/controllers/confirm_controller.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import { Controller } from "@hotwired/stimulus"
-
-export default class extends Controller {
- static values = {"text": String}
-
- connect() {
- this.element.addEventListener("click", this)
- this.element.addEventListener("submit", this)
- }
-
- disconnect() {
- this.element.removeEventListener("click", this)
- this.element.removeEventListener("submit", this)
- }
-
- handleEvent(event) {
- if (!confirm(this.textValue)) {
- event.preventDefault()
- }
- }
-}
diff --git a/admin/app/views/layouts/solidus_admin/application.html.erb b/admin/app/views/layouts/solidus_admin/application.html.erb
index 5508ea9da15..41bc8def781 100644
--- a/admin/app/views/layouts/solidus_admin/application.html.erb
+++ b/admin/app/views/layouts/solidus_admin/application.html.erb
@@ -33,5 +33,6 @@
<%= render component("layout/flashes/alerts").new(alerts:) %>
<%= render component("layout/flashes/toasts").new(toasts:) %>
+ <%= render component("layout/confirm").new %>