From 0658bd9a311d1ee303cb5b40b1f84e25b5559269 Mon Sep 17 00:00:00 2001 From: Antoine Clausse Date: Wed, 3 Jun 2026 13:43:42 +0200 Subject: [PATCH] [web] Change plans order in Change Plan modal (#34096) * [web] Order plans in Change Plan modal consistently Reorder the plans returned by `buildPlansListForSubscriptionDash` so the Subscription page "Change plan" modal lists them top-to-bottom as: 1. Student annual 2. Student monthly 3. Standard monthly 4. Standard annual 5. Pro monthly 6. Pro annual Previously `buildPlansList` produced three per-period buckets which the dash function concatenated, giving an order that flipped per family. Replace that with an explicit `CHANGE_PLAN_MODAL_PLAN_CODES` list so the order matches the Design QA spec at a glance. The now-unused `studentAccounts`, `individualMonthlyPlans`, `individualAnnualPlans`, `groupMonthlyPlans`, and `groupAnnualPlans` buckets are dropped from `buildPlansList` (no other callers). Closes #34024 Co-Authored-By: Claude Opus 4.7 (1M context) * [web] Update personal-plan acceptance test for new buildPlansList shape The previous test asserted `buildPlansList().individualMonthlyPlans`, which no longer exists after the change-plan modal reorder dropped the per-period buckets. Move the assertion to `buildPlansListForSubscriptionDash()`, which is where the personal-plan exclusion is now enforced (via `CHANGE_PLAN_MODAL_PLAN_CODES`). Co-Authored-By: Claude Opus 4.7 (1M context) * [web] Drop now-dead client-side plan filter `IndividualPlansTable` used to filter out `paid-personal`, `paid-personal-annual` and `institutional_commons` defensively because the old `buildPlansListForSubscriptionDash` returned every non-group plan that wasn't `hideFromUsers`. The previous commit pins the modal to an explicit six-plan list (`CHANGE_PLAN_MODAL_PLAN_CODES`), so none of those plan codes ever reach the frontend and the filter is dead. Remove it and the now-unused `useMemo` import. Co-Authored-By: Claude Opus 4.7 (1M context) * Revert "[web] Drop now-dead client-side plan filter" This reverts commit 83e8448f2cfa2c68e44b749d5a2bc350a7443c6d. We'll do that in a later cleanup * Swap "Student monthly" and "Student annual" for consistency --------- Co-authored-by: Claude Opus 4.7 (1M context) GitOrigin-RevId: 046a235e14e7ad6622288f5a5a723f5a4f7f14da --- .../SubscriptionViewModelBuilder.mjs | 69 +++++-------------- 1 file changed, 18 insertions(+), 51 deletions(-) diff --git a/services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.mjs b/services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.mjs index 049f518eaa..6cc04fa302 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.mjs +++ b/services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.mjs @@ -517,39 +517,19 @@ function buildPlansList(currentPlan, isInTrial) { ) } - result.studentAccounts = _.filter( - plans, - plan => plan.planCode.indexOf('student') !== -1 - ) - - result.groupMonthlyPlans = _.filter( - plans, - plan => plan.groupPlan && !plan.annual - ) - - result.groupAnnualPlans = _.filter( - plans, - plan => plan.groupPlan && plan.annual - ) - - result.individualMonthlyPlans = _.filter( - plans, - plan => - !plan.groupPlan && - !plan.annual && - plan.planCode !== 'personal' && // Prevent the personal plan from appearing on the change-plans page - plan.planCode.indexOf('student') === -1 - ) - - result.individualAnnualPlans = _.filter( - plans, - plan => - !plan.groupPlan && plan.annual && plan.planCode.indexOf('student') === -1 - ) - return result } +// Plan codes shown in the subscription dashboard "Change plan" modal, +const CHANGE_PLAN_MODAL_PLAN_CODES = [ + 'student', + 'student-annual', + 'collaborator', + 'collaborator-annual', + 'professional', + 'professional-annual', +] + function _isPlanEqualOrBetter(planA, planB) { return FeaturesHelper.isFeatureSetBetter( planA?.features || {}, @@ -596,28 +576,15 @@ function buildGroupSubscriptionForView(groupSubscription) { } function buildPlansListForSubscriptionDash(currentPlan, isInTrial) { - const allPlansData = buildPlansList(currentPlan, isInTrial) - const plans = [] - // only list individual and visible plans for "change plans" UI - if (allPlansData.studentAccounts) { - plans.push( - ...allPlansData.studentAccounts.filter(plan => !plan.hideFromUsers) - ) - } - if (allPlansData.individualMonthlyPlans) { - plans.push( - ...allPlansData.individualMonthlyPlans.filter(plan => !plan.hideFromUsers) - ) - } - if (allPlansData.individualAnnualPlans) { - plans.push( - ...allPlansData.individualAnnualPlans.filter(plan => !plan.hideFromUsers) - ) - } - + const { allPlans, planCodesChangingAtTermEnd } = buildPlansList( + currentPlan, + isInTrial + ) return { - plans, - planCodesChangingAtTermEnd: allPlansData.planCodesChangingAtTermEnd, + plans: CHANGE_PLAN_MODAL_PLAN_CODES.map(code => allPlans[code]).filter( + Boolean + ), + planCodesChangingAtTermEnd, } }