feat: enhance StripePaymentDialog with document handling and portal rendering
This commit is contained in:
@@ -4,7 +4,8 @@
|
|||||||
*
|
*
|
||||||
* 后端当前返回 PaymentIntent clientSecret,因此这里直接用它完成前端确认。
|
* 后端当前返回 PaymentIntent clientSecret,因此这里直接用它完成前端确认。
|
||||||
*/
|
*/
|
||||||
import { useState, type FormEvent } from "react";
|
import { useEffect, useState, type FormEvent } from "react";
|
||||||
|
import { createPortal } from "react-dom";
|
||||||
import {
|
import {
|
||||||
Elements,
|
Elements,
|
||||||
PaymentElement,
|
PaymentElement,
|
||||||
@@ -35,31 +36,44 @@ export function StripePaymentDialog({
|
|||||||
onClose,
|
onClose,
|
||||||
onConfirmed,
|
onConfirmed,
|
||||||
}: StripePaymentDialogProps) {
|
}: StripePaymentDialogProps) {
|
||||||
if (!stripePromise) {
|
useEffect(() => {
|
||||||
return (
|
if (typeof document === "undefined") return;
|
||||||
<div className={styles.overlay} role="alertdialog" aria-modal="true">
|
|
||||||
<div className={styles.dialog}>
|
const prevOverflow = document.body.style.overflow;
|
||||||
<div className={styles.header}>
|
const handleKeyDown = (event: KeyboardEvent) => {
|
||||||
<h2 className={styles.title}>Payment unavailable</h2>
|
if (event.key === "Escape") onClose();
|
||||||
<p className={styles.content}>
|
};
|
||||||
Stripe publishable key is not configured for this build.
|
|
||||||
</p>
|
document.body.style.overflow = "hidden";
|
||||||
</div>
|
document.addEventListener("keydown", handleKeyDown);
|
||||||
<div className={styles.actions}>
|
|
||||||
<button
|
return () => {
|
||||||
type="button"
|
document.body.style.overflow = prevOverflow;
|
||||||
className={`${styles.button} ${styles.primary}`}
|
document.removeEventListener("keydown", handleKeyDown);
|
||||||
onClick={onClose}
|
};
|
||||||
>
|
}, [onClose]);
|
||||||
OK
|
|
||||||
</button>
|
const dialog = !stripePromise ? (
|
||||||
</div>
|
<div className={styles.overlay} role="alertdialog" aria-modal="true">
|
||||||
|
<div className={styles.dialog}>
|
||||||
|
<div className={styles.header}>
|
||||||
|
<h2 className={styles.title}>Payment unavailable</h2>
|
||||||
|
<p className={styles.content}>
|
||||||
|
Stripe publishable key is not configured for this build.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className={styles.actions}>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`${styles.button} ${styles.primary}`}
|
||||||
|
onClick={onClose}
|
||||||
|
>
|
||||||
|
OK
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
</div>
|
||||||
}
|
) : (
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
<div
|
||||||
className={styles.overlay}
|
className={styles.overlay}
|
||||||
role="dialog"
|
role="dialog"
|
||||||
@@ -95,6 +109,10 @@ export function StripePaymentDialog({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (typeof document === "undefined") return null;
|
||||||
|
|
||||||
|
return createPortal(dialog, document.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
function StripePaymentForm({
|
function StripePaymentForm({
|
||||||
|
|||||||
Reference in New Issue
Block a user