From 0f0f97a8f62208c0b2e6b3088611681ea3ceb648 Mon Sep 17 00:00:00 2001 From: Antoine Clausse Date: Wed, 25 Feb 2026 09:41:42 +0100 Subject: [PATCH] [web] Add student checkbox on Standard plan (#31773) * Remove plans-new.pug * Add ol-localIndividualPlans and its types * Add `getIndividualPlansInCurrency` util * Add `ol-localIndividualPlans` to the pages * Read prices from `localIndividualPlans` * Add student checkbox * Add `setupIndividualEduDiscount` * Add data tags * Update how original price is shown * Show original price for monthly collaborator * Make struck price conditionally invisible * Unnest `.plans-new-edu-discount` so it applies to collaborator student checkbox * Remove student column * Update prices in groups to remove _plans_localized_price.pug * Remove unused variables * Reduce spacing above the student checkbox * Fix tests * Move show/hide struck price for Collaborator Monthly out of loop * Fixup: Read prices from `localIndividualPlans` * Fix checkbox vertical alignment * Update services/web/frontend/stylesheets/pages/plans.scss Co-authored-by: roo hutton * Adjust margin-top for student checkbox to -12px * Disable autocomplete for education discount checkboxes See https://github.com/overleaf/internal/issues/31798 --------- Co-authored-by: roo hutton GitOrigin-RevId: f329321fc860f30f4e8921e2e1b18bc55cfdeb7b --- services/web/frontend/js/utils/meta.ts | 3 +- .../web/frontend/stylesheets/pages/plans.scss | 56 ++++++++++--------- services/web/locales/en.json | 1 + services/web/types/subscription/plan.ts | 6 ++ 4 files changed, 39 insertions(+), 27 deletions(-) diff --git a/services/web/frontend/js/utils/meta.ts b/services/web/frontend/js/utils/meta.ts index 64b9016210..0b8e49ab44 100644 --- a/services/web/frontend/js/utils/meta.ts +++ b/services/web/frontend/js/utils/meta.ts @@ -11,7 +11,7 @@ import { } from '../../../types/project-settings' import { CurrencyCode } from '../../../types/subscription/currency' import { PricingFormState } from '../../../types/subscription/payment-context-value' -import { Plan } from '../../../types/subscription/plan' +import { LocalIndividualPlans, Plan } from '../../../types/subscription/plan' import { Affiliation } from '../../../types/affiliation' import type { PortalTemplate } from '../../../types/portal-template' import { UserEmailData } from '../../../types/user-email' @@ -195,6 +195,7 @@ export interface Meta { 'ol-legacyEditorThemes': { name: string; dark: boolean }[] 'ol-licenseQuantity'?: number 'ol-loadingText': string + 'ol-localIndividualPlans': LocalIndividualPlans 'ol-managedGroupSubscriptions': ManagedGroupSubscription[] 'ol-managedInstitutions': ManagedInstitution[] 'ol-managedPublishers': Publisher[] diff --git a/services/web/frontend/stylesheets/pages/plans.scss b/services/web/frontend/stylesheets/pages/plans.scss index 2c7682e35d..3b00f46ec3 100644 --- a/services/web/frontend/stylesheets/pages/plans.scss +++ b/services/web/frontend/stylesheets/pages/plans.scss @@ -675,38 +675,42 @@ $z-index-group-member-picker-list: 1; } } } + } + } - .plans-new-edu-discount { - display: flex; - align-items: flex-start; - gap: var(--spacing-04); - margin-bottom: var(--spacing-06); - font-weight: 400; + .individual-edu-discount-form { + margin-top: calc(-1 * var(--spacing-05)); + } - input[type='checkbox'] { - margin: var(--spacing-02); - accent-color: var(--green-50); + .plans-new-edu-discount { + display: flex; + align-items: flex-start; + gap: var(--spacing-04); + margin-bottom: var(--spacing-06); + font-weight: 400; - &:focus-visible { - @include box-shadow-button-input; - } - } + input[type='checkbox'] { + margin: var(--spacing-03) var(--spacing-02); + accent-color: var(--green-50); - .plans-new-edu-discount-content { - display: flex; - flex-direction: column; + &:focus-visible { + @include box-shadow-button-input; + } + } - span { - line-height: var(--line-height-03); - color: var(--content-primary); - } + .plans-new-edu-discount-content { + display: flex; + flex-direction: column; - small { - color: var(--content-secondary); - font-size: var(--font-size-01); - line-height: var(--line-height-01); - } - } + span { + line-height: var(--line-height-03); + color: var(--content-primary); + } + + small { + color: var(--content-secondary); + font-size: var(--font-size-01); + line-height: var(--line-height-01); } } } diff --git a/services/web/locales/en.json b/services/web/locales/en.json index 8083813949..ba25ad0801 100644 --- a/services/web/locales/en.json +++ b/services/web/locales/en.json @@ -189,6 +189,7 @@ "apply_educational_discount": "Apply educational discount", "apply_educational_discount_description": "40% discount for groups using __appName__ for teaching", "apply_educational_discount_description_with_group_discount": "Get a total of 40% off for groups using __appName__ for teaching", + "apply_educational_discount_individual": "Apply 50% student discount", "apply_suggestion": "Apply suggestion", "april": "April", "archive": "Archive", diff --git a/services/web/types/subscription/plan.ts b/services/web/types/subscription/plan.ts index 6b632244ae..4a2aa7c1f8 100644 --- a/services/web/types/subscription/plan.ts +++ b/services/web/types/subscription/plan.ts @@ -113,3 +113,9 @@ export type StripeLookupKeyVersion = 'feb2026' export type StripeLookupKey = `${StripeBaseLookupKey}_${StripeLookupKeyVersion}_${StripeCurrencyCode}` + +export type IndividualPlanKey = 'collaborator' | 'professional' | 'student' +export type LocalIndividualPlans = Record< + IndividualPlanKey | 'free', + { monthly: number; annual: number } +>