[web] New Plans Page for A/B Test (#7330)

GitOrigin-RevId: 4e4629583c6e86bd2bc6165d123224734c133df7
This commit is contained in:
M Fahru 2022-05-12 07:38:02 -04:00 committed by Copybot
parent e9e429d339
commit 8157616f85
18 changed files with 3268 additions and 16 deletions

View file

@ -9,6 +9,7 @@ const logger = require('@overleaf/logger')
const GeoIpLookup = require('../../infrastructure/GeoIpLookup')
const FeaturesUpdater = require('./FeaturesUpdater')
const planFeatures = require('./planFeatures')
const planFeaturesV2 = require('./planFeaturesV2')
const GroupPlansData = require('./GroupPlansData')
const V1SubscriptionManager = require('./V1SubscriptionManager')
const Errors = require('../Errors/Errors')
@ -57,6 +58,17 @@ async function plansPage(req, res) {
AnalyticsManager.recordEventForSession(req.session, 'plans-page-view')
const newPlansPageAssignmentV2 =
await SplitTestHandler.promises.getAssignment(
req,
res,
'plans-page-layout-v2'
)
const newPlansPageVariantV2 =
newPlansPageAssignmentV2 &&
newPlansPageAssignmentV2.variant === 'new-plans-page'
const standardPlanNameAssignment =
await SplitTestHandler.promises.getAssignment(
req,
@ -68,13 +80,17 @@ async function plansPage(req, res) {
standardPlanNameAssignment &&
standardPlanNameAssignment.variant === 'new-plan-name'
res.render('subscriptions/plans-marketing', {
const template = newPlansPageVariantV2
? 'subscriptions/plans-marketing-v2'
: 'subscriptions/plans-marketing'
res.render(template, {
title: 'plans_and_pricing',
plans,
itm_content: req.query && req.query.itm_content,
recomendedCurrency: recommendedCurrency,
recommendedCurrency,
planFeatures,
planFeatures: newPlansPageVariantV2 ? planFeaturesV2 : planFeatures,
groupPlans: GroupPlansData,
groupPlanModalOptions,
groupPlanModalDefaults,

View file

@ -0,0 +1,720 @@
const individualPlans = [
{
divider: false,
items: [
{
feature: 'number_of_users',
info: 'number_of_users_info',
value: 'str',
plans: {
free: '1 users',
personal: '1 users',
collaborator: '1 users',
professional: '1 users',
},
},
{
feature: 'max_collab_per_project',
info: 'max_collab_per_project_info',
value: 'str',
plans: {
free: 'You + 1',
personal: 'You + 1',
collaborator: 'You + 10',
professional: 'Unlimited',
},
},
],
},
{
divider: true,
dividerLabel: 'you_and_collaborators_get_access_to',
dividerInfo: 'you_and_collaborators_get_access_to_info',
items: [
{
feature: 'compile_timeout_short',
info: 'compile_timeout_short_info',
value: 'str',
plans: {
free: '1 minute',
personal: '4 minutes',
collaborator: '4 minutes',
professional: '4 minutes',
},
},
{
feature: 'realtime_track_changes',
info: 'realtime_track_changes_info_v2',
value: 'bool',
plans: {
free: false,
personal: false,
collaborator: true,
professional: true,
},
},
{
feature: 'full_doc_history',
info: 'full_doc_history_info_v2',
value: 'bool',
plans: {
free: false,
personal: true,
collaborator: true,
professional: true,
},
},
{
feature: 'reference_search',
info: 'reference_search_info_v2',
value: 'bool',
plans: {
free: false,
personal: true,
collaborator: true,
professional: true,
},
},
{
feature: 'git_integration_lowercase',
info: 'git_integration_lowercase_info',
value: 'bool',
plans: {
free: false,
personal: true,
collaborator: true,
professional: true,
},
},
],
},
{
divider: true,
dividerLabel: 'you_get_access_to',
dividerInfo: 'you_get_access_to_info',
items: [
{
feature: 'powerful_latex_editor_and_realtime_collaboration',
info: 'powerful_latex_editor_and_realtime_collaboration_info',
value: 'bool',
plans: {
free: true,
personal: true,
collaborator: true,
professional: true,
},
},
{
feature: 'unlimited_projects',
info: 'unlimited_projects_info',
value: 'bool',
plans: {
free: true,
personal: true,
collaborator: true,
professional: true,
},
},
{
feature: 'thousands_templates',
info: 'hundreds_templates_info',
value: 'bool',
plans: {
free: true,
personal: true,
collaborator: true,
professional: true,
},
},
{
feature: 'symbol_palette',
info: 'symbol_palette_info',
value: 'bool',
plans: {
free: false,
personal: true,
collaborator: true,
professional: true,
},
},
{
feature: 'github_only_integration_lowercase',
info: 'github_only_integration_lowercase_info',
value: 'bool',
plans: {
free: false,
personal: true,
collaborator: true,
professional: true,
},
},
{
feature: 'dropbox_integration_lowercase',
info: 'dropbox_integration_info',
value: 'bool',
plans: {
free: false,
personal: true,
collaborator: true,
professional: true,
},
},
{
feature: 'mendeley_integration_lowercase',
info: 'mendeley_integration_lowercase_info',
value: 'bool',
plans: {
free: false,
personal: true,
collaborator: true,
professional: true,
},
},
{
feature: 'zotero_integration_lowercase',
info: 'zotero_integration_lowercase_info',
value: 'bool',
plans: {
free: false,
personal: true,
collaborator: true,
professional: true,
},
},
{
feature: 'priority_support',
info: 'priority_support_info',
value: 'bool',
plans: {
free: false,
personal: true,
collaborator: true,
professional: true,
},
},
],
},
]
const groupPlans = [
{
divider: false,
items: [
{
feature: 'number_of_users',
info: 'number_of_users_info',
value: 'str',
plans: {
group_standard: '2 - 50 users',
group_professional: '2 - 50 users',
organization: 'Contact sales',
},
},
{
feature: 'max_collab_per_project',
info: 'max_collab_per_project_info',
value: 'str',
plans: {
group_standard: 'Project author + 10',
group_professional: 'Unlimited',
organization: 'Unlimited',
},
},
],
},
{
divider: true,
dividerLabel: 'group_admins_get_access_to',
dividerInfo: 'group_admins_get_access_to_info',
items: [
{
feature: 'user_management',
info: 'user_management_info',
value: 'str',
plans: {
group_standard: 'admin panel',
group_professional: 'admin panel',
organization: 'automatic user registration',
},
},
{
feature: 'usage_metrics',
info: 'usage_metrics_info',
value: 'bool',
plans: {
group_standard: true,
group_professional: true,
organization: true,
},
},
{
feature: 'sso_integration',
info: 'sso_integration_info',
value: 'bool',
plans: {
group_standard: false,
group_professional: false,
organization: true,
},
},
{
feature: 'sitewide_option_available',
info: 'sitewide_option_available_info',
value: 'bool',
plans: {
group_standard: false,
group_professional: false,
organization: true,
},
},
{
feature: 'custom_resource_portal',
info: 'custom_resource_portal_info',
value: 'bool',
plans: {
group_standard: false,
group_professional: false,
organization: true,
},
},
{
feature: 'personalised_onboarding',
info: 'personalised_onboarding_info',
value: 'bool',
plans: {
group_standard: false,
group_professional: false,
organization: true,
},
},
{
feature: 'dedicated_account_manager',
info: 'dedicated_account_manager_info',
value: 'bool',
plans: {
group_standard: false,
group_professional: false,
organization: true,
},
},
],
},
{
divider: true,
dividerLabel: 'group_members_and_collaborators_get_access_to',
dividerInfo: 'group_members_and_collaborators_get_access_to_info',
items: [
{
feature: 'compile_timeout_short',
info: 'compile_timeout_short_info',
value: 'str',
plans: {
group_standard: '4 minutes',
group_professional: '4 minutes',
organization: '4 minutes',
},
},
{
feature: 'realtime_track_changes',
info: 'realtime_track_changes_info_v2',
value: 'bool',
plans: {
group_standard: true,
group_professional: true,
organization: true,
},
},
{
feature: 'full_doc_history',
info: 'full_doc_history_info_v2',
value: 'bool',
plans: {
group_standard: true,
group_professional: true,
organization: true,
},
},
{
feature: 'reference_search',
info: 'reference_search_info_v2',
value: 'bool',
plans: {
group_standard: true,
group_professional: true,
organization: true,
},
},
{
feature: 'git_integration_lowercase',
info: 'git_integration_lowercase_info',
value: 'bool',
plans: {
group_standard: true,
group_professional: true,
organization: true,
},
},
],
},
{
divider: true,
dividerLabel: 'group_members_get_access_to',
dividerInfo: 'group_members_get_access_to_info',
items: [
{
feature: 'powerful_latex_editor_and_realtime_collaboration',
info: 'powerful_latex_editor_and_realtime_collaboration_info',
value: 'bool',
plans: {
group_standard: true,
group_professional: true,
organization: true,
},
},
{
feature: 'unlimited_projects',
info: 'unlimited_projects_info',
value: 'bool',
plans: {
group_standard: true,
group_professional: true,
organization: true,
},
},
{
feature: 'thousands_templates',
info: 'hundreds_templates_info',
value: 'bool',
plans: {
group_standard: true,
group_professional: true,
organization: true,
},
},
{
feature: 'symbol_palette',
info: 'symbol_palette_info',
value: 'bool',
plans: {
group_standard: true,
group_professional: true,
organization: true,
},
},
{
feature: 'github_only_integration_lowercase',
info: 'github_only_integration_lowercase_info',
value: 'bool',
plans: {
group_standard: true,
group_professional: true,
organization: true,
},
},
{
feature: 'dropbox_integration_lowercase',
info: 'dropbox_integration_info',
value: 'bool',
plans: {
group_standard: true,
group_professional: true,
organization: true,
},
},
{
feature: 'mendeley_integration_lowercase',
info: 'mendeley_integration_lowercase_info',
value: 'bool',
plans: {
group_standard: true,
group_professional: true,
organization: true,
},
},
{
feature: 'zotero_integration_lowercase',
info: 'zotero_integration_lowercase_info',
value: 'bool',
plans: {
group_standard: true,
group_professional: true,
organization: true,
},
},
{
feature: 'priority_support',
info: 'priority_support_info',
value: 'bool',
plans: {
group_standard: true,
group_professional: true,
organization: true,
},
},
],
},
]
const studentPlans = [
{
divider: false,
items: [
{
feature: 'number_of_users',
info: 'number_of_users_info',
value: 'str',
plans: {
free: '1 users',
student: '1 users',
university: 'Multiple users',
},
},
{
feature: 'max_collab_per_project',
info: 'max_collab_per_project_info',
value: 'str',
plans: {
free: 'You + 1',
student: 'You + 6',
university: 'Project author + 10 or unlimited',
},
},
],
},
{
divider: true,
dividerLabel: 'you_and_collaborators_get_access_to',
dividerInfo: 'you_and_collaborators_get_access_to_info',
items: [
{
feature: 'compile_timeout_short',
info: 'compile_timeout_short_info',
value: 'str',
plans: {
free: '1 minute',
student: '4 minutes',
university: '4 minutes',
},
},
{
feature: 'realtime_track_changes',
info: 'realtime_track_changes_info_v2',
value: 'bool',
plans: {
free: false,
student: true,
university: true,
},
},
{
feature: 'full_doc_history',
info: 'full_doc_history_info_v2',
value: 'bool',
plans: {
free: false,
student: true,
university: true,
},
},
{
feature: 'reference_search',
info: 'reference_search_info_v2',
value: 'bool',
plans: {
free: false,
student: true,
university: true,
},
},
{
feature: 'git_integration_lowercase',
info: 'git_integration_lowercase_info',
value: 'bool',
plans: {
free: false,
student: true,
university: true,
},
},
],
},
{
divider: true,
dividerLabel: 'you_get_access_to',
dividerInfo: 'you_get_access_to_info',
items: [
{
feature: 'powerful_latex_editor_and_realtime_collaboration',
info: 'powerful_latex_editor_and_realtime_collaboration_info',
value: 'bool',
plans: {
free: true,
student: true,
university: true,
},
},
{
feature: 'unlimited_projects',
info: 'unlimited_projects_info',
value: 'bool',
plans: {
free: true,
student: true,
university: true,
},
},
{
feature: 'thousands_templates',
info: 'thousands_templates_info',
value: 'bool',
plans: {
free: true,
student: true,
university: true,
},
},
{
feature: 'symbol_palette',
info: 'symbol_palette_info',
value: 'bool',
plans: {
free: false,
student: true,
university: true,
},
},
{
feature: 'github_only_integration_lowercase',
info: 'github_only_integration_lowercase_info',
value: 'bool',
plans: {
free: false,
student: true,
university: true,
},
},
{
feature: 'dropbox_integration_lowercase',
info: 'dropbox_integration_info',
value: 'bool',
plans: {
free: false,
student: true,
university: true,
},
},
{
feature: 'mendeley_integration_lowercase',
info: 'mendeley_integration_lowercase_info',
value: 'bool',
plans: {
free: false,
student: true,
university: true,
},
},
{
feature: 'zotero_integration_lowercase',
info: 'zotero_integration_lowercase_info',
value: 'bool',
plans: {
free: false,
student: true,
university: true,
},
},
{
feature: 'priority_support',
info: 'priority_support_info',
value: 'bool',
plans: {
free: false,
student: true,
university: true,
},
},
],
},
{
divider: true,
dividerLabel: 'group_admins_get_access_to',
dividerInfo: 'group_admins_get_access_to_info',
items: [
{
feature: 'user_management',
info: 'user_management_info',
value: 'bool',
plans: {
free: false,
student: false,
university: true,
},
},
{
feature: 'usage_metrics',
info: 'usage_metrics_info',
value: 'bool',
plans: {
free: false,
student: false,
university: true,
},
},
{
feature: 'sso_integration',
info: 'sso_integration_info',
value: 'bool',
plans: {
free: false,
student: false,
university: true,
},
},
{
feature: 'sitewide_option_available',
info: 'sitewide_option_available_info',
value: 'bool',
plans: {
free: false,
student: false,
university: true,
},
},
{
feature: 'custom_resource_portal',
info: 'custom_resource_portal_info',
value: 'bool',
plans: {
free: false,
student: false,
university: true,
},
},
{
feature: 'personalised_onboarding',
info: 'personalised_onboarding_info',
value: 'bool',
plans: {
free: false,
student: false,
university: true,
},
},
{
feature: 'dedicated_account_manager',
info: 'dedicated_account_manager_info',
value: 'bool',
plans: {
free: false,
student: false,
university: true,
},
},
],
},
]
module.exports = {
individual: individualPlans,
group: groupPlans,
student: studentPlans,
}

View file

@ -0,0 +1,58 @@
extends ../layout-marketing
include ./plans-marketing/_mixins
include ./plans-marketing/_tables
block vars
- entrypoint = 'pages/user/subscription/plans-v2/plans-v2-main'
block append meta
meta(name="ol-recommendedCurrency" content=recommendedCurrency)
meta(name="ol-groupPlans" data-type="json" content=groupPlans)
meta(name="ol-currencySymbols" data-type="json" content=groupPlanModalOptions.currencySymbols)
meta(name="ol-itm_content" content=itm_content)
block content
main.content.content-alt#main-content
.content-page
.plans
.container(ng-cloak)
.row
.col-md-12
.page-header.centered.plans-header.text-centered.top-page-header
h1.text-capitalize(ng-non-bindable) #{translate('choose_your_plan')}
include ./plans-marketing/v2/_cards_controls_tables
.row.row-spaced-large.text-centered
.col-xs-12
p.text-centered #{translate("subject_to_additional_vat")}
i.fa.fa-cc-mastercard.fa-2x(aria-hidden="true")  
span.sr-only Mastercard accepted
i.fa.fa-cc-visa.fa-2x(aria-hidden="true")  
span.sr-only Visa accepted
i.fa.fa-cc-amex.fa-2x(aria-hidden="true")  
span.sr-only Amex accepted
i.fa.fa-cc-paypal.fa-2x(aria-hidden="true")  
span.sr-only Paypal accepted
include ./plans-marketing/_quotes
include ./plans-marketing/v2/_faq
#bottom-cards.row.row-spaced(style="display: none;")
.col-sm-12
+allCardsAndControls(true, 'bottom')
.row.row-spaced-large
.col-md-12
.plans-header.plans-subheader.text-centered
hr
h2.header-with-btn #{translate('still_have_questions')}
button.btn.plans-v2-btn-header.text-capitalize(
data-ol-open-contact-form-modal="general"
) #{translate('contact_us')}
.row.row-spaced
include ./plans-marketing/_group_plan_modal
!= moduleIncludes("contactModalGeneral-marketing", locals)

View file

@ -38,7 +38,13 @@ div.modal.fade(tabindex="-1" role="dialog" data-ol-group-plan-modal)
| Plan
for plan_code in groupPlanModalOptions.plan_codes
label.group-plan-option
input(type="radio" name="plan_code" checked=(plan_code.code === "collaborator") value=plan_code.code )
input(
type="radio"
name="plan_code"
checked=(plan_code.code === "collaborator")
value=plan_code.code
data-ol-group-plan-code=plan_code.code
)
if (useNewPlanName && plan_code.code === 'collaborator')
span Standard
else
@ -52,7 +58,7 @@ div.modal.fade(tabindex="-1" role="dialog" data-ol-group-plan-modal)
value=size
selected=(size === groupPlanModalDefaults.size)
) #{size}
.form-group
.form-group(data-ol-group-plan-form-currency)
label(for='currency')
| Currency
select.form-control(id="currency")
@ -65,7 +71,11 @@ div.modal.fade(tabindex="-1" role="dialog" data-ol-group-plan-modal)
label(for='usage')
| Overleaf offers a 40% educational discount for groups of 10 or more.
label.group-plan-option
input(id="usage", type="checkbox")
input(
id="usage"
type="checkbox"
autocomplete="off"
)
span This license is for educational purposes (applies to students or faculty using Overleaf for teaching)
.row

View file

@ -39,10 +39,10 @@ mixin table_premium
| #{plan}
else if plan
i.fa.fa-check(aria-hidden="true")
span.sr-only Feature included
span.sr-only #{translate("feature_included")}
else
i.fa.fa-times(aria-hidden="true")
span.sr-only Feature not included
span.sr-only #{translate("feature_not_included")}
tr
td
@ -62,10 +62,10 @@ mixin table_cell_student(feature)
| #{feature.student}
else if feature.student
i.fa.fa-check(aria-hidden="true")
span.sr-only Feature included
span.sr-only #{translate("feature_included")}
else
i.fa.fa-times(aria-hidden="true")
span.sr-only Feature not included
span.sr-only #{translate("feature_not_included")}
mixin table_student
table.card.plans-table.plans-table-student
@ -99,10 +99,10 @@ mixin table_student
| #{feature.plans.free}
else if feature.plans.free
i.fa.fa-check(aria-hidden="true")
span.sr-only Feature included
span.sr-only #{translate("feature_included")}
else
i.fa.fa-times(aria-hidden="true")
span.sr-only Feature included
span.sr-only #{translate("feature_not_included")}
td(ng-non-bindable)
+table_cell_student(feature)
td(ng-non-bindable)

View file

@ -0,0 +1,64 @@
include ./_mixins
.row.plans-v2-top-switch
.col-xs-12
ul.nav.plans-v2-nav
li.active.plans-v2-top-switch-individual(data-ol-plans-v2-view-tab='individual')
a.btn.btn-default-outline(
href="#"
) #{translate("indvidual_plans")}
li.plans-v2-top-switch-group(data-ol-plans-v2-view-tab='group')
a.btn.btn-default-outline(
href="#"
)
span #{translate("group_plans")}
span (save 30% or more)
li.plans-v2-top-switch-student(data-ol-plans-v2-view-tab='student')
a.btn.btn-default-outline(
href="#"
) #{translate("student_plans")}
.row
.col-md-4.col-md-offset-4.text-centered.plans-v2-m-a-switch-container(data-ol-plans-v2-m-a-switch-container)
span.underline(data-ol-plans-v2-m-a-switch-monthly-text) #{translate("monthly")}
label.plans-v2-m-a-switch(data-ol-plans-v2-m-a-switch)
input(
type="checkbox"
role="switch"
autocomplete="off"
)
span
div.plans-v2-m-a-switch-annual-text-container
span(data-ol-plans-v2-m-a-switch-annual-text) #{translate("annual")}
div.plans-v2-m-a-tooltip.plans-v2-m-a-tooltip-monthly(data-ol-plans-v2-m-a-tooltip)
div.plans-v2-m-a-tooltip-arrow
span(data-ol-tooltip-period='monthly') #{translate("save_20_percent_by_paying_annually")}
span(hidden data-ol-tooltip-period='annual') #{translate("saving_20_percent")}
.row(hidden data-ol-plans-v2-license-picker-container)
.col-sm-12
+group_plans_license_picker()
+table_sticky_header
.row.plans-v2-table-container(data-ol-plans-v2-table-container='monthly')
.col-sm-12(data-ol-plans-v2-view='individual')
.row
+table_individual('monthly')
.col-sm-12(hidden data-ol-plans-v2-view='student')
.row
+table_student('monthly')
.row.plans-v2-table-container(hidden data-ol-plans-v2-table-container='annual')
.col-sm-12(data-ol-plans-v2-view='individual')
.row
+table_individual('annual')
.col-sm-12(hidden data-ol-plans-v2-view='group')
.row
+table_group('annual')
.col-sm-12(hidden data-ol-plans-v2-view='student')
.row
+table_student('annual')
//- sticky header on mobile will be "hidden" (by removing its sticky position) if it reaches this div
.invisible(aria-hidden="true" data-ol-plans-v2-table-sticky-header-stop)

View file

@ -0,0 +1,25 @@
.faq.plans-v2-faq
.row.row-spaced-large
.col-md-12
.page-header.plans-header.plans-subheader.text-centered
h2 FAQ
.row
.col-md-12
h3 #{translate('faq_how_free_trial_works_question')}
p #{translate('faq_how_free_trial_works_answer_v2', { len:'7' })}
.row
.col-md-12
h3 #{translate('faq_change_plans_or_cancel_question')}
p #{translate('faq_change_plans_or_cancel_answer')}
.row
.col-md-12
h3 #{translate('faq_do_collab_need_on_paid_plan_question')}
p !{translate('faq_do_collab_need_on_paid_plan_answer', {}, [{ name: 'a', attrs: { href: "/learn/how-to/Overleaf_Accounts_and_Subscriptions", target: '_blank'}}, { name: 'a', attrs: { href: "/learn/how-to/Overleaf_premium_features", target: '_blank'}}])}
.row
.col-md-12
h3 #{translate('faq_how_does_a_group_plan_work_question')}
p !{translate('faq_how_does_a_group_plan_work_answer', {}, [{ name: 'a', attrs: { href: "/learn/how-to/Joining_an_Overleaf_Group_Subscription", target: '_blank'}}, { name: 'a', attrs: { href: "/learn/how-to/Managing_a_group_subscription", target: '_blank'}}, { name: 'a', attrs: { href: "/contact", target: '_blank'}}])}
.row
.col-md-12
h3 #{translate('faq_pay_by_invoice_question')}
p #{translate('faq_pay_by_invoice_answer_v2')}

View file

@ -0,0 +1,512 @@
mixin table_individual(period)
table.card.plans-v2-table.plans-v2-table-individual
tr
th
th
div.plans-v2-table-th-content
p.plans-v2-table-th-content-title #{translate("free")}
+table_head_price('free', period)
.plans-v2-table-btn-buy-container-mobile
+btn_buy_individual_free()
ul.plans-v2-table-th-content-benefit
li #{translate("only_one_collaborator")}
.plans-v2-table-btn-buy-container-desktop
+btn_buy_individual_free()
th.plans-v2-table-cell-before-highlighted-column
div.plans-v2-table-th-content
p.plans-v2-table-th-content-title #{translate("personal")}
+table_head_price('personal', period)
.plans-v2-table-btn-buy-container-mobile
+btn_buy_individual_personal(period)
ul.plans-v2-table-th-content-benefit
li #{translate("only_one_collaborator")}
li #{translate("most_premium_features")}
.plans-v2-table-btn-buy-container-desktop
+btn_buy_individual_personal(period)
th.plans-v2-table-green-highlighted
div.plans-v2-table-th-content
p.plans-v2-table-green-highlighted-text MOST POPULAR
p.plans-v2-table-th-content-title #{translate("standard")}
+table_head_price('collaborator', period)
.plans-v2-table-btn-buy-container-mobile
+btn_buy_individual_collaborator(period)
ul.plans-v2-table-th-content-benefit
li #{translate("only_one_collaborator")}
li #{translate("all_premium_features")}
.plans-v2-table-btn-buy-container-desktop
+btn_buy_individual_collaborator(period)
th
div.plans-v2-table-th-content
p.plans-v2-table-th-content-title #{translate("professional")}
+table_head_price('professional', period)
.plans-v2-table-btn-buy-container-mobile
+btn_buy_individual_professional()
ul.plans-v2-table-th-content-benefit
li !{translate("x_collaborators_per_project", {collaboratorsCount: '10'})}
li #{translate("all_premium_features")}
.plans-v2-table-btn-buy-container-desktop
+btn_buy_individual_professional(period)
for planFeaturesPerSection in planFeatures.individual
if planFeaturesPerSection.divider
tr.plans-v2-table-divider
td(colspan="5")
div
span.plans-v2-table-divider-label #{translate(planFeaturesPerSection.dividerLabel)}
//- will only appear on screen width >= 768px (using CSS)
i.fa.fa-question-circle.plans-v2-table-divider-question-icon(
data-toggle="tooltip"
title=translate(planFeaturesPerSection.dividerInfo),
data-placement="top"
)
//- will only appear on screen width < 768px (using CSS)
span.plans-v2-table-divider-learn-more-container
span (
span.plans-v2-table-divider-learn-more-text(
data-toggle="tooltip"
title=translate(planFeaturesPerSection.dividerInfo),
data-placement="top"
) #{translate("learn_more_lowercase")}
span )
for feature, featureIndex in planFeaturesPerSection.items
tr(
class=(featureIndex === (planFeaturesPerSection.items.length - 1) ? 'plans-v2-table-row-last-row-per-section' : '')
)
td(event-tracking="plans-page-table" event-tracking-trigger="hover" event-tracking-ga="subscription-funnel" event-tracking-label=`${feature.feature}`)
.plans-v2-table-feature-name
if feature.info
span #{translate(feature.feature)}
//- will only appear on screen width >= 768px (using CSS)
i.fa.fa-question-circle.plans-v2-table-feature-name-question-icon(
data-toggle="tooltip"
title=translate(feature.info),
data-placement="right"
)
//- will only appear on screen width < 768px (using CSS)
span.plans-v2-table-feature-name-learn-more-container
span (
span.plans-v2-table-feature-name-learn-more-text(
data-toggle="tooltip"
title=translate(feature.info),
data-placement="top"
) #{translate("learn_more_lowercase")}
span )
else
| #{translate(feature.feature)}
td(ng-non-bindable)
+table_cell(feature, 'free')
td.plans-v2-table-cell-before-highlighted-column(ng-non-bindable)
+table_cell(feature, 'personal')
td.plans-v2-table-green-highlighted(ng-non-bindable)
+table_cell(feature, 'collaborator')
td(ng-non-bindable)
+table_cell(feature, 'professional')
mixin table_group
table.card.plans-v2-table.plans-v2-table-group
tr
th
th.plans-v2-table-cell-before-highlighted-column
div.plans-v2-table-th-content
p.plans-v2-table-th-content-title #{translate("group_standard")}
div.plans-v2-table-price-container
strike.plans-v2-table-annual-price-before-discount(data-ol-plans-v2-table-annual-price-before-discount)
+gen_localized_price_for_plan_view('collaborator', 'annual')
p.plans-v2-table-price
span(data-ol-group-price-per-user='collaborator') $0
p.plans-v2-table-price-period-label
| per user / year
.plans-v2-table-btn-buy-container-mobile
+btn_buy_group_collaborator()
small.plans-v2-table-th-content-additional-link !{translate("or_contact_us", {}, [{name: 'a', attrs: {href: '/for/enterprises/sales-contact', target: '_blank'}}])}
ul.plans-v2-table-th-content-benefit
li #{translate("up_to")} !{translate("x_collaborators_per_project", {collaboratorsCount: '10'})}
li
span.plans-v2-group-total-price(data-ol-plans-v2-group-total-price='collaborator') $0
span &nbsp;#{translate("total_per_year_lowercase")}
.plans-v2-table-btn-buy-container-desktop
+btn_buy_group_collaborator()
small.plans-v2-table-th-content-additional-link !{translate("or_contact_us", {}, [{name: 'a', attrs: {href: '/for/enterprises/sales-contact', target: '_blank'}}])}
th.plans-v2-table-green-highlighted
div.plans-v2-table-th-content
p.plans-v2-table-green-highlighted-text RECOMMENDED
p.plans-v2-table-th-content-title #{translate("group_professional")}
div.plans-v2-table-price-container
strike.plans-v2-table-annual-price-before-discount(data-ol-plans-v2-table-annual-price-before-discount)
+gen_localized_price_for_plan_view('professional', 'annual')
p.plans-v2-table-price
span(data-ol-group-price-per-user='professional') $0
p.plans-v2-table-price-period-label
| per user / year
.plans-v2-table-btn-buy-container-mobile
+btn_buy_group_professional()
small.plans-v2-table-th-content-additional-link !{translate("or_contact_us", {}, [{name: 'a', attrs: {href: '/for/enterprises/sales-contact', target: '_blank'}}])}
ul.plans-v2-table-th-content-benefit
li #{translate("unlimited_collaborators_in_each_project")}
li
span.plans-v2-group-total-price(data-ol-plans-v2-group-total-price='professional') $0
span &nbsp;#{translate("total_per_year_lowercase")}
.plans-v2-table-btn-buy-container-desktop
+btn_buy_group_professional()
small.plans-v2-table-th-content-additional-link !{translate("or_contact_us", {}, [{name: 'a', attrs: {href: '/for/enterprises/sales-contact', target: '_blank'}}])}
th
div.plans-v2-table-th-content
p.plans-v2-table-th-content-title #{translate("organization")}
div.plans-v2-table-comments-icon
i.fa.fa-comments-o
.plans-v2-table-btn-buy-container-mobile
+btn_buy_group_organization()
small.plans-v2-table-th-content-additional-link.invisible(aria-hidden="true")
ul.plans-v2-table-th-content-benefit
li #{translate("best_choices_companies_universities_non_profits")}
li #{translate("for_groups_or_site_wide")}
li
a(href="/for/enterprises/sales-contact") #{translate("also_available_as_on_premises")}
.plans-v2-table-btn-buy-container-desktop
+btn_buy_group_organization()
small.plans-v2-table-th-content-additional-link.invisible(aria-hidden="true")
th
for planFeaturesPerSection in planFeatures.group
if planFeaturesPerSection.divider
tr.plans-v2-table-divider
td(colspan="4")
div
span.plans-v2-table-divider-label #{translate(planFeaturesPerSection.dividerLabel)}
//- will only appear on screen width >= 768px (using CSS)
i.fa.fa-question-circle.plans-v2-table-divider-question-icon(
data-toggle="tooltip"
title=translate(planFeaturesPerSection.dividerInfo),
data-placement="top"
)
//- will only appear on screen width < 768px (using CSS)
span.plans-v2-table-divider-learn-more-container
span (
span.plans-v2-table-divider-learn-more-text(
data-toggle="tooltip"
title=translate(planFeaturesPerSection.dividerInfo),
data-placement="top"
) #{translate("learn_more_lowercase")}
span )
td
for feature, featureIndex in planFeaturesPerSection.items
tr(
class=(featureIndex === (planFeaturesPerSection.items.length - 1) ? 'plans-v2-table-row-last-row-per-section' : '')
)
td(event-tracking="plans-page-table" event-tracking-trigger="hover" event-tracking-ga="subscription-funnel" event-tracking-label=`${feature.feature}`)
.plans-v2-table-feature-name
if feature.info
span #{translate(feature.feature)}
//- will only appear on screen width >= 768px (using CSS)
i.fa.fa-question-circle.plans-v2-table-feature-name-question-icon(
data-toggle="tooltip"
title=translate(feature.info),
data-placement="right"
)
//- will only appear on screen width < 768px (using CSS)
span.plans-v2-table-feature-name-learn-more-container
span (
span.plans-v2-table-feature-name-learn-more-text(
data-toggle="tooltip"
title=translate(feature.info),
data-placement="top"
) #{translate("learn_more_lowercase")}
span )
else
| #{translate(feature.feature)}
td.plans-v2-table-cell-before-highlighted-column(ng-non-bindable)
+table_cell(feature, 'group_standard')
td.plans-v2-table-green-highlighted(ng-non-bindable)
+table_cell(feature, 'group_professional')
td(ng-non-bindable)
+table_cell(feature, 'organization')
td
mixin table_student(period)
table.card.plans-v2-table.plans-v2-table-student
tr
th
th.plans-v2-table-cell-before-highlighted-column
div.plans-v2-table-th-content
p.plans-v2-table-th-content-title #{translate("free")}
+table_head_price('free', period)
.plans-v2-table-btn-buy-container-mobile
+btn_buy_student_free()
ul.plans-v2-table-th-content-benefit
li #{translate("only_one_collaborator")}
li #{translate("most_premium_features")}
.plans-v2-table-btn-buy-container-desktop
+btn_buy_student_free()
th.plans-v2-table-green-highlighted
div.plans-v2-table-th-content
p.plans-v2-table-green-highlighted-text
if (period === 'monthly')
| SAVE 20% ON ANNUAL PLAN
else
| SAVING 20%
p.plans-v2-table-th-content-title #{translate("student")}
+table_head_price('student', period)
.plans-v2-table-btn-buy-container-mobile
+btn_buy_student_student(period)
ul.plans-v2-table-th-content-benefit
li #{translate("only_one_collaborator")}
li #{translate("all_premium_features")}
.plans-v2-table-btn-buy-container-desktop
+btn_buy_student_student(period)
th
div.plans-v2-table-th-content
p.plans-v2-table-th-content-title #{translate("university")}
div.plans-v2-table-comments-icon
i.fa.fa-comments-o
.plans-v2-table-btn-buy-container-mobile
+btn_buy_student_university
p.plans-v2-table-th-content-benefit !{translate("all_our_group_plans_offer_educational_discount", {}, [{name: 'b'}, {name: 'b'}])}
.plans-v2-table-btn-buy-container-desktop
+btn_buy_student_university
th
for planFeaturesPerSection in planFeatures.student
if (planFeaturesPerSection.divider)
tr.plans-v2-table-divider
td(colspan="4")
div
span.plans-v2-table-divider-label #{translate(planFeaturesPerSection.dividerLabel)}
//- will only appear on screen width >= 768px (using CSS)
i.fa.fa-question-circle.plans-v2-table-divider-question-icon(
data-toggle="tooltip"
title=translate(planFeaturesPerSection.dividerInfo),
data-placement="top"
)
//- will only appear on screen width < 768px (using CSS)
span.plans-v2-table-divider-learn-more-container
span (
span.plans-v2-table-divider-learn-more-text(
data-toggle="tooltip"
title=translate(planFeaturesPerSection.dividerInfo),
data-placement="top"
) #{translate("learn_more_lowercase")}
span )
td
for feature, featureIndex in planFeaturesPerSection.items
tr(
class=(featureIndex === (planFeaturesPerSection.items.length - 1) ? 'plans-v2-table-row-last-row-per-section' : '')
)
td(event-tracking="plans-page-table" event-tracking-trigger="hover" event-tracking-ga="subscription-funnel" event-tracking-label=`${feature.feature}`)
.plans-v2-table-feature-name
if (feature.info)
span #{translate(feature.feature)}
//- will only appear on screen width >= 768px (using CSS)
i.fa.fa-question-circle.plans-v2-table-feature-name-question-icon(
data-toggle="tooltip"
title=translate(feature.info),
data-placement="right"
)
//- will only appear on screen width < 768px (using CSS)
span.plans-v2-table-feature-name-learn-more-container
span (
span.plans-v2-table-feature-name-learn-more-text(
data-toggle="tooltip"
title=translate(feature.info),
data-placement="top"
) #{translate("learn_more_lowercase")}
span )
else
| #{translate(feature.feature)}
td.plans-v2-table-cell-before-highlighted-column(ng-non-bindable)
+table_cell(feature, 'free')
td.plans-v2-table-green-highlighted(ng-non-bindable)
+table_cell(feature, 'student')
td(ng-non-bindable)
+table_cell(feature, 'university')
td
mixin table_head_price(plan, period)
div.plans-v2-table-price-container
if plan !== 'free'
strike.plans-v2-table-annual-price-before-discount.hidden(data-ol-plans-v2-table-annual-price-before-discount)
+gen_localized_price_for_plan_view(plan, 'monthlyTimesTwelve')
p.plans-v2-table-price
+gen_localized_price_for_plan_view(plan, period)
p.plans-v2-table-price-period-label
if period == 'annual'
| per year
else
| per month
mixin table_cell(feature, plan)
.plans-v2-table-cell-inner-content
if (feature.value === 'str')
| #{feature.plans[plan]}
else if (feature.plans[plan])
i.fa.fa-check(aria-hidden="true")
span.sr-only #{translate("feature_included")}
else
span(aria-hidden="true") -
span.sr-only #{translate("feature_not_included")}
mixin group_plans_license_picker()
form.plans-v2-license-picker-form(data-ol-plans-v2-license-picker-form)
.plans-v2-license-picker-select-container
span #{translate("how_many_licenses_are_you_looking_for")}
select.plans-v2-license-picker-select(
name="plans-v2-license-picker-select"
id="plans-v2-license-picker-select"
autocomplete="off"
data-ol-plans-v2-license-picker-select
)
option(value="2") 2
option(value="3") 3
option(value="4") 4
option(value="5") 5
option(value="10") 10
option(value="20") 20
option(value="50") 50
.plans-v2-license-picker-educational-discount
label.plans-v2-license-picker-educational-discount-label(data-ol-plans-v2-license-picker-educational-discount-label)
input.plans-v2-license-picker-educational-discount-checkbox(
type="checkbox"
id="license-picker-educational-discount"
autocomplete="off"
data-ol-plans-v2-license-picker-educational-discount-input
)
span #{translate("include_educational_discount")}
//- will only appear on screen width >= 768px (using CSS)
i.fa.fa-question-circle.plans-v2-license-picker-educational-discount-question-icon(
data-toggle="tooltip"
title=translate("include_educational_discount_info"),
data-placement="bottom"
)
//- will only appear on screen width < 768px (using CSS)
span.plans-v2-license-picker-educational-discount-learn-more-container
span (
span.plans-v2-license-picker-educational-discount-learn-more-text(
data-toggle="tooltip"
title=translate("include_educational_discount_info"),
data-placement="bottom"
) #{translate("learn_more_lowercase")}
span )
mixin btn_buy_individual(subscriptionPlan, period, highlighted)
if (highlighted)
a.btn.btn-primary.plans-v2-table-btn-buy(
data-ol-start-new-subscription=subscriptionPlan
data-ol-item-view=period
)
if (period === 'monthly')
span #{translate("try_for_free")}
else
span #{translate("buy_now")}
else
a.btn.btn-default.plans-v2-table-btn-buy(
data-ol-start-new-subscription=subscriptionPlan
data-ol-item-view=period
)
if (period === 'monthly')
span #{translate("try_for_free")}
else
span #{translate("buy_now")}
mixin btn_buy_individual_free()
if (!getSessionUser())
a.btn.btn-default.plans-v2-table-btn-buy(href="/register")
span #{translate("try_for_free")}
else
a.btn.btn-default.plans-v2-table-btn-buy.invisible(aria-hidden="true")
mixin btn_buy_individual_personal(period)
+btn_buy_individual('paid-personal', period, false)
if (period === 'monthly')
small.plans-v2-table-th-content-additional-link !{translate("or_buy_now", {}, [{name: 'a', attrs: {href: '/user/subscription/new?planCode=paid-personal&currency=' + recommendedCurrency + '&itm_campaign=plans&itm_content=card'}}])}
mixin btn_buy_individual_collaborator(period)
+btn_buy_individual('collaborator', period, true)
if (period === 'monthly')
small.plans-v2-table-th-content-additional-link !{translate("or_buy_now", {}, [{name: 'a', attrs: {href: '/user/subscription/new?planCode=collaborator&currency=' + recommendedCurrency + '&itm_campaign=plans&itm_content=card'}}])}
mixin btn_buy_individual_professional(period)
+btn_buy_individual('professional', period, false)
if (period === 'monthly')
small.plans-v2-table-th-content-additional-link !{translate("or_buy_now", {}, [{name: 'a', attrs: {href: '/user/subscription/new?planCode=professional&currency=' + recommendedCurrency + '&itm_campaign=plans&itm_content=card'}}])}
mixin btn_buy_group_collaborator()
a.btn.btn-default.plans-v2-table-btn-buy(
data-ol-start-new-subscription='group_collaborator'
data-ol-item-view='annual'
data-ol-has-custom-href
)
span #{translate("customize")}
span.hidden-mobile #{translate("your_plan_lowercase")}
mixin btn_buy_group_professional()
a.btn.btn-primary.plans-v2-table-btn-buy(
data-ol-start-new-subscription='group_professional'
data-ol-item-view='annual'
data-ol-has-custom-href
)
span #{translate("customize")}
span.hidden-mobile #{translate("your_plan_lowercase")}
mixin btn_buy_group_organization()
a.btn.btn-default.plans-v2-table-btn-buy(
data-ol-start-new-subscription='group_organization'
data-ol-item-view='annual'
data-ol-has-custom-href
href='/for/enterprises/sales-contact'
target='_blank'
)
span #{translate("contact_us_lowercase")}
mixin btn_buy_student_free()
if (!getSessionUser())
a.btn.btn-default.plans-v2-table-btn-buy(href="/register")
span #{translate("try_for_free")}
mixin btn_buy_student_student(period)
a.btn.btn-primary.plans-v2-table-btn-buy(
data-ol-start-new-subscription='student'
data-ol-item-view=period
data-ol-location='card'
)
if (period === 'monthly')
span #{translate("try_for_free")}
else
span #{translate("buy_now")}
if (period === 'monthly')
small.plans-v2-table-th-content-additional-link !{translate("or_buy_now", {}, [{name: 'a', attrs: {href: '/user/subscription/new?planCode=student&currency=' + recommendedCurrency + '&itm_campaign=plans&itm_content=card'}}])}
mixin btn_buy_student_university()
a.btn.btn-default.plans-v2-table-btn-buy(
href="/for/enterprises/sales-contact"
target="_blank"
)
span #{translate("contact_us_lowercase")}
mixin table_sticky_header
.row.plans-v2-table-sticky-header.plans-v2-table-sticky-header-individual.sticky(data-ol-plans-v2-table-sticky-header='individual')
.plans-v2-table-sticky-header-item
span #{translate("free")}
.plans-v2-table-sticky-header-item
span #{translate("personal")}
.plans-v2-table-sticky-header-item.plans-v2-table-sticky-header-item-highlighted
span #{translate("standard")}
.plans-v2-table-sticky-header-item
span #{translate("professional")}
.row.plans-v2-table-sticky-header.plans-v2-table-sticky-header-group.sticky(hidden data-ol-plans-v2-table-sticky-header='group')
.plans-v2-table-sticky-header-item
span #{translate("group_standard")}
.plans-v2-table-sticky-header-item.plans-v2-table-sticky-header-item-highlighted
span #{translate("group_professional")}
.plans-v2-table-sticky-header-item
span #{translate("organization")}
.row.plans-v2-table-sticky-header.plans-v2-table-sticky-header-student.sticky(hidden data-ol-plans-v2-table-sticky-header='student')
.plans-v2-table-sticky-header-item
span #{translate("free")}
.plans-v2-table-sticky-header-item.plans-v2-table-sticky-header-item-highlighted
span #{translate("student")}
.plans-v2-table-sticky-header-item
span #{translate("university")}

View file

@ -0,0 +1,81 @@
import './group-plan-modal'
import getMeta from '../../utils/meta'
const NEW_PLANS_PAGE_VARIANT = 'new-plans-page'
export function checkIfGroupModalOpen() {
return window.location.hash.includes('groups')
}
export function changePlansV2MainPageGroupData() {
const mainPlansPageFormEl = document.querySelector(
'[data-ol-plans-v2-license-picker-form]'
)
const mainPlansPageLicensePickerEl = mainPlansPageFormEl.querySelector(
'[data-ol-plans-v2-license-picker-select]'
)
const mainPlansPageEducationalDiscountEl = mainPlansPageFormEl.querySelector(
'[data-ol-plans-v2-license-picker-educational-discount-input]'
)
const groupPlanModalNumberOfLicenses = document.querySelector(
'[data-ol-group-plan-modal] #size'
).value
const educationalDiscountChecked = document.querySelector(
'[data-ol-group-plan-modal] #usage'
).checked
const educationalDiscountEnabled =
educationalDiscountChecked && groupPlanModalNumberOfLicenses >= 10
if (checkIfGroupModalOpen()) {
// update license picker on the main plans page
mainPlansPageLicensePickerEl.value = groupPlanModalNumberOfLicenses
mainPlansPageLicensePickerEl.dispatchEvent(new Event('change'))
// update educational discount checkbox on the main plans page
if (groupPlanModalNumberOfLicenses >= 10) {
mainPlansPageEducationalDiscountEl.checked = educationalDiscountEnabled
mainPlansPageEducationalDiscountEl.dispatchEvent(new Event('change'))
} else {
if (educationalDiscountChecked) {
mainPlansPageEducationalDiscountEl.checked = false
mainPlansPageEducationalDiscountEl.dispatchEvent(new Event('change'))
}
}
}
}
function hideCurrencyPicker() {
document.querySelector('[data-ol-group-plan-form-currency]').hidden = true
}
const plansPageVariant =
getMeta('ol-splitTestVariants')?.['plans-page-layout-v2'] ?? 'default'
if (plansPageVariant === NEW_PLANS_PAGE_VARIANT) {
hideCurrencyPicker()
// we need to sync the form data between group plan modal
// and the main plan page
document.querySelectorAll('[data-ol-group-plan-code]').forEach(el => {
// listening to new CustomEvent 'showmodal'
// we do this to check whether user clicks the "Standard (Collaborator)" plan or the "Professional" plan
// and the radio button on the group plan modal will then be 'checked' accordingly
el.addEventListener('showmodal', () => {
if (!checkIfGroupModalOpen()) {
el.checked = true
el.dispatchEvent(new Event('change'))
}
})
})
}
document
.querySelectorAll('[data-ol-group-plan-form] select')
.forEach(el => el.addEventListener('change', changePlansV2MainPageGroupData))
document
.querySelectorAll('[data-ol-group-plan-form] input')
.forEach(el => el.addEventListener('change', changePlansV2MainPageGroupData))

View file

@ -0,0 +1,136 @@
import { checkIfGroupModalOpen } from '../../../../features/plans/plans-v2-group-plan-modal'
import getMeta from '../../../../utils/meta'
const MINIMUM_NUMBER_OF_LICENSES_EDUCATIONAL_DISCOUNT = 10
export function updateGroupPricing() {
const groupPlans = getMeta('ol-groupPlans')
const currencySymbols = getMeta('ol-currencySymbols')
const currentCurrencyCode = getMeta('ol-recommendedCurrency')
const formEl = document.querySelector(
'[data-ol-plans-v2-license-picker-form]'
)
const numberOfLicenses = formEl.querySelector(
'[data-ol-plans-v2-license-picker-select]'
).value
const currency = currentCurrencyCode
const currencySymbol = currencySymbols[currency]
const usage = formEl.querySelector(
'[data-ol-plans-v2-license-picker-educational-discount-input]'
).checked
? 'educational'
: 'enterprise'
const priceInCentsProfessional =
groupPlans[usage].professional[currency][numberOfLicenses].price_in_cents
const priceInUnitProfessional = (priceInCentsProfessional / 100).toFixed()
const perUserPriceProfessional = parseFloat(
(priceInCentsProfessional / 100 / numberOfLicenses).toFixed(2)
)
let displayPriceProfessional = `${currencySymbol}${priceInUnitProfessional}`
let displayPerUserPriceProfessional = `${currencySymbol}${perUserPriceProfessional}`
const priceInCentsCollaborator =
groupPlans[usage].collaborator[currency][numberOfLicenses].price_in_cents
const priceInUnitCollaborator = (priceInCentsCollaborator / 100).toFixed()
const perUserPriceCollaborator = parseFloat(
(priceInCentsCollaborator / 100 / numberOfLicenses).toFixed(2)
)
let displayPriceCollaborator = `${currencySymbol}${priceInUnitCollaborator}`
let displayPerUserPriceCollaborator = `${currencySymbol}${perUserPriceCollaborator}`
if (currencySymbol === 'kr') {
displayPriceProfessional = `${priceInUnitProfessional} ${currencySymbol}`
displayPerUserPriceProfessional = `${perUserPriceProfessional} ${currencySymbol}`
displayPriceCollaborator = `${priceInUnitCollaborator} ${currencySymbol}`
displayPerUserPriceCollaborator = `${perUserPriceCollaborator} ${currencySymbol}`
} else if (currencySymbol === 'Fr') {
displayPriceProfessional = `${currencySymbol} ${priceInUnitProfessional}`
displayPerUserPriceProfessional = `${currencySymbol} ${perUserPriceProfessional}`
displayPriceCollaborator = `${currencySymbol} ${priceInUnitCollaborator}`
displayPerUserPriceCollaborator = `${currencySymbol} ${perUserPriceCollaborator}`
}
document.querySelector(
'[data-ol-plans-v2-group-total-price="professional"]'
).innerText = displayPriceProfessional
document.querySelector(
'[data-ol-plans-v2-group-total-price="collaborator"]'
).innerText = displayPriceCollaborator
document.querySelector(
'[data-ol-group-price-per-user="collaborator"]'
).innerText = displayPerUserPriceCollaborator
document.querySelector(
'[data-ol-group-price-per-user="professional"]'
).innerText = displayPerUserPriceProfessional
// educational discount can only be activated if numberOfLicenses is > 10
if (numberOfLicenses < MINIMUM_NUMBER_OF_LICENSES_EDUCATIONAL_DISCOUNT) {
formEl.querySelector(
'[data-ol-plans-v2-license-picker-educational-discount-input]'
).disabled = true
formEl.querySelector(
'[data-ol-plans-v2-license-picker-educational-discount-input]'
).checked = false
formEl
.querySelector(
'[data-ol-plans-v2-license-picker-educational-discount-label]'
)
.classList.add('disabled')
} else {
formEl.querySelector(
'[data-ol-plans-v2-license-picker-educational-discount-input]'
).disabled = false
formEl
.querySelector(
'[data-ol-plans-v2-license-picker-educational-discount-label]'
)
.classList.remove('disabled')
}
}
export function showGroupPlansLicensePicker() {
const el = document.querySelector(
'[data-ol-plans-v2-license-picker-container]'
)
el.hidden = false
}
export function hideGroupPlansLicensePicker() {
const el = document.querySelector(
'[data-ol-plans-v2-license-picker-container]'
)
el.hidden = true
}
export function changeGroupPlanModalNumberOfLicenses() {
const modalEl = document.querySelector('[data-ol-group-plan-modal]')
const numberOfLicenses = document.querySelector(
'[data-ol-plans-v2-license-picker-select]'
).value
const groupPlanModalLicensePickerEl = modalEl.querySelector('#size')
if (!checkIfGroupModalOpen()) {
groupPlanModalLicensePickerEl.value = numberOfLicenses
groupPlanModalLicensePickerEl.dispatchEvent(new Event('change'))
}
}
export function changeGroupPlanModalEducationalDiscount() {
const modalEl = document.querySelector('[data-ol-group-plan-modal]')
const groupPlanModalEducationalDiscountEl = modalEl.querySelector('#usage')
const educationalDiscountChecked = document.querySelector(
'[data-ol-plans-v2-license-picker-educational-discount-input]'
).checked
if (!checkIfGroupModalOpen()) {
groupPlanModalEducationalDiscountEl.checked = educationalDiscountChecked
groupPlanModalEducationalDiscountEl.dispatchEvent(new Event('change'))
}
}

View file

@ -0,0 +1,218 @@
// m-a stands for monthly-annual
// We need this mutable variable because the group tab only have annual.
// There's some difference between the monthly and annual UI
// and since monthly-annual switch is disabled for the group tab,
// we need to introduce a new variable to store the information
let currentMonthlyAnnualSwitchValue = 'monthly'
// only executed if switching to group tab
export function disableMonthlyAnnualSwitching() {
const containerEl = document.querySelector(
'[data-ol-plans-v2-m-a-switch-container]'
)
const checkbox = containerEl.querySelector('input[type="checkbox"]')
containerEl.classList.add('disabled')
checkbox.disabled = true
checkbox.checked = true
document
.querySelectorAll('[data-ol-plans-v2-table-container]')
.forEach(el => {
const period = el.getAttribute('data-ol-plans-v2-table-container')
if (period === 'annual') {
el.hidden = false
} else {
el.hidden = true
}
})
document
.querySelectorAll('[data-ol-plans-v2-table-annual-price-before-discount]')
.forEach(el => {
el.classList.remove('hidden')
})
}
// executed if switching from group tab to individual and student tab
export function enableMonthlyAnnualSwitching() {
const containerEl = document.querySelector(
'[data-ol-plans-v2-m-a-switch-container]'
)
const checkbox = containerEl.querySelector('input[type="checkbox"]')
containerEl.classList.remove('disabled')
checkbox.disabled = false
if (currentMonthlyAnnualSwitchValue === 'annual') {
checkbox.checked = true
} else {
checkbox.checked = false
document
.querySelectorAll('[data-ol-plans-v2-table-container]')
.forEach(el => {
const period = el.getAttribute('data-ol-plans-v2-table-container')
if (period === 'annual') {
el.hidden = true
} else {
el.hidden = false
}
})
document
.querySelectorAll('[data-ol-plans-v2-table-annual-price-before-discount]')
.forEach(el => {
el.classList.add('hidden')
})
}
}
export function hideMonthlyAnnualSwitchOnSmallScreen() {
const isSmallScreen = window.matchMedia('(max-width: 767px)').matches
if (isSmallScreen) {
const el = document.querySelector('[data-ol-plans-v2-m-a-switch-container]')
el.hidden = true
}
}
export function showMonthlyAnnualSwitchOnSmallScreen() {
const isSmallScreen = window.matchMedia('(max-width: 767px)').matches
if (isSmallScreen) {
const el = document.querySelector('[data-ol-plans-v2-m-a-switch-container]')
el.hidden = false
}
}
// in group tab, there are no "20% discount"
// tooltip in the monthly-annual switch "annual" text.
// so, we need to hide it
export function showMonthlyAnnualTooltip() {
const el = document.querySelector('[data-ol-plans-v2-m-a-tooltip]')
el.hidden = false
}
export function hideMonthlyAnnualTooltip() {
const el = document.querySelector('[data-ol-plans-v2-m-a-tooltip]')
el.hidden = true
}
// "20% discount" tooltip in the monthly-annual switch will have a different
// text and different colour, so we need to switch them accordingly
function switchMonthlyAnnualTooltip() {
const el = document.querySelector('[data-ol-plans-v2-m-a-tooltip]')
if (currentMonthlyAnnualSwitchValue === 'annual') {
el.classList.replace(
'plans-v2-m-a-tooltip-annual',
'plans-v2-m-a-tooltip-monthly'
)
document.querySelectorAll('[data-ol-tooltip-period]').forEach(childEl => {
const period = childEl.getAttribute('data-ol-tooltip-period')
if (period === 'monthly') {
childEl.hidden = false
} else {
childEl.hidden = true
}
})
} else {
el.classList.replace(
'plans-v2-m-a-tooltip-monthly',
'plans-v2-m-a-tooltip-annual'
)
document.querySelectorAll('[data-ol-tooltip-period]').forEach(childEl => {
const period = childEl.getAttribute('data-ol-tooltip-period')
if (period === 'annual') {
childEl.hidden = false
} else {
childEl.hidden = true
}
})
}
}
// month and annual value will each have its own set of tables that we need to
// switch accordingly
function switchMonthlyAnnualTable() {
const isAnnualPricing = document.querySelector(
'[data-ol-plans-v2-m-a-switch] input[type="checkbox"]'
).checked
if (isAnnualPricing) {
currentMonthlyAnnualSwitchValue = 'annual'
} else {
currentMonthlyAnnualSwitchValue = 'monthly'
}
document
.querySelectorAll('[data-ol-plans-v2-table-annual-price-before-discount]')
.forEach(el => {
if (isAnnualPricing) {
el.classList.remove('hidden')
} else {
el.classList.add('hidden')
}
})
document
.querySelectorAll('[data-ol-plans-v2-table-container]')
.forEach(el => {
const period = el.getAttribute('data-ol-plans-v2-table-container')
if (isAnnualPricing) {
if (period === 'annual') {
el.hidden = false
} else {
el.hidden = true
}
} else {
if (period === 'annual') {
el.hidden = true
} else {
el.hidden = false
}
}
})
}
export function underlineAnnualText() {
document
.querySelector('[data-ol-plans-v2-m-a-switch-monthly-text]')
.classList.remove('underline')
document
.querySelector('[data-ol-plans-v2-m-a-switch-annual-text]')
.classList.add('underline')
}
function underlineMonthlyText() {
document
.querySelector('[data-ol-plans-v2-m-a-switch-monthly-text]')
.classList.add('underline')
document
.querySelector('[data-ol-plans-v2-m-a-switch-annual-text]')
.classList.remove('underline')
}
// if annual is active, we need to underline the "annual" text
// if monthly is active, we need to underline the "monthly" text
export function switchUnderlineText() {
if (currentMonthlyAnnualSwitchValue === 'annual') {
underlineAnnualText()
} else {
underlineMonthlyText()
}
}
// click event listener for monthly-annual switch
export function setUpMonthlyAnnualSwitching() {
document
.querySelector('[data-ol-plans-v2-m-a-switch]')
.addEventListener('click', () => {
switchMonthlyAnnualTooltip()
switchMonthlyAnnualTable()
switchUnderlineText()
})
}

View file

@ -0,0 +1,107 @@
import '../../../../marketing'
import {
setUpStickyHeaderObserver,
switchStickyHeader,
} from './plans-v2-sticky-header'
import {
disableMonthlyAnnualSwitching,
enableMonthlyAnnualSwitching,
hideMonthlyAnnualSwitchOnSmallScreen,
showMonthlyAnnualSwitchOnSmallScreen,
hideMonthlyAnnualTooltip,
showMonthlyAnnualTooltip,
setUpMonthlyAnnualSwitching,
underlineAnnualText,
switchUnderlineText,
} from './plans-v2-m-a-switch'
import {
changeGroupPlanModalEducationalDiscount,
changeGroupPlanModalNumberOfLicenses,
hideGroupPlansLicensePicker,
showGroupPlansLicensePicker,
updateGroupPricing,
} from './plans-v2-group-plan'
import { setUpGroupSubscriptionButtonAction } from './plans-v2-subscription-button'
import { checkIfGroupModalOpen } from '../../../../features/plans/plans-v2-group-plan-modal'
import { updateLinkTargets } from '../plans'
function selectTab(viewTab) {
document.querySelectorAll('[data-ol-plans-v2-view-tab]').forEach(el => {
if (el.getAttribute('data-ol-plans-v2-view-tab') === viewTab) {
el.classList.add('active')
} else {
el.classList.remove('active')
}
})
document.querySelectorAll('[data-ol-plans-v2-view]').forEach(el => {
el.hidden = el.getAttribute('data-ol-plans-v2-view') !== viewTab
})
switchUnderlineText()
switchStickyHeader(viewTab)
// group tab is special because group plan only has annual value
// so we need to perform some UI changes whenever user click the group tab
if (viewTab === 'group') {
disableMonthlyAnnualSwitching()
hideMonthlyAnnualTooltip()
updateGroupPricing()
underlineAnnualText()
showGroupPlansLicensePicker()
hideMonthlyAnnualSwitchOnSmallScreen()
} else {
enableMonthlyAnnualSwitching()
showMonthlyAnnualTooltip()
hideGroupPlansLicensePicker()
showMonthlyAnnualSwitchOnSmallScreen()
}
}
function setUpTabSwitching() {
document.querySelectorAll('[data-ol-plans-v2-view-tab]').forEach(el => {
const viewTab = el.getAttribute('data-ol-plans-v2-view-tab')
el.querySelector('a').addEventListener('click', function (e) {
e.preventDefault()
// TODO: analytics
// eventTracking.send('subscription-funnel', 'plans-page', `${view}-prices`)
// eventTracking.sendMB('plans-page-toggle', { button: view })
selectTab(viewTab)
})
})
}
function setUpGroupPlanPricingChange() {
document
.querySelectorAll('[data-ol-plans-v2-license-picker-select]')
.forEach(el => {
el.addEventListener('change', () => {
updateGroupPricing()
if (!checkIfGroupModalOpen()) {
changeGroupPlanModalNumberOfLicenses()
}
})
})
document
.querySelectorAll(
'[data-ol-plans-v2-license-picker-educational-discount-input]'
)
.forEach(el =>
el.addEventListener('change', () => {
updateGroupPricing()
if (!checkIfGroupModalOpen()) {
changeGroupPlanModalEducationalDiscount()
}
})
)
}
setUpTabSwitching()
setUpGroupPlanPricingChange()
setUpMonthlyAnnualSwitching()
setUpGroupSubscriptionButtonAction()
setUpStickyHeaderObserver()
updateLinkTargets()

View file

@ -0,0 +1,40 @@
// we have different sticky header according to plans (individual, group, and student)
// we need to show different sticky header based on active tab
// the value of attribute 'data-ol-plans-v2-table-sticky-header' can be individual, group, or student
export function switchStickyHeader(viewTab) {
document
.querySelectorAll('[data-ol-plans-v2-table-sticky-header]')
.forEach(el => {
const plan = el.getAttribute('data-ol-plans-v2-table-sticky-header')
if (plan === viewTab) {
el.hidden = false
} else {
el.hidden = true
}
})
}
function stickyHeaderObserverCallback(entry) {
const entryItem = entry[0]
if (entryItem.boundingClientRect.bottom <= 0) {
document
.querySelectorAll('[data-ol-plans-v2-table-sticky-header]')
.forEach(el => el.classList.remove('sticky'))
} else {
document
.querySelectorAll('[data-ol-plans-v2-table-sticky-header]')
.forEach(el => el.classList.add('sticky'))
}
}
export function setUpStickyHeaderObserver() {
const stickyHeaderStopEl = document.querySelector(
'[data-ol-plans-v2-table-sticky-header-stop]'
)
const observer = new IntersectionObserver(stickyHeaderObserverCallback)
observer.observe(stickyHeaderStopEl)
}

View file

@ -0,0 +1,40 @@
function sendShowModalEvent(plan) {
const groupPlan = plan.split('_')[1]
const groupModalRadioInputEl = document.querySelector(
`[data-ol-group-plan-code="${groupPlan}"]`
)
groupModalRadioInputEl.dispatchEvent(new CustomEvent('showmodal'))
}
function showGroupPlanModal(el) {
const plan = el.getAttribute('data-ol-start-new-subscription')
sendShowModalEvent(plan)
const modalEl = $('[data-ol-group-plan-modal]')
modalEl
.on('shown.bs.modal', function () {
const path = `${window.location.pathname}${window.location.search}`
history.replaceState(null, document.title, path + '#groups')
})
.on('hidden.bs.modal', function () {
history.replaceState(null, document.title, window.location.pathname)
})
modalEl.modal()
}
export function setUpGroupSubscriptionButtonAction() {
document.querySelectorAll('[data-ol-start-new-subscription]').forEach(el => {
const plan = el.getAttribute('data-ol-start-new-subscription')
if (plan === 'group_collaborator' || plan === 'group_professional') {
el.addEventListener('click', e => {
e.preventDefault()
showGroupPlanModal(el)
})
}
})
}

View file

@ -67,7 +67,7 @@ function setUpSubscriptionTracking(linkEl) {
})
}
function updateLinkTargets() {
export function updateLinkTargets() {
document.querySelectorAll('[data-ol-start-new-subscription]').forEach(el => {
if (el.hasAttribute('data-ol-has-custom-href')) return

View file

@ -85,6 +85,7 @@
@import 'app/editor.less';
@import 'app/homepage.less';
@import 'app/plans.less';
@import 'app/plans-v2.less';
@import 'app/recurly.less';
@import 'app/bonus.less';
@import 'app/register.less';

File diff suppressed because it is too large Load diff

View file

@ -54,6 +54,8 @@
"also_provides_free_plan": "__appName__ also provides a free plan -- simply <0>register here</0> to get started.",
"increased_compile_timeout": "Increased compile timeout",
"compile_timeout": "Compile timeout (minutes)",
"compile_timeout_short": "Compile timeout",
"compile_timeout_short_info": "This is how much time you get to compile your project on the Overleaf servers. For short and simple projects, 1 minute should be enough, but you may need longer for complex or longer projects",
"collabs_per_proj_single": "__collabcount__ collaborator per project",
"premium_feature": "Premium feature",
"premium_features": "Premium features",
@ -155,7 +157,6 @@
"project_ownership_transfer_confirmation_2": "This action cannot be undone. The new owner will be notified and will be able to change project access settings (including removing your own access).",
"change_owner": "Change owner",
"change_project_owner": "Change Project Owner",
"faq_pay_by_invoice_answer": "Yes, if youd like to purchase a group account or site license and would prefer to pay by invoice,\r\nor need to raise a purchase order, please <0>let us know</0>.\r\nFor individual accounts or accounts with monthly billing, we can only accept payment online\r\nvia credit or debit card, or PayPal.",
"password_too_long_please_reset": "Maximum password length exceeded. Please reset your password.",
"view_other_options_to_log_in": "View other options to log in",
"we_logged_you_in": "We have logged you in.",
@ -374,6 +375,7 @@
"overall_theme": "Overall theme",
"faq_how_does_free_trial_works_answer": "You get full access to your chosen __appName__ plan during your __len__-day free trial. There is no obligation to continue beyond the trial. Your card will be charged at the end of your __len__ day trial unless you cancel before then. You can cancel via your subscription settings.",
"thousands_templates": "Thousands of templates",
"thousands_templates_info": "Produce beautiful documents starting from our gallery of LaTeX templates for journals, conferences, theses, reports, CVs and much more.",
"get_instant_access_to": "Get instant access to",
"ask_proj_owner_to_upgrade_for_full_history": "Please ask the project owner to upgrade to access this projects full history.",
"currently_seeing_only_24_hrs_history": "Youre currently seeing the last 24 hours of changes in this project.",
@ -448,7 +450,9 @@
"in_good_company": "Youre In Good Company",
"unlimited": "Unlimited",
"priority_support": "Priority support",
"priority_support_info": "Our helpful Support team will prioritise and escalate your support requests where necessary.",
"dropbox_integration_lowercase": "Dropbox integration",
"dropbox_integration_lowercase_info": "You can synchronize your projects with a Dropbox folder. Changes in Overleaf are automatically pushed to Dropbox and vice versa.",
"github_integration_lowercase": "Git and GitHub integration",
"discounted_group_accounts": "discounted group accounts",
"referring_your_friends": "referring your friends",
@ -458,27 +462,43 @@
"best_value": "Best value",
"faq_how_free_trial_works_question": "How does the free trial work?",
"faq_change_plans_question": "Can I change plans later?",
"faq_change_plans_or_cancel_question": "Can I change plans or cancel later?",
"faq_do_collab_need_premium_question": "Do my collaborators also need premium accounts?",
"faq_do_collab_need_on_paid_plan_question": "Do my collaborators also need a license?",
"faq_need_more_collab_question": "What if I need more collaborators?",
"faq_purchase_more_licenses_question": "Can I purchase additional licenses for my colleagues?",
"faq_monthly_or_annual_question": "Should I choose monthly or annual billing?",
"faq_how_to_pay_question": "Can I pay online with a credit or debit card, or PayPal?",
"faq_pay_by_invoice_question": "Can I pay by invoice / purchase order?",
"faq_how_does_a_group_plan_work_question": "How does a group plan work?",
"reference_search": "Advanced reference search",
"reference_search_info": "You can always search by citation key, and advanced reference search lets you also search by author, title, year or journal.",
"reference_search_info_v2": "Its easy to find your references - you can search by author, title, year or journal. You can still search by citation key too.",
"reference_sync": "Reference manager sync",
"reference_sync_info": "Manage your reference library in Mendeley and link it directly to a .bib file in Overleaf, so you can easily cite anything in your Mendeley library.",
"faq_how_free_trial_works_answer": "You get full access to your chosen __appName__ plan during your __len__-day free trial. There is no obligation to continue beyond the trial. Your card will be charged at the end of your __len__ day trial unless you cancel before then. You can cancel via your subscription settings.",
"faq_how_free_trial_works_answer_v2": "You get full access to your chosen __appName__ plan during your __len__ day free trial, and there is no obligation to continue beyond the trial. Your card will be charged at the end of your trial unless you cancel before then. To cancel, go to your subscription settings in your account (the trial will continue for the full __len__ days).",
"faq_change_plans_answer": "Yes, you can change your plan at any time via your subscription settings. This includes options to switch to a different plan, or to switch between monthly and annual billing options, or to cancel to downgrade to the free plan.",
"faq_change_plans_or_cancel_answer": "You can change your plan at any time via your subscription settings. You can switch to a different plan, or switch between monthly and annual billing options, or cancel to downgrade to the free plan. When cancelling, your subscription will continue until the end of the billing period.",
"faq_do_collab_need_premium_answer": "Premium features, such as tracked changes, will be available to your collaborators on projects that you have created, even if those collaborators have free accounts.",
"faq_do_collab_need_on_paid_plan_answer": "No, they can be on the free plan. If you are on a paid plan, some premium features will be available to your collaborators in projects that you have created, even if those collaborators are on the free plan. For more information, read about <0>account and subscription</0> and <1>how premium features work</1>.",
"faq_need_more_collab_answer": "You can upgrade to one of our paid accounts, which support more collaborators. You can also earn additional collaborators on our free accounts by __referFriendsLink__.",
"faq_purchase_more_licenses_answer": "Yes, we provide __groupLink__, which are easy to manage, help to save on paperwork, and reduce the cost of purchasing multiple licenses.",
"faq_monthly_or_annual_answer": "Annual billing offers a way to cut down on your admin and paperwork. If youd prefer to manage a single payment every year, instead of twelve, annual billing is for you.",
"faq_how_to_pay_answer": "Yes, you can. All major credit and debit cards and Paypal are supported. Select the plan youd like above, and youll have the option to pay by card or to go through to PayPal when its time to set up payment.",
"faq_pay_by_invoice_answer": "Yes, if youd like to purchase a group account or site license and would prefer to pay by invoice,\r\nor need to raise a purchase order, please <0>let us know</0>.\r\nFor individual accounts or accounts with monthly billing, we can only accept payment online\r\nvia credit or debit card, or PayPal.",
"faq_pay_by_invoice_answer_v2": "Yes, if youd like to purchase a group subscription for five or more people, or a site license. For individual subscriptions we can only accept payment online via credit card, debit card or PayPal.",
"faq_how_does_a_group_plan_work_answer": "Group subscriptions are a way to purchase more than one license. They are easy to manage, help to save on paperwork, and reduce the cost of purchasing multiple licenses. If you have any questions, read more about <0>joining a group subscription</0> and <1>managing a group subscription</1>. You can purchase group subscriptions above or by <2>contacting us</2>.",
"account_and_subscriptions": "account and subscriptions",
"how_premium_features_work": "how premium features work",
"powerful_latex_editor": "Powerful LaTeX editor",
"powerful_latex_editor_and_realtime_collaboration": "Powerful LaTeX editor & real-time collaboration",
"powerful_latex_editor_and_realtime_collaboration_info": "Spell check, intelligent autocomplete, syntax highlighting, dozens of color themes, vim and emacs bindings, help with LaTeX warnings and error messages, and more. Everyone always has the latest version, and you can see your collaborators cursors and changes in real time.",
"realtime_track_changes": "Real-time track changes",
"realtime_track_changes_info": "Now you dont have to choose between tracked changes and typesetting in LaTeX. Leave comments, keep track of TODOs, and accept or reject others changes.",
"realtime_track_changes_info_v2": "Switch on track changes to see who made every change, accept or reject others changes, and write comments.",
"full_doc_history_info": "Travel back in time to see any version and who made changes. No matter what happens, weve got your back.",
"full_doc_history_info_v2": "You can see all the edits in your project and who made every change. Add labels to quickly access specific versions.",
"dropbox_integration_info": "Work online and offline seamlessly with two-way Dropbox sync. Changes you make locally will be sent automatically to the version on Overleaf and vice versa.",
"github_integration_info": "Push and pull commits to and from GitHub or directly from Git, so you or your collaborators can work offline with Git and online with Overleaf.",
"latex_editor_info": "Everything you need in a modern LaTeX editor --- spell check, intelligent autocomplete, syntax highlighting, dozens of color themes, vim and emacs bindings, help with LaTeX warnings and error messages, and much more.",
@ -922,6 +942,7 @@
"doesnt_match": "Doesnt match",
"dropbox_integration": "Dropbox Integration",
"learn_more": "Learn more",
"learn_more_lowercase": "learn more",
"dropbox_is_premium": "Dropbox Sync is a premium feature",
"account_is_linked": "Account is linked",
"unlink_dropbox": "Unlink Dropbox",
@ -1391,6 +1412,7 @@
"university_licences": "University Licenses",
"security": "Security",
"contact_us": "Contact Us",
"contact_us_lowercase": "Contact us",
"thanks": "Thanks",
"blog": "Blog",
"latex_editor": "LaTeX Editor",
@ -1429,6 +1451,7 @@
"free_forever": "Free forever",
"low_priority_compile": "Low priority compiling",
"unlimited_projects": "Unlimited projects",
"unlimited_projects_info": "Your projects are private by default. This means that only you can view them, and only you can allow other people to access them.",
"unlimited_compiles": "Unlimited compiles",
"full_history_of_changes": "Full history of changes",
"highest_priority_compiling": "Highest priority compiling",
@ -1637,10 +1660,74 @@
"keep_your_email_updated": "Keep your email updated so that you dont lose access to your account and data.",
"learn_more_about_emails": "<0>Learn more</0> about managing your __appName__ emails.",
"thank_you_email_checked": "Thank you, were now taking you back to the projects page",
"change_primary_email_address_instructions": "To change your primary email, please add your new primary email address first (by clicking <0>Add another email</0>) and confirm it. Then click the <0>Make Primary</0> button. <1>Learn more</1> about managing your __appName__ emails.",
"change_primary_email_address_instructions": "To change your primary email, please add your new primary email address first (by clicking <0>Add another email</0>) and confirm it. Then click the <0>Make Primary</0> button. <1>Learn more</1> about managing your __appName__ emails.",
"help_improve_overleaf_fill_out_this_survey": "If you would like to help us improve Overleaf, please take a moment to fill out <0>this survey</0>.",
"number_of_users": "Number of users",
"number_of_users_info": "The number of users that can upgrade their Overleaf account if you purchase this plan.",
"student_plans": "Student plans",
"group_plans": "Group plans",
"max_collab_per_project": "Max. collaborators per project",
"max_collab_per_project_info": "The number of people you can invite to work on each project. They just need to have an Overleaf account. They can be different people in each project.",
"you_and_collaborators_get_access_to": "You and your project collaborators get access to",
"you_and_collaborators_get_access_to_info": "These features are available to you and your collaborators (other Overleaf users that you invite to your projects).",
"you_get_access_to": "You get access to",
"you_get_access_to_info": "These features are available only to you (the subscriber).",
"symbol_palette": "Symbol palette",
"symbol_palette_info": "A quick and convenient way to insert math symbols into your document.",
"github_only_integration_lowercase": "Github integration",
"github_only_integration_lowercase_info": "Link your Overleaf projects directly to a GitHub repository that acts as a remote repository for your overleaf project. This allows you to share with collaborators outside of Overleaf, and integrate Overleaf into more complex workflows.",
"git_integration_lowercase": "Git integration",
"git_integration_lowercase_info": "You can clone your Overleaf project to a local repository, treating your Overleaf project as a remote repository that changes can be pushed to and pulled from.",
"mendeley_integration_lowercase": "Mendeley integration",
"mendeley_integration_lowercase_info": "Manage your reference library in Mendeley, and link it directly to .bib files in Overleaf, so you can easily cite anything from your libraries.",
"zotero_integration_lowercase": "Zotero integration",
"zotero_integration_lowercase_info": "Manage your reference library in Zotero, and link it directly to .bib files in Overleaf, so you can easily cite anything from your libraries.",
"only_one_collaborator": "Only one collaborator",
"up_to": "Up to",
"x_collaborators_per_project": "__collaboratorsCount__ collaborators per project",
"unlimited_collaborators_in_each_project": "Unlimited collaborators in each project",
"most_premium_features": "Most premium features",
"total_per_year_lowercase": "total per year",
"user_management": "User management",
"user_management_info": "Group plan admins have access to an admin panel where users can be added and removed easily. For site-wide plans, users are automatically upgraded when they register or add their email address to Overleaf (domain-based enrollment or SSO).",
"usage_metrics": "Usage metrics",
"usage_metrics_info": "Metrics that show how many users are accessing the licence, how many projects are being created and worked on, and how much collaboration is happening in Overleaf.",
"sso_integration": "SSO integration",
"sso_integration_info": "Overleaf offers a standard SAML-based Single Sign On integration.",
"sitewide_option_available": "Site-wide option available",
"sitewide_option_available_info": "Users are automatically upgraded when they register or add their email address to Overleaf (domain-based enrollment or SSO).",
"custom_resource_portal": "Custom resource portal",
"custom_resource_portal_info": "You can have your own custom portal page on Overleaf. This is a great place for your users to find out more about Overleaf, access templates, FAQs and Help resources, and sign up to Overleaf.",
"personalised_onboarding": "Personalised onboarding",
"personalised_onboarding_info": "Well help you get everything set up and then were here to answer questions from your users about the platform, templates or LaTeX!",
"dedicated_account_manager": "Dedicated account manager",
"dedicated_account_manager_info": "Our Account Management Team will be able to assist with requests, questions and to help you spread the word about Overleaf with promotional materials, training resources and webinars.",
"group_standard": "Group Standard",
"group_professional": "Group Professional",
"organization": "Organization",
"group_admins_get_access_to": "Group admins get access to",
"group_admins_get_access_to_info": "Special features available only on group plans.",
"group_members_and_collaborators_get_access_to": "Group members and their project collaborators get access to",
"group_members_and_collaborators_get_access_to_info": "These features are available to group members and their collaborators (other Overleaf users invited to projects owned a group member).",
"group_members_get_access_to": "Group members get access to",
"group_members_get_access_to_info": "These features are available only to group members (subscribers).",
"best_choices_companies_universities_non_profits": "Best choice for companies, universities and non-profits",
"for_groups_or_site_wide": "For groups or site-wide",
"also_available_as_on_premises": "Also available as On-Premises",
"how_many_licenses_are_you_looking_for": "How many licenses are you looking for?",
"include_educational_discount": "Include educational discount",
"include_educational_discount_info": "Overleaf offers a 40% educational discount for groups of 10 or more. Applies to students or faculty using Overleaf for teaching.",
"try_for_free": "Try for free",
"customize": "Customize",
"your_plan_lowercase": "your plan",
"save_20_percent_by_paying_annually": "Save 20% by paying annually",
"saving_20_percent": "Saving 20%!",
"feature_included": "Feature included",
"feature_not_included": "Feature not included",
"or_contact_us": "or <0>contact us</0>",
"or_buy_now": "or <0>buy now</0>",
"all_our_group_plans_offer_educational_discount": "All of our <0>group plans</0> offer an <1>educational discount</1> for students and faculty",
"unlink_dropbox_folder": "Unlink Dropbox Account",
"unlink_dropbox_warning": "Any projects that you have synced with Dropbox will be disconnected and no longer kept in sync with Dropbox. Are you sure you want to unlink your Dropbox account?",
"save_20_percent_by_paying_annually": "Save 20% by paying annually",
"saving_20_percent": "Saving 20%!"
"group_plans_are_only_available_on_an_annual_billing_cycle": "Group plans are only available on an annual billing cycle"
}