fix(充值弹窗): 当前档位改从未过滤目录解析
- 有效会员的当前档位被后台临时禁用时,filter 后的 membershipPlans 查不到,状态卡退化成「会员」、按钮变「开通会员」,可在有效会员上重复开通(评审第 5 条) - 结算弹窗升级摘要的 currentPlan 同样取自过滤列表,禁用档位会丢「原套餐标准价」;改由父组件传入未过滤目录解析出的 currentPlan,并移除弹窗对 membership 的无用依赖(评审第 11 条) - 新增回归:active 会员 + 当前档 disabled 时仍显示「当前 Plus · 年付」、Max 提供「补差升级」,摘要保留「原套餐标准年价」
This commit is contained in:
@@ -261,6 +261,50 @@ describe('PlatformProfileRechargeModal', () => {
|
||||
expect(onSubmitMembershipCheckout).toHaveBeenCalledWith('max', 'yearly');
|
||||
});
|
||||
|
||||
test('keeps an active member as member when their current plan is disabled', async () => {
|
||||
const user = userEvent.setup();
|
||||
const onRequestMembershipQuote = vi.fn();
|
||||
|
||||
render(
|
||||
<PlatformProfileRechargeModal
|
||||
center={{
|
||||
mudPointBalance: buildMudPointBalance(615),
|
||||
membership: buildActiveMembership('plus', 'yearly'),
|
||||
pointProducts: buildPointProducts(),
|
||||
// plus 在后台被临时禁用:目录里仍有该档,但过滤后的可购买列表只剩 max。
|
||||
membershipPlans: [{ ...PLUS_PLAN, enabled: false }, MAX_PLAN],
|
||||
latestOrder: null,
|
||||
hasPointsRecharged: true,
|
||||
}}
|
||||
isLoading={false}
|
||||
error={null}
|
||||
submittingProductId={null}
|
||||
nativePayment={null}
|
||||
membershipQuote={null}
|
||||
isLoadingMembershipQuote={false}
|
||||
membershipQuoteError={null}
|
||||
onClose={vi.fn()}
|
||||
onRetry={vi.fn()}
|
||||
onBuy={vi.fn()}
|
||||
onRequestMembershipQuote={onRequestMembershipQuote}
|
||||
onSubmitMembershipCheckout={vi.fn()}
|
||||
onConfirmNativePayment={vi.fn()}
|
||||
onCloseNativePayment={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
|
||||
// 状态卡仍认得当前档位,而不是退化成「会员」。
|
||||
expect(screen.getByText('当前 Plus · 年付')).toBeTruthy();
|
||||
// 有效会员看到的是补差升级,而不是可在有效会员上重复开通的「开通会员」。
|
||||
await user.click(screen.getByRole('button', { name: 'Max 年付 补差升级' }));
|
||||
expect(onRequestMembershipQuote).toHaveBeenCalledWith('max');
|
||||
|
||||
const checkout = screen.getByRole('dialog', { name: '确认套餐变更' });
|
||||
// 即使原档位已禁用,升级摘要也要给出「原套餐标准年价」。
|
||||
expect(within(checkout).getByText('原套餐标准年价')).toBeTruthy();
|
||||
expect(within(checkout).getByText('¥990')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('shows a placeholder instead of the list price while the upgrade quote is loading', async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
|
||||
@@ -936,7 +936,7 @@ function PlatformPointProductGrid({
|
||||
function PlatformRechargeCheckoutDialog({
|
||||
target,
|
||||
membershipPlans,
|
||||
membership,
|
||||
currentPlan,
|
||||
membershipQuote,
|
||||
isLoadingMembershipQuote,
|
||||
membershipQuoteError,
|
||||
@@ -949,7 +949,8 @@ function PlatformRechargeCheckoutDialog({
|
||||
}: {
|
||||
target: PlatformProfileRechargeCheckoutTarget;
|
||||
membershipPlans: ProfileMembershipPlanRecord[];
|
||||
membership: ProfileMembership | null;
|
||||
/** 会员当前档位;来自未过滤目录,档位被后台临时禁用时仍保留「原套餐标准价」。 */
|
||||
currentPlan: ProfileMembershipPlanRecord | null;
|
||||
membershipQuote: ProfileMembershipUpgradeQuote | null;
|
||||
isLoadingMembershipQuote: boolean;
|
||||
membershipQuoteError: string | null;
|
||||
@@ -1001,8 +1002,6 @@ function PlatformRechargeCheckoutDialog({
|
||||
? (plan?.yearPriceCents ?? 0)
|
||||
: (plan?.monthPriceCents ?? 0);
|
||||
const isUpgrade = target.mode === 'upgrade';
|
||||
const currentPlan =
|
||||
membershipPlans.find((item) => item.plan === membership?.plan) ?? null;
|
||||
const productId = resolveMembershipProductId(target.plan, target.cycleKind);
|
||||
const submitting = submittingProductId === productId;
|
||||
const quoteForTarget =
|
||||
@@ -1317,10 +1316,14 @@ export function PlatformProfileRechargeModal({
|
||||
() => center?.pointProducts ?? [],
|
||||
[center?.pointProducts],
|
||||
);
|
||||
// 当前档位必须从「未过滤目录」里查:会员有效期内若该档被后台临时禁用,
|
||||
// 过滤后的 membershipPlans 查不到会把有效会员误判成非会员(状态卡丢标题、按钮变「开通会员」)。
|
||||
const currentPlanRecord = useMemo(
|
||||
() =>
|
||||
membershipPlans.find((plan) => plan.plan === membership?.plan) ?? null,
|
||||
[membership?.plan, membershipPlans],
|
||||
(center?.membershipPlans ?? []).find(
|
||||
(plan) => plan.plan === membership?.plan,
|
||||
) ?? null,
|
||||
[center?.membershipPlans, membership?.plan],
|
||||
);
|
||||
const [activeTab, setActiveTab] =
|
||||
useState<PlatformProfileRechargeTab>('subscription');
|
||||
@@ -1546,7 +1549,7 @@ export function PlatformProfileRechargeModal({
|
||||
<PlatformRechargeCheckoutDialog
|
||||
target={checkout}
|
||||
membershipPlans={membershipPlans}
|
||||
membership={membership}
|
||||
currentPlan={currentPlanRecord}
|
||||
membershipQuote={membershipQuote}
|
||||
isLoadingMembershipQuote={isLoadingMembershipQuote}
|
||||
membershipQuoteError={membershipQuoteError}
|
||||
|
||||
Reference in New Issue
Block a user