feat(subscription): add VIP renewal price notice

This commit is contained in:
2026-07-15 11:50:44 +08:00
parent a7c1574e58
commit 3f3d1a0203
4 changed files with 42 additions and 1 deletions
@@ -200,16 +200,32 @@ describe("subscription screen helpers", () => {
expect(
getFirstRechargeOfferView({
isFirstRecharge: true,
subscriptionType: "vip",
vipPlans: vipViews,
coinPlans: coinViews,
}),
).toMatchObject({
badgeText: "50% OFF",
title: "First Recharge Offer",
renewalNotice:
"First month 50% off. Renews at the regular price from the second month.",
});
expect(
getFirstRechargeOfferView({
isFirstRecharge: true,
subscriptionType: "topup",
vipPlans: vipViews,
coinPlans: coinViews,
}),
).toMatchObject({
badgeText: "50% OFF",
title: "First Recharge Offer",
renewalNotice: null,
});
expect(
getFirstRechargeOfferView({
isFirstRecharge: false,
subscriptionType: "vip",
vipPlans: vipViews,
coinPlans: coinViews,
}),
@@ -68,6 +68,14 @@
line-height: 1.25;
}
.firstRechargeRenewalNotice {
margin: var(--responsive-inline-gap-xs, 4px) 0 0;
color: #a23869;
font-size: var(--responsive-micro, 12px);
font-weight: 800;
line-height: 1.3;
}
.offerStack {
display: flex;
flex-direction: column;
@@ -12,6 +12,7 @@ export interface FirstRechargeOfferView {
badgeText: string;
title: string;
subtitle: string;
renewalNotice: string | null;
}
export function canChooseSubscriptionPayChannel(
@@ -159,6 +160,7 @@ export function getDefaultSubscriptionPlanId(input: {
export function getFirstRechargeOfferView(input: {
isFirstRecharge: boolean;
subscriptionType: SubscriptionType;
vipPlans: readonly VipOfferPlanView[];
coinPlans: readonly CoinsOfferPlanView[];
}): FirstRechargeOfferView | null {
@@ -176,5 +178,9 @@ export function getFirstRechargeOfferView(input: {
title: "First Recharge Offer",
subtitle:
"Your first recharge price is already applied. No code needed.",
renewalNotice:
input.subscriptionType === "vip"
? "First month 50% off. Renews at the regular price from the second month."
: null,
};
}
+12 -1
View File
@@ -99,10 +99,16 @@ export function SubscriptionScreen({
() =>
getFirstRechargeOfferView({
isFirstRecharge: payment.isFirstRecharge,
subscriptionType,
vipPlans: vipOfferPlans,
coinPlans: directCoinsPlans,
}),
[directCoinsPlans, payment.isFirstRecharge, vipOfferPlans],
[
directCoinsPlans,
payment.isFirstRecharge,
subscriptionType,
vipOfferPlans,
],
);
const selectedPlan = findSelectedSubscriptionPlan({
@@ -207,6 +213,11 @@ export function SubscriptionScreen({
<p className={styles.firstRechargeSubtitle}>
{firstRechargeOffer.subtitle}
</p>
{firstRechargeOffer.renewalNotice ? (
<p className={styles.firstRechargeRenewalNotice}>
{firstRechargeOffer.renewalNotice}
</p>
) : null}
</div>
</section>
) : null}