From 14c17fffa799ce909ba0a80b1fc7ca4a566220fa Mon Sep 17 00:00:00 2001 From: isaacclad Date: Tue, 21 Jul 2026 18:46:26 +0000 Subject: [PATCH] Keep Paystack sheet/modal visible; open Paystack from Continue. Stop auto-popups that steal focus, use one responsive panel, and skip ladl.link redirects for JSON pay requests. --- .../RedirectLegacyQrToLadillLink.php | 6 + .../views/partials/paystack-sheet.blade.php | 175 ++++++------------ tests/Feature/ResponsivePaystackSheetTest.php | 18 +- 3 files changed, 80 insertions(+), 119 deletions(-) diff --git a/app/Http/Middleware/RedirectLegacyQrToLadillLink.php b/app/Http/Middleware/RedirectLegacyQrToLadillLink.php index d503be1..af7170d 100644 --- a/app/Http/Middleware/RedirectLegacyQrToLadillLink.php +++ b/app/Http/Middleware/RedirectLegacyQrToLadillLink.php @@ -36,6 +36,12 @@ class RedirectLegacyQrToLadillLink return $next($request); } + // Same-origin AJAX from Events-hosted pages must not 307 to ladl.link + // (cross-origin fetch has no CORS → checkout sheet never opens). + if ($request->ajax() || $request->expectsJson() || $request->wantsJson()) { + return $next($request); + } + if ($this->servesStoredAsset($request) || $this->servesRegistrationTransaction($request)) { return $next($request); } diff --git a/resources/views/partials/paystack-sheet.blade.php b/resources/views/partials/paystack-sheet.blade.php index 17afe3c..9817a4e 100644 --- a/resources/views/partials/paystack-sheet.blade.php +++ b/resources/views/partials/paystack-sheet.blade.php @@ -10,9 +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. 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. + External checkouts stay in this chrome with a Continue CTA that opens Paystack + in a named window (user gesture — not blocked). Auto-popups are intentionally + avoided so the sheet/modal always remains visibly on screen. --}} @php $audience = $audience ?? 'buyer'; @@ -64,17 +64,9 @@ } catch (e) {} } + // Kept for callers; no longer opens a window on Pay click (that stole focus + // from the sheet/modal). Prefer opening from the in-sheet Continue CTA. 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; } @@ -111,31 +103,35 @@ window.Alpine.store('ladillPayCheckout', { frameable: false, popupBlocked: false, - launchKey: '', + ready: false, reset() { this.frameable = false; this.popupBlocked = false; - this.launchKey = ''; + this.ready = false; }, sync(show, url) { if (!show) { this.reset(); return; } - if (!url) return; - this.frameable = isFrameable(url); - if (this.frameable) { - cancel(); + this.ready = !!url; + if (!url) { + this.frameable = false; this.popupBlocked = false; return; } - if (this.launchKey === url) return; - this.launchKey = url; - var popup = openCheckout(url); - this.popupBlocked = !(popup && !popup.closed); + this.frameable = isFrameable(url); + // Never auto-open an external popup here — the sheet/modal must stay + // visible. External checkouts use the Continue CTA (user gesture). + this.popupBlocked = !this.frameable; }, continueTo(url) { if (!url) return; + if (isFrameable(url)) { + this.frameable = true; + this.popupBlocked = false; + return; + } var popup = openCheckout(url); this.popupBlocked = !(popup && !popup.closed); if (this.popupBlocked) { @@ -168,13 +164,15 @@