diff --git a/resources/js/checkout/bbk-checkout-form-controller.js b/resources/js/checkout/bbk-checkout-form-controller.js index 83648d4..5060cb8 100644 --- a/resources/js/checkout/bbk-checkout-form-controller.js +++ b/resources/js/checkout/bbk-checkout-form-controller.js @@ -101,6 +101,15 @@ export default class extends Controller { this.saveTimer = setTimeout(() => this.save(), 700) } + // Called by bbk-payment right before place-order — a debounced save (and + // the shipping-option auto-select that happens as part of it) might still + // be pending when the shopper clicks "place order"; this guarantees the + // server has processed the current form state first. + async flush() { + clearTimeout(this.saveTimer) + await this.save() + } + async save() { this.saveController?.abort() this.saveController = new AbortController() diff --git a/resources/js/checkout/bbk-payment-controller.js b/resources/js/checkout/bbk-payment-controller.js index 57e12d8..4fcbd38 100644 --- a/resources/js/checkout/bbk-payment-controller.js +++ b/resources/js/checkout/bbk-payment-controller.js @@ -123,6 +123,11 @@ export default class extends Controller { amount: Math.max(this.amountValue, 1), currency: this.currencyValue, paymentMethodCreation: 'manual', + // Card only — matches the server confirming with + // automatic_payment_methods.allow_redirects = 'never' (no + // return_url in our flow: 3-D Secure resolves in-page via + // handleNextAction, never a full-page redirect). + paymentMethodTypes: ['card'], }) this.paymentElement = this.elements.create('payment') this.paymentElement.mount(this.elementTarget) @@ -142,22 +147,34 @@ export default class extends Controller { // ── Place order ────────────────────────────────────────────────── + // Sibling controller on the same element (.bbk-checkout-main) — used to + // flush a pending debounced address autosave before placing the order. + get checkoutForm() { + return this.application.getControllerForElementAndIdentifier(this.element, 'bbk-checkout-form') + } + async placeOrder() { this.clearError() + this.submitTarget.disabled = true + + // A debounced address save (and the shipping-option auto-select that + // happens as part of it) might still be pending — make sure the + // server has the latest state before we ask it to place the order. + await this.checkoutForm?.flush() if (!this.termsTarget.checked) { + this.submitTarget.disabled = false this.showError(this.termsRequiredValue) return } const radio = this.selectedRadio() if (!radio) { + this.submitTarget.disabled = false this.showError(this.chooseMethodValue) return } - this.submitTarget.disabled = true - let paymentMethodId = null if (radio.dataset.paymentDriver === 'stripe') { const { error: submitError } = await this.elements.submit()