diff --git a/services/web/app/src/Features/Subscription/SubscriptionController.js b/services/web/app/src/Features/Subscription/SubscriptionController.js index 62568cffbe..0b63a56ccb 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionController.js +++ b/services/web/app/src/Features/Subscription/SubscriptionController.js @@ -48,6 +48,14 @@ async function userSubscriptionPage(req, res) { await SplitTestHandler.promises.getAssignment(req, res, 'pause-subscription') + const groupPricingDiscount = await SplitTestHandler.promises.getAssignment( + req, + res, + 'group-discount-10' + ) + + const showGroupDiscount = groupPricingDiscount.variant === 'enabled' + const { variant: flexibleLicensingVariant } = await SplitTestHandler.promises.getAssignment( req, @@ -167,6 +175,7 @@ async function userSubscriptionPage(req, res) { managedGroupSubscriptions, managedInstitutions, managedPublishers, + showGroupDiscount, currentInstitutionsWithLicence, canUseFlexibleLicensing: personalSubscription?.plan?.canUseFlexibleLicensing, diff --git a/services/web/app/views/subscriptions/dashboard-react.pug b/services/web/app/views/subscriptions/dashboard-react.pug index 67380d660e..388f60c864 100644 --- a/services/web/app/views/subscriptions/dashboard-react.pug +++ b/services/web/app/views/subscriptions/dashboard-react.pug @@ -23,6 +23,7 @@ block append meta meta(name="ol-plans", data-type="json" content=plans) meta(name="ol-groupSettingsAdvertisedFor", data-type="json" content=groupSettingsAdvertisedFor) meta(name="ol-canUseFlexibleLicensing", data-type="boolean", content=canUseFlexibleLicensing) + meta(name="ol-showGroupDiscount", data-type="boolean", content=showGroupDiscount) meta(name="ol-groupSettingsEnabledFor", data-type="json" content=groupSettingsEnabledFor) meta(name="ol-user" data-type="json" content=user) if (personalSubscription && personalSubscription.recurly) diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index 8d8380cfc1..f5257e1acb 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -137,6 +137,7 @@ "anyone_with_link_can_view": "", "app_on_x": "", "appearance": "", + "apply_educational_discount_description_with_group_discount": "", "apply_suggestion": "", "archive": "", "archive_projects": "", @@ -199,8 +200,6 @@ "cancel": "", "cancel_add_on": "", "cancel_anytime": "", - "cancel_group_price_warning": "", - "cancel_group_price_warning_heading": "", "cancel_my_account": "", "cancel_my_subscription": "", "cancel_personal_subscription_first": "", @@ -890,7 +889,6 @@ "let_us_know_what_you_think": "", "lets_get_those_premium_features": "", "library": "", - "license_for_educational_purposes_confirmation": "", "limited_document_history": "", "limited_offer": "", "limited_to_n_editors": "", @@ -1416,6 +1414,7 @@ "save_or_cancel-cancel": "", "save_or_cancel-or": "", "save_or_cancel-save": "", + "save_x_or_more": "", "saving": "", "saving_notification_with_seconds": "", "search": "", diff --git a/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/cancel-subscription.tsx b/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/cancel-subscription.tsx index e4ca68ac74..504891cabb 100644 --- a/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/cancel-subscription.tsx +++ b/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/cancel-subscription.tsx @@ -15,8 +15,6 @@ import ExtendTrialButton from './extend-trial-button' import { useLocation } from '../../../../../../../shared/hooks/use-location' import { debugConsole } from '@/utils/debugging' import OLButton from '@/features/ui/components/ol/ol-button' -import moment from 'moment' -import OLNotification from '@/features/ui/components/ol/ol-notification' const planCodeToDowngradeTo = 'paid-personal' @@ -172,12 +170,6 @@ export function CancelSubscription() { return } - const startDate = moment.utc(personalSubscription.recurly.account.created_at) - const pricingChangeEffectiveDate = moment.utc('2025-01-08T12:00:00Z') - const displayPricingWarning = - personalSubscription.plan.groupPlan && - startDate.isBefore(pricingChangeEffectiveDate) - async function handleCancelSubscription() { try { await runAsyncCancel(postJSON(cancelSubscriptionUrl)) @@ -191,19 +183,6 @@ export function CancelSubscription() { return ( <> - {displayPricingWarning && ( - -

- {t('cancel_group_price_warning_heading')} -

-

{t('cancel_group_price_warning')}

- - } - /> - )}

{t('wed_love_you_to_stay')} diff --git a/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/change-to-group-modal.tsx b/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/change-to-group-modal.tsx index 822afc269d..a6f89623c9 100644 --- a/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/change-to-group-modal.tsx +++ b/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/change-to-group-modal.tsx @@ -118,6 +118,7 @@ export function ChangeToGroupModal() { const { modal: contactModal, showModal: showContactModal } = useContactUsModal({ autofillProjectUrl: false }) const groupPlans = getMeta('ol-groupPlans') + const showGroupDiscount = getMeta('ol-showGroupDiscount') const personalSubscription = getMeta('ol-subscription') as RecurlySubscription const [error, setError] = useState(false) const [inflight, setInflight] = useState(false) @@ -172,6 +173,11 @@ export function ChangeToGroupModal() { {t('customize_your_group_subscription')} + {showGroupDiscount && ( +

+ {t('save_x_or_more', { percentage: '10%' })} +

+ )} @@ -259,20 +265,9 @@ export function ChangeToGroupModal() { setGroupPlanToChangeToUsage('enterprise') } }} - label={ - , - /* eslint-disable-next-line react/jsx-key */ -
, - ]} - /> - } + label={t( + 'apply_educational_discount_description_with_group_discount' + )} />
diff --git a/services/web/frontend/js/utils/meta.ts b/services/web/frontend/js/utils/meta.ts index d8e0382999..7922f9f0cb 100644 --- a/services/web/frontend/js/utils/meta.ts +++ b/services/web/frontend/js/utils/meta.ts @@ -194,6 +194,7 @@ export interface Meta { 'ol-showAiErrorAssistant': boolean 'ol-showBrlGeoBanner': boolean 'ol-showCouponField': boolean + 'ol-showGroupDiscount': boolean 'ol-showGroupsAndEnterpriseBanner': boolean 'ol-showInrGeoBanner': boolean 'ol-showLATAMBanner': boolean diff --git a/services/web/frontend/stylesheets/bootstrap-5/pages/subscription.scss b/services/web/frontend/stylesheets/bootstrap-5/pages/subscription.scss index 34ec1135a0..61dcc49504 100644 --- a/services/web/frontend/stylesheets/bootstrap-5/pages/subscription.scss +++ b/services/web/frontend/stylesheets/bootstrap-5/pages/subscription.scss @@ -37,6 +37,13 @@ * MODALS */ +.group-subscription-modal-title-discount { + @include body-base; + + margin-top: var(--spacing-02); + margin-bottom: unset; +} + .group-subscription-modal { .circle { font-size: var(--font-size-06); diff --git a/services/web/locales/en.json b/services/web/locales/en.json index e5a7d23624..03e7cfb9f3 100644 --- a/services/web/locales/en.json +++ b/services/web/locales/en.json @@ -261,8 +261,6 @@ "cancel": "Cancel", "cancel_add_on": "Cancel add-on", "cancel_anytime": "We’re confident that you’ll love __appName__, but if not you can cancel anytime. We’ll give you your money back, no questions asked, if you let us know within 30 days.", - "cancel_group_price_warning": "Our per-user prices are increasing in 2025. Keep your current rate for existing and new users by staying with us.", - "cancel_group_price_warning_heading": "Don’t lose your current pricing", "cancel_my_account": "Cancel my subscription", "cancel_my_subscription": "Cancel my subscription", "cancel_personal_subscription_first": "You already have an individual subscription, would you like us to cancel this first before joining the group licence?", @@ -1172,7 +1170,6 @@ "libraries": "Libraries", "library": "Library", "license": "License", - "license_for_educational_purposes_confirmation": "<0>__percent__% educational discount<1/>I confirm this subscription is for educational purposes (applies to students or faculty using __appName__ for teaching)", "limited_document_history": "Limited document history", "limited_to_n_editors": "Limited to __count__ editor", "limited_to_n_editors_per_project": "Limited to __count__ editor per project", @@ -1876,6 +1873,7 @@ "save_or_cancel-cancel": "Cancel", "save_or_cancel-or": "or", "save_or_cancel-save": "Save", + "save_x_or_more": "Save __percentage__ or more", "saving": "Saving", "saving_notification_with_seconds": "Saving __docname__... (__seconds__ seconds of unsaved changes)", "search": "Search", diff --git a/services/web/test/frontend/features/subscription/components/dashboard/states/active/change-plan/change-plan.test.tsx b/services/web/test/frontend/features/subscription/components/dashboard/states/active/change-plan/change-plan.test.tsx index bbd0755e40..e2bc6fecc7 100644 --- a/services/web/test/frontend/features/subscription/components/dashboard/states/active/change-plan/change-plan.test.tsx +++ b/services/web/test/frontend/features/subscription/components/dashboard/states/active/change-plan/change-plan.test.tsx @@ -322,7 +322,7 @@ describe('', function () { const standardPlanCollaboratorText = '10 collaborators per project' const professionalPlanCollaboratorText = 'Unlimited collaborators' const educationInputLabel = - '40% educational discountI confirm this subscription is for educational purposes (applies to students or faculty using Overleaf for teaching)' + 'Get a total of 40% off for groups using Overleaf for teaching' let modal: HTMLElement async function openModal() { @@ -368,15 +368,14 @@ describe('', function () { expect(sizeSelect.value).to.equal('10') const sizeOption = within(sizeSelect).getAllByRole('option') expect(sizeOption.length).to.equal(groupPlans.sizes.length) - within(modal).getByText('40% educational discount') + within(modal).getByText( + 'Get a total of 40% off for groups using Overleaf for teaching' + ) const educationalCheckbox = within(modal).getByRole( 'checkbox' ) as HTMLInputElement expect(educationalCheckbox.checked).to.be.false - within(modal).getByText( - 'I confirm this subscription is for educational purposes (applies to students or faculty using Overleaf for teaching)' - ) within(modal).getByText( 'Your new subscription will be billed immediately to your current payment method.'