diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json
index c84bad0dc3..b4de3719e5 100644
--- a/services/web/frontend/extracted-translations.json
+++ b/services/web/frontend/extracted-translations.json
@@ -126,6 +126,7 @@
"an_email_has_already_been_sent_to": "",
"an_error_occured_while_restoring_project": "",
"an_error_occurred_when_verifying_the_coupon_code": "",
+ "annual_discount": "",
"anonymous": "",
"anyone_with_link_can_edit": "",
"anyone_with_link_can_view": "",
@@ -1376,6 +1377,7 @@
"saml_missing_signature_error": "",
"saml_response": "",
"save": "",
+ "save_20_percent_when_you_switch_to_annual": "",
"save_or_cancel-cancel": "",
"save_or_cancel-or": "",
"save_or_cancel-save": "",
@@ -1595,6 +1597,7 @@
"sure_you_want_to_change_plan": "",
"sure_you_want_to_delete": "",
"sure_you_want_to_leave_group": "",
+ "switch_back_to_monthly_pay_20_more": "",
"switch_plan": "",
"switch_to_editor": "",
"switch_to_pdf": "",
@@ -1979,6 +1982,7 @@
"you_are_a_manager_of_publisher_x": "",
"you_are_a_manager_of_x_plan_as_member_of_group_subscription_y_administered_by_z": "",
"you_are_a_manager_of_x_plan_as_member_of_group_subscription_y_administered_by_z_you": "",
+ "you_are_now_saving_20_percent": "",
"you_are_on_a_paid_plan_contact_support_to_find_out_more": "",
"you_are_on_x_plan_as_a_confirmed_member_of_institution_y": "",
"you_are_on_x_plan_as_member_of_group_subscription_y_administered_by_z": "",
diff --git a/services/web/frontend/stylesheets/bootstrap-5/pages/subscription.scss b/services/web/frontend/stylesheets/bootstrap-5/pages/subscription.scss
index 2c0b75947d..77ff1f5f62 100644
--- a/services/web/frontend/stylesheets/bootstrap-5/pages/subscription.scss
+++ b/services/web/frontend/stylesheets/bootstrap-5/pages/subscription.scss
@@ -175,6 +175,10 @@
h4 {
margin-bottom: var(--spacing-06);
+
+ &:has(+ .payment-nudge-annual-button) {
+ margin-bottom: 0;
+ }
}
.features-list {
@@ -440,6 +444,16 @@
}
}
+.payment-nudge-annual-button {
+ margin: var(--spacing-02) 0 var(--spacing-06) 0;
+
+ @include body-sm;
+
+ button {
+ padding: 0;
+ }
+}
+
.add-on-card {
display: flex;
align-items: center;
diff --git a/services/web/locales/en.json b/services/web/locales/en.json
index 67d369dd90..ed0ac1b527 100644
--- a/services/web/locales/en.json
+++ b/services/web/locales/en.json
@@ -1837,6 +1837,7 @@
"saml_response": "SAML Response",
"save": "Save",
"save_20_percent": "save 20%",
+ "save_20_percent_when_you_switch_to_annual": "Save 20% when you switch to annual",
"save_or_cancel-cancel": "Cancel",
"save_or_cancel-or": "or",
"save_or_cancel-save": "Save",
@@ -2093,6 +2094,7 @@
"sure_you_want_to_delete": "Are you sure you want to permanently delete the following files?",
"sure_you_want_to_leave_group": "Are you sure you want to leave this group?",
"sv": "Swedish",
+ "switch_back_to_monthly_pay_20_more": "Switch back to monthly (20% more)",
"switch_plan": "Switch plan",
"switch_to_editor": "Switch to editor",
"switch_to_pdf": "Switch to PDF",
@@ -2537,6 +2539,7 @@
"you_are_a_manager_of_x_plan_as_member_of_group_subscription_y_administered_by_z": "You are a <1>manager1> of the <0>__planName__0> group subscription <1>__groupName__1> administered by <1>__adminEmail__1>.",
"you_are_a_manager_of_x_plan_as_member_of_group_subscription_y_administered_by_z_you": "You are a <1>manager1> of the <0>__planName__0> group subscription <1>__groupName__1> administered by <1>you (__adminEmail__1>).",
"you_are_currently_logged_in_as": "You are currently logged in as __email__.",
+ "you_are_now_saving_20_percent": "You are now saving 20%",
"you_are_on_a_paid_plan_contact_support_to_find_out_more": "You’re on an __appName__ Paid plan. <0>Contact support0> to find out more.",
"you_are_on_x_plan_as_a_confirmed_member_of_institution_y": "You are on our <0>__planName__0> plan as a <1>confirmed member1> of <1>__institutionName__1>",
"you_are_on_x_plan_as_member_of_group_subscription_y_administered_by_z": "You are on our <0>__planName__0> plan as a <1>member1> of the group subscription <1>__groupName__1> administered by <1>__adminEmail__1>",
diff --git a/services/web/types/recurly/pricing/subscription.ts b/services/web/types/recurly/pricing/subscription.ts
index 744d08c3ea..78b761fd61 100644
--- a/services/web/types/recurly/pricing/subscription.ts
+++ b/services/web/types/recurly/pricing/subscription.ts
@@ -5,7 +5,7 @@ import {
Tax,
} from 'recurly__recurly-js'
-interface Plan {
+export interface Plan {
code: string
name: string
period: {
diff --git a/services/web/types/subscription/payment-context-value.tsx b/services/web/types/subscription/payment-context-value.tsx
index 79dec23ef5..496f7e027b 100644
--- a/services/web/types/subscription/payment-context-value.tsx
+++ b/services/web/types/subscription/payment-context-value.tsx
@@ -4,6 +4,18 @@ import { SubscriptionPricingStateTax } from 'recurly__recurly-js'
import { SubscriptionPricingInstanceCustom } from '../recurly/pricing/subscription'
import { currencies, CurrencyCode } from './currency'
+export type RecurlyPrice =
+ | {
+ subtotal: string
+ plan: string
+ addons: string
+ setup_fee: string
+ discount: string
+ tax: string
+ total: string
+ }
+ | undefined
+
export type PricingFormState = {
first_name: string
last_name: string
@@ -35,17 +47,7 @@ export type PaymentContextValue = {
pricing: React.MutableRefObject
recurlyLoading: boolean
recurlyLoadError: boolean
- recurlyPrice:
- | {
- subtotal: string
- plan: string
- addons: string
- setup_fee: string
- discount: string
- tax: string
- total: string
- }
- | undefined
+ recurlyPrice: RecurlyPrice
monthlyBilling: boolean | undefined
taxes: SubscriptionPricingStateTax[]
coupon:
@@ -71,4 +73,5 @@ export type PaymentContextValue = {
React.SetStateAction
>
updatePlan: (newPlanCode: string) => void
+ showNudgeToAnnualText: boolean
}