[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) <noreply@anthropic.com>

* [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) <noreply@anthropic.com>

* [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) <noreply@anthropic.com>

* 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) <noreply@anthropic.com>
GitOrigin-RevId: 046a235e14e7ad6622288f5a5a723f5a4f7f14da
This commit is contained in:
Antoine Clausse
2026-06-03 13:43:42 +02:00
committed by Copybot
parent b07d141397
commit 0658bd9a31
@@ -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,
}
}