UNPKG

@blocklet/payment-react

Version:

Reusable react components for payment kit v2

127 lines (126 loc) 3.94 kB
import { jsx } from "react/jsx-runtime"; import { useRequest, useSetState } from "ahooks"; import noop from "lodash/noop"; import { useEffect } from "react"; import { joinURL } from "ufo"; import { ReactGA } from "@arcblock/ux/lib/withTracker"; import api from "../libs/api.js"; import { getPrefix, mergeExtraParams } from "../libs/util.js"; import Payment from "../payment/index.js"; import { PaymentThemeProvider } from "../theme/index.js"; import DonationForm from "../payment/donation-form.js"; const promises = {}; const startFromPaymentLink = (id, params) => { if (!promises[id]) { promises[id] = api.post(`/api/checkout-sessions/start/${id}?${mergeExtraParams(params)}`).then((res) => res?.data).finally(() => { setTimeout(() => { delete promises[id]; }, 3e3); }); } return promises[id]; }; const fetchCheckoutSession = async (id) => { const { data } = await api.get(`/api/checkout-sessions/retrieve/${id}`); return data; }; export default function CheckoutForm({ id, mode = "inline", onPaid = noop, onError = console.error, onChange, goBack, extraParams = {}, action = "", theme = "default", formType = "payment", ...restProps }) { if (!id.startsWith("plink_") && !id.startsWith("cs_")) { throw new Error("Either a checkoutSession or a paymentLink id is required."); } const type = id.startsWith("plink_") ? "paymentLink" : "checkoutSession"; const [state, setState] = useSetState({ completed: false, appError: null }); const { error: apiError, data } = useRequest( () => type === "paymentLink" ? startFromPaymentLink(id, extraParams) : fetchCheckoutSession(id) ); useEffect(() => { if (type === "paymentLink" && mode === "standalone" && data) { window.history.replaceState( null, "", joinURL(getPrefix(), `/checkout/pay/${data.checkoutSession.id}?${mergeExtraParams(extraParams)}`) ); } }, [type, mode, data, extraParams]); const handlePaid = (result) => { setState({ completed: true }); onPaid?.(result); const paySuccessEvent = { action: "paySuccess", // @ts-ignore 后续升级的话就会报错了,移除这个 lint 即可 mode: data?.checkoutSession?.mode, success: true }; ReactGA.event(paySuccessEvent.action, paySuccessEvent); }; const handleError = (err) => { console.error(err); setState({ appError: err }); onError?.(err); const payFailedEvent = { action: "payFailed", // @ts-ignore后续升级的话就会报错了,移除这个 lint 即可 mode: data?.checkoutSession?.mode, errorMessage: err.message, success: false }; ReactGA.event(payFailedEvent.action, payFailedEvent); }; const Checkout = formType === "donation" ? /* @__PURE__ */ jsx( DonationForm, { checkoutSession: data?.checkoutSession, paymentMethods: data?.paymentMethods, paymentIntent: data?.paymentIntent, paymentLink: data?.paymentLink, customer: data?.customer, completed: state.completed, error: apiError, onPaid: handlePaid, onError: handleError, onChange, goBack, mode, action, id, ...restProps } ) : /* @__PURE__ */ jsx( Payment, { checkoutSession: data?.checkoutSession, paymentMethods: data?.paymentMethods, paymentIntent: data?.paymentIntent, paymentLink: data?.paymentLink, customer: data?.customer, completed: state.completed, error: apiError, onPaid: handlePaid, onError: handleError, onChange, goBack, mode, action, ...restProps } ); if (theme === "inherit") { return Checkout; } if (theme && typeof theme === "object") { return /* @__PURE__ */ jsx(PaymentThemeProvider, { theme, children: Checkout }); } return /* @__PURE__ */ jsx(PaymentThemeProvider, { children: Checkout }); }