refactor(payment): share launch flow
This commit is contained in:
@@ -4,19 +4,12 @@
|
||||
*
|
||||
* 包装 `SubscriptionCtaButton` —— 通过 payment 状态机创建后端订单并拉起支付。
|
||||
*/
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
import {
|
||||
getPaymentUrl,
|
||||
getStripeClientSecret,
|
||||
isEzpayPayment,
|
||||
launchEzpayRedirect,
|
||||
} from "@/lib/payment/payment_launch";
|
||||
import { usePaymentLaunchFlow } from "@/app/_hooks/use-payment-launch-flow";
|
||||
import {
|
||||
usePaymentDispatch,
|
||||
usePaymentState,
|
||||
} from "@/stores/payment/payment-context";
|
||||
import { AppEnvUtil, Logger } from "@/utils";
|
||||
import { Logger } from "@/utils";
|
||||
|
||||
import { StripePaymentDialog } from "./stripe-payment-dialog";
|
||||
import dialogStyles from "./stripe-payment-dialog.module.css";
|
||||
@@ -39,65 +32,14 @@ export function SubscriptionCheckoutButton({
|
||||
}: SubscriptionCheckoutButtonProps) {
|
||||
const payment = usePaymentState();
|
||||
const paymentDispatch = usePaymentDispatch();
|
||||
const launchedNonceRef = useRef(0);
|
||||
const [hiddenStripeClientSecret, setHiddenStripeClientSecret] = useState<
|
||||
string | null
|
||||
>(null);
|
||||
const [isConfirmingEzpay, setIsConfirmingEzpay] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!payment.payParams || payment.launchNonce <= launchedNonceRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
launchedNonceRef.current = payment.launchNonce;
|
||||
const clientSecret = getStripeClientSecret(payment.payParams);
|
||||
if (clientSecret) {
|
||||
return;
|
||||
}
|
||||
|
||||
const paymentUrl = getPaymentUrl(payment.payParams);
|
||||
if (paymentUrl) {
|
||||
const isEzpay = isEzpayPayment(payment.payParams);
|
||||
|
||||
if (!AppEnvUtil.isProduction() && isEzpay) {
|
||||
log.debug("[subscription-checkout] ezpay confirmation required", {
|
||||
orderId: payment.currentOrderId,
|
||||
paymentUrl,
|
||||
subscriptionType,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (isEzpay) {
|
||||
void launchEzpayRedirect({
|
||||
orderId: payment.currentOrderId,
|
||||
paymentUrl,
|
||||
subscriptionType,
|
||||
returnTo: returnTo ?? undefined,
|
||||
onFailed: (errorMessage) =>
|
||||
paymentDispatch({ type: "PaymentLaunchFailed", errorMessage }),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
window.location.href = paymentUrl;
|
||||
return;
|
||||
}
|
||||
|
||||
paymentDispatch({
|
||||
type: "PaymentLaunchFailed",
|
||||
errorMessage:
|
||||
"Payment parameters did not include a supported URL or Stripe client secret.",
|
||||
});
|
||||
}, [
|
||||
payment.currentOrderId,
|
||||
payment.launchNonce,
|
||||
payment.payParams,
|
||||
const paymentLaunch = usePaymentLaunchFlow({
|
||||
log,
|
||||
logScope: "subscription-checkout",
|
||||
payment,
|
||||
paymentDispatch,
|
||||
returnTo,
|
||||
returnTo: returnTo ?? undefined,
|
||||
subscriptionType,
|
||||
]);
|
||||
});
|
||||
|
||||
const isLoading =
|
||||
payment.isCreatingOrder ||
|
||||
@@ -118,69 +60,10 @@ export function SubscriptionCheckoutButton({
|
||||
|
||||
const handleClick = () => {
|
||||
if (disabled || isLoading) return;
|
||||
setIsConfirmingEzpay(false);
|
||||
setHiddenStripeClientSecret(null);
|
||||
paymentLaunch.resetLaunchState();
|
||||
paymentDispatch({ type: "PaymentCreateOrderSubmitted" });
|
||||
};
|
||||
|
||||
const handleStripeClose = () => {
|
||||
if (stripeClientSecret) {
|
||||
setHiddenStripeClientSecret(stripeClientSecret);
|
||||
}
|
||||
if (payment.orderStatus !== "paid") {
|
||||
paymentDispatch({ type: "PaymentReset" });
|
||||
}
|
||||
};
|
||||
|
||||
const handleStripeConfirmed = () => {
|
||||
if (stripeClientSecret) {
|
||||
setHiddenStripeClientSecret(stripeClientSecret);
|
||||
}
|
||||
};
|
||||
|
||||
const stripeClientSecret = payment.payParams
|
||||
? getStripeClientSecret(payment.payParams)
|
||||
: null;
|
||||
const shouldShowStripeDialog =
|
||||
stripeClientSecret !== null &&
|
||||
stripeClientSecret !== hiddenStripeClientSecret &&
|
||||
!payment.isPaid;
|
||||
const ezpayPaymentUrl = payment.payParams
|
||||
? getPaymentUrl(payment.payParams)
|
||||
: null;
|
||||
const shouldShowEzpayConfirmDialog =
|
||||
!AppEnvUtil.isProduction() &&
|
||||
payment.payParams &&
|
||||
isEzpayPayment(payment.payParams) &&
|
||||
ezpayPaymentUrl &&
|
||||
payment.currentOrderId
|
||||
? true
|
||||
: false;
|
||||
|
||||
const handleEzpayConfirm = () => {
|
||||
if (!payment.currentOrderId || !ezpayPaymentUrl) return;
|
||||
setIsConfirmingEzpay(true);
|
||||
void launchEzpayRedirect({
|
||||
orderId: payment.currentOrderId,
|
||||
paymentUrl: ezpayPaymentUrl,
|
||||
subscriptionType,
|
||||
returnTo: returnTo ?? undefined,
|
||||
onFailed: (errorMessage) => {
|
||||
setIsConfirmingEzpay(false);
|
||||
paymentDispatch({ type: "PaymentLaunchFailed", errorMessage });
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const handleEzpayCancel = () => {
|
||||
log.debug("[subscription-checkout] ezpay confirmation cancelled", {
|
||||
orderId: payment.currentOrderId,
|
||||
subscriptionType,
|
||||
});
|
||||
setIsConfirmingEzpay(false);
|
||||
paymentDispatch({ type: "PaymentReset" });
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SubscriptionCtaButton
|
||||
@@ -205,19 +88,19 @@ export function SubscriptionCheckoutButton({
|
||||
{payment.errorMessage}
|
||||
</p>
|
||||
) : null}
|
||||
{shouldShowEzpayConfirmDialog ? (
|
||||
{paymentLaunch.shouldShowEzpayConfirmDialog ? (
|
||||
<EzpayRedirectConfirmDialog
|
||||
orderId={payment.currentOrderId ?? ""}
|
||||
isConfirming={isConfirmingEzpay}
|
||||
onCancel={handleEzpayCancel}
|
||||
onConfirm={handleEzpayConfirm}
|
||||
isConfirming={paymentLaunch.isConfirmingEzpay}
|
||||
onCancel={paymentLaunch.handleEzpayCancel}
|
||||
onConfirm={paymentLaunch.handleEzpayConfirm}
|
||||
/>
|
||||
) : null}
|
||||
{shouldShowStripeDialog ? (
|
||||
{paymentLaunch.shouldShowStripeDialog && paymentLaunch.stripeClientSecret ? (
|
||||
<StripePaymentDialog
|
||||
clientSecret={stripeClientSecret}
|
||||
onClose={handleStripeClose}
|
||||
onConfirmed={handleStripeConfirmed}
|
||||
clientSecret={paymentLaunch.stripeClientSecret}
|
||||
onClose={paymentLaunch.handleStripeClose}
|
||||
onConfirmed={paymentLaunch.handleStripeConfirmed}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user