refactor(subscription): tighten payment flow boundaries

This commit is contained in:
2026-06-30 15:36:49 +08:00
parent 61504050e5
commit 218df59345
9 changed files with 640 additions and 286 deletions
@@ -64,3 +64,61 @@ export function toCoinsOfferPlanView(plan: PaymentPlan): CoinsOfferPlanView {
currency: formatCoinCurrency(plan.currency),
};
}
export function toVipOfferPlanViews(
plans: readonly PaymentPlan[],
): VipOfferPlanView[] {
return plans.filter(isVipPlan).slice(0, 3).map(toVipOfferPlanView);
}
export function toCoinsOfferPlanViews(
plans: readonly PaymentPlan[],
): CoinsOfferPlanView[] {
return plans.filter(isCreditPlan).map(toCoinsOfferPlanView);
}
export function findSelectedSubscriptionPlan(input: {
canSubscribeVip: boolean;
selectedPlanId: string;
vipPlans: readonly VipOfferPlanView[];
coinPlans: readonly CoinsOfferPlanView[];
}): VipOfferPlanView | CoinsOfferPlanView | null {
const plans = input.canSubscribeVip
? [...input.vipPlans, ...input.coinPlans]
: input.coinPlans;
return plans.find((plan) => plan.id === input.selectedPlanId) ?? null;
}
export function getDefaultSubscriptionPlanId(input: {
canSubscribeVip: boolean;
selectedPlanId: string;
status: string;
isLoadingPlans: boolean;
selectedPlan: VipOfferPlanView | CoinsOfferPlanView | null;
vipPlans: readonly VipOfferPlanView[];
coinPlans: readonly CoinsOfferPlanView[];
}): string | null {
if (input.canSubscribeVip) {
const firstVipPlanId = input.vipPlans[0]?.id ?? "";
const hasSelectedVipPlan = input.vipPlans.some(
(plan) => plan.id === input.selectedPlanId,
);
const hasSelectedCoinsPlan = input.coinPlans.some(
(plan) => plan.id === input.selectedPlanId,
);
const canSelectPlan =
firstVipPlanId.length > 0 &&
(input.status === "ready" ||
input.status === "paid" ||
input.status === "failed");
if (!canSelectPlan || hasSelectedVipPlan || hasSelectedCoinsPlan) {
return null;
}
return firstVipPlanId;
}
if (input.isLoadingPlans || input.coinPlans.length === 0) return null;
if (input.selectedPlan !== null) return null;
return input.coinPlans[0]?.id ?? null;
}