mirror of
https://github.com/perfect-panel/ppanel-web.git
synced 2026-02-15 04:41:10 -05:00
110 lines
2.8 KiB
TypeScript
110 lines
2.8 KiB
TypeScript
import { Elements, useStripe } from '@stripe/react-stripe-js';
|
|
import { loadStripe, PaymentIntentResult } from '@stripe/stripe-js';
|
|
import { QRCodeCanvas } from 'qrcode.react';
|
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
|
|
interface StripePaymentProps {
|
|
method: string;
|
|
client_secret: string;
|
|
publishable_key: string;
|
|
}
|
|
|
|
const StripePayment: React.FC<StripePaymentProps> = ({
|
|
method,
|
|
client_secret,
|
|
publishable_key,
|
|
}) => {
|
|
const stripePromise = useMemo(() => loadStripe(publishable_key), [publishable_key]);
|
|
|
|
return (
|
|
<Elements stripe={stripePromise}>
|
|
<CheckoutForm method={method} client_secret={client_secret} />
|
|
</Elements>
|
|
);
|
|
};
|
|
|
|
const CheckoutForm: React.FC<Omit<StripePaymentProps, 'publishable_key'>> = ({
|
|
client_secret,
|
|
method,
|
|
}) => {
|
|
const stripe = useStripe();
|
|
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
|
const [qrCodeUrl, setQrCodeUrl] = useState<string | null>(null);
|
|
const [isSubmitted, setIsSubmitted] = useState(false);
|
|
|
|
const handleError = useCallback((message: string) => {
|
|
setErrorMessage(message);
|
|
setIsSubmitted(false);
|
|
}, []);
|
|
|
|
const confirmPayment = useCallback(async (): Promise<PaymentIntentResult | null> => {
|
|
if (!stripe) {
|
|
handleError('Stripe.js is not loaded.');
|
|
return null;
|
|
}
|
|
|
|
if (method === 'alipay') {
|
|
return await stripe.confirmAlipayPayment(
|
|
client_secret,
|
|
{ return_url: window.location.href },
|
|
{ handleActions: false },
|
|
);
|
|
}
|
|
|
|
return await stripe.confirmWechatPayPayment(
|
|
client_secret,
|
|
{
|
|
payment_method_options: { wechat_pay: { client: 'web' } },
|
|
},
|
|
{ handleActions: false },
|
|
);
|
|
}, [client_secret, method, stripe, handleError]);
|
|
|
|
const autoSubmit = useCallback(async () => {
|
|
if (isSubmitted) return;
|
|
|
|
setIsSubmitted(true);
|
|
|
|
try {
|
|
const result = await confirmPayment();
|
|
if (!result) return;
|
|
|
|
const { error, paymentIntent } = result;
|
|
if (error) return handleError(error.message!);
|
|
|
|
if (paymentIntent?.status === 'requires_action') {
|
|
const nextAction = paymentIntent.next_action as any;
|
|
const qrUrl =
|
|
method === 'alipay'
|
|
? nextAction?.alipay_handle_redirect?.url
|
|
: nextAction?.wechat_pay_display_qr_code?.image_url_svg;
|
|
|
|
setQrCodeUrl(qrUrl || null);
|
|
}
|
|
} catch (error) {
|
|
handleError('An unexpected error occurred');
|
|
}
|
|
}, [confirmPayment, isSubmitted, handleError, method]);
|
|
|
|
useEffect(() => {
|
|
autoSubmit();
|
|
}, [autoSubmit]);
|
|
|
|
return qrCodeUrl ? (
|
|
<QRCodeCanvas
|
|
value={qrCodeUrl}
|
|
size={208}
|
|
imageSettings={{
|
|
src: `/payment/${method}.svg`,
|
|
width: 24,
|
|
height: 24,
|
|
excavate: true,
|
|
}}
|
|
/>
|
|
) : (
|
|
errorMessage
|
|
);
|
|
};
|
|
|
|
export default StripePayment;
|