feat(payment): confirm renewal only at checkout
This commit is contained in:
@@ -4,11 +4,17 @@
|
||||
*
|
||||
* 包装 `SubscriptionCtaButton` —— 通过 payment 状态机创建后端订单并拉起支付。
|
||||
*/
|
||||
import { useState } from "react";
|
||||
|
||||
import { usePaymentLaunchFlow } from "@/app/_hooks/use-payment-launch-flow";
|
||||
import { PaymentLaunchDialogs } from "@/app/_components/payment/payment-launch-dialogs";
|
||||
import { ExternalBrowserCheckoutButton } from "@/app/_components/payment/external-browser-checkout-button";
|
||||
import { DEFAULT_CHARACTER_SLUG } from "@/data/constants/character";
|
||||
import type { SubscriptionReturnTo } from "@/lib/navigation/subscription_exit";
|
||||
import {
|
||||
hasAutomaticRenewalAcknowledgement,
|
||||
rememberAutomaticRenewalAcknowledgement,
|
||||
} from "@/lib/payment/automatic_renewal_acknowledgement";
|
||||
import {
|
||||
usePaymentDispatch,
|
||||
usePaymentState,
|
||||
@@ -16,15 +22,19 @@ import {
|
||||
import { Logger } from "@/utils/logger";
|
||||
|
||||
import { SubscriptionCtaButton } from "./subscription-cta-button";
|
||||
import { SubscriptionRenewalConfirmationDialog } from "./subscription-renewal-confirmation-dialog";
|
||||
import type { VipOfferPlanView } from "./subscription-vip-offer-section";
|
||||
|
||||
const log = new Logger("SubscriptionCheckoutButton");
|
||||
|
||||
export interface SubscriptionCheckoutButtonProps {
|
||||
/** 是否可用(未选套餐或 VIP 套餐尚未确认自动续费时为 false) */
|
||||
/** 是否可用(未选套餐、缺少角色来源或支付处理中为 false) */
|
||||
disabled?: boolean;
|
||||
subscriptionType: "vip" | "topup";
|
||||
returnTo?: SubscriptionReturnTo;
|
||||
sourceCharacterSlug?: string;
|
||||
renewalPlan?: VipOfferPlanView | null;
|
||||
renewalConsentSubjectId?: string | null;
|
||||
}
|
||||
|
||||
export function SubscriptionCheckoutButton({
|
||||
@@ -32,7 +42,11 @@ export function SubscriptionCheckoutButton({
|
||||
subscriptionType,
|
||||
returnTo = null,
|
||||
sourceCharacterSlug = DEFAULT_CHARACTER_SLUG,
|
||||
renewalPlan = null,
|
||||
renewalConsentSubjectId = null,
|
||||
}: SubscriptionCheckoutButtonProps) {
|
||||
const [showRenewalConfirmation, setShowRenewalConfirmation] =
|
||||
useState(false);
|
||||
const payment = usePaymentState();
|
||||
const paymentDispatch = usePaymentDispatch();
|
||||
const paymentLaunch = usePaymentLaunchFlow({
|
||||
@@ -53,12 +67,32 @@ export function SubscriptionCheckoutButton({
|
||||
? "Creating order..."
|
||||
: readyLabel;
|
||||
|
||||
const handleClick = () => {
|
||||
const startCheckout = () => {
|
||||
if (disabled || isLoading) return;
|
||||
paymentLaunch.resetLaunchState();
|
||||
paymentDispatch({ type: "PaymentCreateOrderSubmitted" });
|
||||
};
|
||||
|
||||
const handleClick = () => {
|
||||
if (disabled || isLoading) return;
|
||||
if (
|
||||
payment.payChannel === "stripe" &&
|
||||
payment.autoRenew &&
|
||||
renewalPlan !== null &&
|
||||
!hasAutomaticRenewalAcknowledgement(renewalConsentSubjectId)
|
||||
) {
|
||||
setShowRenewalConfirmation(true);
|
||||
return;
|
||||
}
|
||||
startCheckout();
|
||||
};
|
||||
|
||||
const handleRenewalConfirm = () => {
|
||||
rememberAutomaticRenewalAcknowledgement(renewalConsentSubjectId);
|
||||
setShowRenewalConfirmation(false);
|
||||
startCheckout();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SubscriptionCtaButton
|
||||
@@ -105,6 +139,12 @@ export function SubscriptionCheckoutButton({
|
||||
ezpayDescription="Your order has been created. Continue to the secure payment page to finish."
|
||||
launch={paymentLaunch}
|
||||
/>
|
||||
<SubscriptionRenewalConfirmationDialog
|
||||
open={showRenewalConfirmation}
|
||||
plan={renewalPlan}
|
||||
onCancel={() => setShowRenewalConfirmation(false)}
|
||||
onConfirm={handleRenewalConfirm}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user