"use client"; import {useRef,useState} from "react"; import { useRouter } from 'next/navigation'; import { usePlaceOrder } from "@/utils/hooks/usePlaceOrder"; import { usePayPal, useEligibleMethods, INSTANCE_LOADING_STATE, usePayPalOneTimePaymentSession, usePayPalGuestPaymentSession, usePayLaterOneTimePaymentSession, type OnApproveDataOneTimePayments, type OnErrorData, type OnCompleteData, type OnCancelDataOneTimePayments, } from "@paypal/react-paypal-js/sdk-v6"; import { overlayLoading } from "@/components/theme/ui/kernel/loading/api"; import { confirmDialog } from "@/components/theme/ui/kernel/confirm/api"; export default function PaypalButton({ createOrder, isRePay }:{ createOrder: () => Promise<{orderId: string;webOrderId: string;error: boolean;msg: string;}>; isRePay?: boolean; }) { const router = useRouter(); const {createPaymentCallback} = usePlaceOrder(); const [isPaying, setIsPaying] = useState(false); const gatewayOrderIdRef = useRef(""); const webOrderIdRef = useRef(""); // paypal sdk 是否加载完成 const { loadingStatus } = usePayPal(); // Fetch eligibility(资格) for one-time payment flow const { error: eligibilityError, eligiblePaymentMethods, isLoading: isEligibilityLoading, } = useEligibleMethods({ payload: { currencyCode: "USD", // @todo 需要根据用户选择的货币走 paymentFlow: "ONE_TIME_PAYMENT", }, }); const isLoading = loadingStatus === INSTANCE_LOADING_STATE.PENDING; const isPayLaterEligible = !isEligibilityLoading && eligiblePaymentMethods?.isEligible("paylater"); // const isCreditEligible = // !isEligibilityLoading && eligiblePaymentMethods?.isEligible("credit"); const handlerPaypalClick = async (buttonHandlerClick: () => Promise) => { setIsPaying(true); const res = await createOrder(); if(!res.error) { gatewayOrderIdRef.current = res.orderId; webOrderIdRef.current = res.webOrderId; return buttonHandlerClick(); } else { setIsPaying(false); } } // paypal支付回调配置 const paypalOnHandlerConfig = { createOrder: async () => { const res = { orderId: gatewayOrderIdRef.current, webOrderId: webOrderIdRef.current }; return res; }, onApprove: async (data: OnApproveDataOneTimePayments) => { console.log("Payment approved:", data); const resCallback = await createPaymentCallback({ orderId: Number(webOrderIdRef.current), gatewayOrderId: data.orderId || gatewayOrderIdRef.current, status: 'success', }); overlayLoading.stop(); if(!resCallback.error) { // 支付成功,跳转到成功落地页 confirmDialog({ title: "Payment Success", content: "Your payment was successful. Will redirect to success page.", noCancel: true, }).then(() => { router.replace('/paymentresult/result?orderId=' + webOrderIdRef.current + '&return_result=success'); }); } else { // callback 失败,提示错误 confirmDialog({ title: "Somthing Wrong", content: resCallback.msg + " Please contact customer service." + " OrderId: "+ webOrderIdRef.current, noCancel: true, }).then(() => { router.replace('/'); }); } }, onCancel: async (data: OnCancelDataOneTimePayments) => { /** * {oederId: paypalOrderId} */ console.log("Payment cancelled:", data); await createPaymentCallback({ orderId: Number(webOrderIdRef.current), gatewayOrderId: data.orderId || gatewayOrderIdRef.current, status: 'cancel', }); if(!isRePay) { overlayLoading.stop(); router.replace('/paymentresult/result?orderId=' + webOrderIdRef.current + '&return_result=cancel'); } else { // 登录用户在二次支付页面 confirmDialog({ title: "Payment cancelled", content: "You canceled the payment.", noCancel: true, }).then(() => { }); } }, onError: async (data: OnErrorData) => { console.error("Payment error:", data); /** * code: string; name: string; isRecoverable: boolean; */ await createPaymentCallback({ orderId: Number(webOrderIdRef.current), gatewayOrderId: gatewayOrderIdRef.current, status: 'failure', }); if(!isRePay) { overlayLoading.stop(); router.replace('/paymentresult/result?orderId=' + webOrderIdRef.current + '&return_result=failure'); } else { // 登录用户 二次支付页面 confirmDialog({ title: "Payment Failed", content: data.message, noCancel: true, }).then(() => { }); } }, onComplete: (data: OnCompleteData) => { overlayLoading.stop(); setIsPaying(false); console.log("Payment session completed"); console.log("On Complete data:", data); }, // onShippingAddressChange: (data) => {}, // onShippingOptionsChange: (data) => { // } }; const { // isPending: paypalButtonPending, error: paypalButtonError, handleClick: paypalButtonHandleClick, } = usePayPalOneTimePaymentSession({ presentationMode: "auto", ...paypalOnHandlerConfig }); const { buttonRef: guestButtonRef, // isPending: guestButtonPending, error: guestButtonError, handleClick: guestButtonHandleClick, } = usePayPalGuestPaymentSession(paypalOnHandlerConfig); const payLaterDetails = eligiblePaymentMethods?.getDetails("paylater"); const { // isPending: paylaterButtonPending, // error: paylaterButtonError, handleClick: paylaterButtonHandleClick, } = usePayLaterOneTimePaymentSession({ presentationMode: "auto", ...paypalOnHandlerConfig }); return (
{ isLoading ? (
Loading paypal payment methods...
) : eligibilityError ? (
Failed to load paypal payment options. Please refresh the page.
) : ( <> {paypalButtonError ?

Error: {paypalButtonError.message}

: { return handlerPaypalClick(paypalButtonHandleClick); }} type="pay" className="w-full" disabled={isPaying} /> } {guestButtonError ?

Error: {guestButtonError.message}

: handlerPaypalClick(guestButtonHandleClick)} /> } {isPayLaterEligible && handlerPaypalClick(paylaterButtonHandleClick)} countryCode={payLaterDetails?.countryCode} productCode={payLaterDetails?.productCode} /> } ) }
); }