Stop Paystack pre-modal flash on customer checkout.
Deploy Ladill Mini / deploy (push) Successful in 1m39s
Deploy Ladill Mini / deploy (push) Successful in 1m39s
Use the shared Inline sheet, hold busy until payment UI opens, and avoid locking page scroll during the handoff.
This commit is contained in:
+5
-1
@@ -323,7 +323,11 @@ Alpine.data('miniPaymentLanding', (config = {}) => ({
|
|||||||
: 'Network error. Please try again.';
|
: 'Network error. Please try again.';
|
||||||
} finally {
|
} finally {
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
this.loading = false;
|
// Keep loading while the sheet is open — ladill-pay-opened / cancel / error clear it.
|
||||||
|
// Clearing here caused a form flash before Paystack's modal painted.
|
||||||
|
if (!this.showSheet) {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -59,8 +59,7 @@
|
|||||||
this.accessCode = data.access_code || '';
|
this.accessCode = data.access_code || '';
|
||||||
this.publicKey = data.public_key || '';
|
this.publicKey = data.public_key || '';
|
||||||
this.returnUrl = data.callback_url || '';
|
this.returnUrl = data.callback_url || '';
|
||||||
this.showSheet = true;
|
this.showSheet = true; // loading cleared when payment UI opens (ladill-pay-opened)
|
||||||
this.loading = false;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
window.LadillPayCheckout?.cancel?.(); this.errorMsg = 'Network error. Please try again.';
|
window.LadillPayCheckout?.cancel?.(); this.errorMsg = 'Network error. Please try again.';
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -374,8 +374,7 @@
|
|||||||
this.accessCode = data.access_code || '';
|
this.accessCode = data.access_code || '';
|
||||||
this.publicKey = data.public_key || '';
|
this.publicKey = data.public_key || '';
|
||||||
this.returnUrl = data.callback_url || '';
|
this.returnUrl = data.callback_url || '';
|
||||||
this.showSheet = true;
|
this.showSheet = true; // loading cleared when payment UI opens (ladill-pay-opened)
|
||||||
this.loading = false;
|
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
window.LadillPayCheckout?.cancel?.(); this.errorMsg = 'Network error. Please try again.';
|
window.LadillPayCheckout?.cancel?.(); this.errorMsg = 'Network error. Please try again.';
|
||||||
@@ -695,8 +694,7 @@
|
|||||||
this.accessCode = data.access_code || '';
|
this.accessCode = data.access_code || '';
|
||||||
this.publicKey = data.public_key || '';
|
this.publicKey = data.public_key || '';
|
||||||
this.returnUrl = data.callback_url || '';
|
this.returnUrl = data.callback_url || '';
|
||||||
this.showSheet = true;
|
this.showSheet = true; // loading cleared when payment UI opens (ladill-pay-opened)
|
||||||
this.loading = false;
|
|
||||||
}
|
}
|
||||||
} catch(e) { window.LadillPayCheckout?.cancel?.(); this.errorMsg = 'Network error. Please try again.'; this.loading = false; }
|
} catch(e) { window.LadillPayCheckout?.cancel?.(); this.errorMsg = 'Network error. Please try again.'; this.loading = false; }
|
||||||
}
|
}
|
||||||
@@ -1246,8 +1244,7 @@
|
|||||||
this.accessCode = data.access_code || '';
|
this.accessCode = data.access_code || '';
|
||||||
this.publicKey = data.public_key || '';
|
this.publicKey = data.public_key || '';
|
||||||
this.returnUrl = data.callback_url || '';
|
this.returnUrl = data.callback_url || '';
|
||||||
this.showSheet = true;
|
this.showSheet = true; // loading cleared when payment UI opens (ladill-pay-opened)
|
||||||
this.loading = false;
|
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
window.LadillPayCheckout?.cancel?.(); this.errorMsg = 'Network error. Please try again.';
|
window.LadillPayCheckout?.cancel?.(); this.errorMsg = 'Network error. Please try again.';
|
||||||
|
|||||||
@@ -18,39 +18,52 @@ class ResponsivePaystackSheetTest extends TestCase
|
|||||||
$this->assertStringContainsString('data-ladill-pay-panel', $html);
|
$this->assertStringContainsString('data-ladill-pay-panel', $html);
|
||||||
$this->assertStringContainsString('data-ladill-pay-backdrop', $html);
|
$this->assertStringContainsString('data-ladill-pay-backdrop', $html);
|
||||||
$this->assertStringContainsString('data-ladill-pay-handle', $html);
|
$this->assertStringContainsString('data-ladill-pay-handle', $html);
|
||||||
$this->assertStringContainsString('data-ladill-pay-inline-status', $html);
|
|
||||||
$this->assertStringContainsString('md:items-center', $html);
|
$this->assertStringContainsString('md:items-center', $html);
|
||||||
$this->assertStringContainsString('rounded-t-2xl', $html);
|
$this->assertStringContainsString('rounded-t-2xl', $html);
|
||||||
$this->assertStringContainsString('md:rounded-2xl', $html);
|
$this->assertStringContainsString('md:rounded-2xl', $html);
|
||||||
$this->assertStringContainsString('md:max-w-lg', $html);
|
$this->assertStringContainsString('md:max-w-lg', $html);
|
||||||
$this->assertStringContainsString('data-paystack-live', $html);
|
$this->assertStringContainsString('data-paystack-live', $html);
|
||||||
$this->assertStringContainsString('data-ladill-pay-close-live', $html);
|
$this->assertStringContainsString('data-ladill-pay-close-live', $html);
|
||||||
|
$this->assertStringContainsString('data-ladill-pay-header-minimal', $html);
|
||||||
$this->assertStringContainsString('Complete your payment', $html);
|
$this->assertStringContainsString('Complete your payment', $html);
|
||||||
$this->assertStringContainsString('safe-area-inset-bottom', $html);
|
$this->assertStringContainsString('safe-area-inset-bottom', $html);
|
||||||
$this->assertStringContainsString('LadillPayCheckout', $html);
|
$this->assertStringContainsString('LadillPayCheckout', $html);
|
||||||
$this->assertStringContainsString('resumeTransaction', $html);
|
$this->assertStringContainsString('resumeTransaction', $html);
|
||||||
$this->assertStringContainsString("\$watch('showSheet'", $html);
|
$this->assertStringContainsString("\$watch('showSheet'", $html);
|
||||||
$this->assertStringContainsString('js.paystack.co/v2/inline.js', $html);
|
$this->assertStringContainsString('js.paystack.co/v2/inline.js', $html);
|
||||||
$this->assertStringContainsString('Paystack owns its secure checkout popup', $html);
|
|
||||||
$this->assertStringContainsString('items-end justify-center md:items-center', $html);
|
$this->assertStringContainsString('items-end justify-center md:items-center', $html);
|
||||||
// Cross-origin checkout needs fullscreen delegated on the iframe + parent policy.
|
$this->assertStringContainsString('rounded-t-2xl bg-white shadow-2xl md:max-w-lg md:rounded-2xl', $html);
|
||||||
$this->assertStringContainsString('ensurePaystackIframePermissions', $html);
|
$this->assertStringContainsString('ensurePaystackIframePermissions', $html);
|
||||||
$this->assertStringContainsString('installIframeAllowHook', $html);
|
$this->assertStringContainsString('installIframeAllowHook', $html);
|
||||||
$this->assertStringContainsString('fullscreen *', $html);
|
$this->assertStringContainsString('fullscreen *', $html);
|
||||||
$this->assertStringContainsString("attributeFilter: ['allow', 'src', 'id', 'name', 'style', 'class']", $html);
|
$this->assertStringNotContainsString("attributeFilter: ['allow', 'src', 'id', 'name', 'style', 'class']", $html);
|
||||||
// Paystack must load inside the Ladill sheet mount — not a second full-screen modal.
|
$this->assertStringContainsString('childList only', $html);
|
||||||
|
$this->assertStringContainsString('Only write attributes when they actually change', $html);
|
||||||
|
$this->assertStringContainsString('Do not watch iframes or preload Paystack on every page', $html);
|
||||||
$this->assertStringContainsString('data-ladill-pay-mount', $html);
|
$this->assertStringContainsString('data-ladill-pay-mount', $html);
|
||||||
$this->assertStringContainsString('setPaystackContainActive', $html);
|
$this->assertStringContainsString('data-ladill-pay-body', $html);
|
||||||
$this->assertStringContainsString('installAppendHook', $html);
|
$this->assertStringNotContainsString('styleCheckoutPinnedToRect', $html);
|
||||||
$this->assertStringContainsString('ladill-pay-inline-active', $html);
|
$this->assertStringNotContainsString('waitForPinTarget', $html);
|
||||||
// Must not push Paystack to a separate browser as the primary path.
|
$this->assertStringNotContainsString('placeCheckoutInMount', $html);
|
||||||
|
$this->assertStringNotContainsString('installAppendHook', $html);
|
||||||
|
$this->assertStringNotContainsString('__ladillContainPaystack', $html);
|
||||||
|
$this->assertStringNotContainsString('Node.prototype.appendChild', $html);
|
||||||
|
$this->assertStringNotContainsString('data-ladill-pay-inline-status', $html);
|
||||||
|
$this->assertStringNotContainsString('Please wait', $html);
|
||||||
|
$this->assertStringContainsString('Payment UI did not open', $html);
|
||||||
|
$this->assertStringContainsString('ladill-pay-opened', $html);
|
||||||
|
$this->assertStringContainsString('Only lock page scroll when OUR shell is visible', $html);
|
||||||
|
$this->assertStringContainsString('releaseBusy', $html);
|
||||||
|
$this->assertStringContainsString('markOpened', $html);
|
||||||
$this->assertStringNotContainsString('Continue to Paystack', $html);
|
$this->assertStringNotContainsString('Continue to Paystack', $html);
|
||||||
$this->assertStringNotContainsString('window.open(', $html);
|
$this->assertStringNotContainsString('window.open(', $html);
|
||||||
// Must not use Tailwind `hidden` + x-show on the panel (desktop stays invisible).
|
|
||||||
$this->assertStringNotContainsString('hidden w-full max-w-lg', $html);
|
$this->assertStringNotContainsString('hidden w-full max-w-lg', $html);
|
||||||
$this->assertStringNotContainsString('Paystack checkout', $html);
|
$this->assertStringNotContainsString('Paystack checkout', $html);
|
||||||
|
$this->assertStringNotContainsString('bg-transparent shadow-none', $html);
|
||||||
|
$this->assertStringNotContainsString('not in a separate browser', $html);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function test_payment_return_escapes_popup_and_iframe_to_opener_or_top(): void
|
public function test_payment_return_escapes_popup_and_iframe_to_opener_or_top(): void
|
||||||
{
|
{
|
||||||
$view = view()->exists('partials.payment-return')
|
$view = view()->exists('partials.payment-return')
|
||||||
|
|||||||
Reference in New Issue
Block a user