Files
PolyWeather/frontend/lib/billing-utils.ts
T
2569718930@qq.com 3534f759d0 终端内直接弹出 UnlockProOverlay:订阅支付无需跳转账户页
新增 useTerminalPay hook 和 billing-utils 纯函数,SubscriptionGate 集成支付弹窗。
用户点击订阅后原地弹窗 → 连接钱包 → 链上支付 → 自动刷新进入终端。
2026-05-25 02:14:21 +08:00

70 lines
1.8 KiB
TypeScript

export interface TerminalBilling {
planAmount: number;
pointsEnabled: boolean;
pointsPerUsdc: number;
maxDiscountUsdc: number;
pointsUsed: number;
discountAmount: number;
payAmount: number;
canRedeem: boolean;
}
export interface PointsRedemptionConfig {
enabled?: boolean;
points_per_usdc?: number;
max_discount_usdc?: number;
}
export function computeBilling(params: {
planPriceUsd: number;
totalPoints: number;
usePoints: boolean;
redemptionCfg?: PointsRedemptionConfig | null;
}): TerminalBilling {
const planAmount =
Number.isFinite(params.planPriceUsd) && params.planPriceUsd > 0
? params.planPriceUsd
: 10;
const cfg = params.redemptionCfg || {};
const pointsEnabled = cfg.enabled !== false;
const pointsPerUsdcRaw = Number(cfg.points_per_usdc ?? 500);
const pointsPerUsdc =
Number.isFinite(pointsPerUsdcRaw) && pointsPerUsdcRaw > 0
? Math.floor(pointsPerUsdcRaw)
: 500;
const maxDiscountRaw = Number(cfg.max_discount_usdc ?? 3);
const maxDiscountUsdc = Math.max(
0,
Math.min(
Math.floor(Number.isFinite(maxDiscountRaw) ? maxDiscountRaw : 3),
Math.floor(planAmount),
),
);
const maxRedeemablePoints = pointsPerUsdc * maxDiscountUsdc;
const actualRedeem = pointsEnabled
? Math.min(params.totalPoints, maxRedeemablePoints)
: 0;
const discountUnits = Math.floor(actualRedeem / pointsPerUsdc);
const pointsUsed = discountUnits * pointsPerUsdc;
const canRedeem =
pointsEnabled &&
maxDiscountUsdc > 0 &&
params.totalPoints >= pointsPerUsdc;
const applyDiscount =
params.usePoints && canRedeem && pointsUsed > 0;
return {
planAmount,
pointsEnabled,
pointsPerUsdc,
maxDiscountUsdc,
pointsUsed,
discountAmount: discountUnits,
payAmount: planAmount - (applyDiscount ? discountUnits : 0),
canRedeem,
};
}