diff --git a/resources/js/app.js b/resources/js/app.js index 9fe7a59..0fb1976 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -231,7 +231,7 @@ Alpine.data('miniPaymentLanding', (config = {}) => ({ } this.errorMsg = ''; - this.loading = true; + this.loading = true; window.LadillPayCheckout?.prepare?.(); try { const res = await fetch(config.payUrl, { @@ -259,7 +259,7 @@ Alpine.data('miniPaymentLanding', (config = {}) => ({ this.showSheet = true; this.loading = false; } catch (e) { - this.errorMsg = 'Network error. Please try again.'; + window.LadillPayCheckout?.cancel?.(); this.errorMsg = 'Network error. Please try again.'; this.loading = false; } }, diff --git a/resources/views/partials/paystack-sheet.blade.php b/resources/views/partials/paystack-sheet.blade.php index a437868..17afe3c 100644 --- a/resources/views/partials/paystack-sheet.blade.php +++ b/resources/views/partials/paystack-sheet.blade.php @@ -10,8 +10,9 @@ Paystack (checkout.paystack.com) sends X-Frame-Options: SAMEORIGIN and cannot be embedded. Same-origin URLs (e.g. MoMo waiting pages) still load in an iframe. - External checkouts open in a named window, with an in-sheet Continue CTA as a - user-gesture fallback when the popup is blocked after an async fetch. + External checkouts open in a named window. Call LadillPayCheckout.prepare() + synchronously in the Pay click handler (before await fetch) so the popup is not + blocked after the async response. An in-sheet Continue CTA remains as fallback. --}} @php $audience = $audience ?? 'buyer'; @@ -42,6 +43,9 @@ (function () { if (window.LadillPayCheckout) return; + var PENDING_NAME = 'ladill_pay_checkout'; + var pendingWindow = null; + function isFrameable(url) { if (!url) return false; try { @@ -51,12 +55,50 @@ } } + function writePendingPlaceholder(win) { + if (!win) return; + try { + win.document.open(); + win.document.write('Payment

Opening secure checkout…

'); + win.document.close(); + } catch (e) {} + } + + function prepare() { + cancel(); + try { + var win = window.open('about:blank', PENDING_NAME, 'width=480,height=720'); + if (win && !win.closed) { + pendingWindow = win; + writePendingPlaceholder(win); + return win; + } + } catch (e) {} + pendingWindow = null; + return null; + } + + function cancel() { + if (pendingWindow && !pendingWindow.closed) { + try { pendingWindow.close(); } catch (e) {} + } + pendingWindow = null; + } + function openCheckout(url) { if (!url) return null; try { + if (pendingWindow && !pendingWindow.closed) { + pendingWindow.location = url; + var win = pendingWindow; + pendingWindow = null; + return win; + } + pendingWindow = null; // Named window (no noopener) so payment-return can redirect window.opener. - return window.open(url, 'ladill_pay_checkout', 'width=480,height=720'); + return window.open(url, PENDING_NAME, 'width=480,height=720'); } catch (e) { + pendingWindow = null; return null; } } @@ -83,6 +125,7 @@ if (!url) return; this.frameable = isFrameable(url); if (this.frameable) { + cancel(); this.popupBlocked = false; return; } @@ -114,6 +157,8 @@ window.LadillPayCheckout = { isFrameable: isFrameable, + prepare: prepare, + cancel: cancel, open: openCheckout, ensureStore: ensureStore, }; @@ -183,12 +228,12 @@
- -

+ x-text="$store.ladillPayCheckout.popupBlocked ? 'Continue in a secure payment window' : 'Complete payment in the secure window'">

- A Paystack window should be open. If you do not see it, tap continue below. - Your browser blocked the popup. Tap continue to open Paystack. + A Paystack window should be open. If you do not see it, tap continue below. + Your browser blocked the popup. Tap continue to open Paystack.

@@ -251,13 +296,13 @@
- -

+ x-text="$store.ladillPayCheckout.popupBlocked ? 'Continue in a secure payment window' : 'Complete payment in the secure window'">

- A Paystack window should be open. If you do not see it, click continue below. - Your browser blocked the popup. Click continue to open Paystack. + A Paystack window should be open. If you do not see it, click continue below. + Your browser blocked the popup. Click continue to open Paystack.

diff --git a/tests/Feature/ResponsivePaystackSheetTest.php b/tests/Feature/ResponsivePaystackSheetTest.php index 814687e..8da1d1b 100644 --- a/tests/Feature/ResponsivePaystackSheetTest.php +++ b/tests/Feature/ResponsivePaystackSheetTest.php @@ -22,6 +22,7 @@ class ResponsivePaystackSheetTest extends TestCase $this->assertStringContainsString('LadillPayCheckout', $html); $this->assertStringContainsString('Continue to Paystack', $html); $this->assertStringContainsString('ladill_pay_checkout', $html); + $this->assertStringContainsString('prepare:', $html); $this->assertStringNotContainsString('Paystack checkout', $html); }