diff --git a/services/web/app/src/Features/Subscription/SubscriptionController.js b/services/web/app/src/Features/Subscription/SubscriptionController.js index 0a4cc2ee5f..4315462be7 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionController.js +++ b/services/web/app/src/Features/Subscription/SubscriptionController.js @@ -9,7 +9,10 @@ const logger = require('@overleaf/logger') const GeoIpLookup = require('../../infrastructure/GeoIpLookup') const FeaturesUpdater = require('./FeaturesUpdater') const planFeatures = require('./planFeatures') -const plansV2Config = require('./plansV2Config') +const noPersonalPlansConfig = require('./st-personal-off-variant/plansConfig') +const hasPersonalPlansConfig = require('./st-personal-off-default/plansConfig') +const noPersonalInterstitialPaymentConfig = require('./st-personal-off-variant/interstitialPaymentConfig') +const hasPersonalInterstitialPaymentConfig = require('./st-personal-off-default/interstitialPaymentConfig') const GroupPlansData = require('./GroupPlansData') const V1SubscriptionManager = require('./V1SubscriptionManager') const Errors = require('../Errors/Errors') @@ -21,7 +24,6 @@ const { expressify } = require('../../util/promises') const OError = require('@overleaf/o-error') const SplitTestHandler = require('../SplitTests/SplitTestHandler') const SubscriptionHelper = require('./SubscriptionHelper') -const interstitialPaymentConfig = require('./interstitialPaymentConfig') const groupPlanModalOptions = Settings.groupPlanModalOptions const validGroupPlanModalOptions = { @@ -31,6 +33,22 @@ const validGroupPlanModalOptions = { usage: groupPlanModalOptions.usages.map(item => item.code), } +function getPlansSplitOptions(assignment) { + if (assignment?.variant === 'personal-off') { + return { + directory: 'st-personal-off-variant', + plansConfig: noPersonalPlansConfig, + interstitialPaymentConfig: noPersonalInterstitialPaymentConfig, + } + } + + return { + directory: 'st-personal-off-default', + plansConfig: hasPersonalPlansConfig, + interstitialPaymentConfig: hasPersonalInterstitialPaymentConfig, + } +} + async function plansPage(req, res) { const plans = SubscriptionViewModelBuilder.buildPlansList() @@ -66,14 +84,34 @@ async function plansPage(req, res) { usage: getDefault('usage', 'usage', 'enterprise'), } + let removePersonalPlanAssingment = { variant: 'default' } + try { + removePersonalPlanAssingment = + await SplitTestHandler.promises.getAssignment( + req, + res, + 'remove-personal-plan' + ) + } catch (error) { + logger.error( + { err: error }, + 'Failed to get assignment for remove-personal-plan test' + ) + } + + const { plansConfig, directory } = getPlansSplitOptions( + removePersonalPlanAssingment + ) + AnalyticsManager.recordEventForSession(req.session, 'plans-page-view', { - currency, + currency: recommendedCurrency, + 'remove-personal-plan-page': removePersonalPlanAssingment?.variant, countryCode, 'geo-pricing-inr-group': geoPricingTestVariant, 'geo-pricing-inr-page': currency === 'INR' ? 'inr' : 'default', }) - res.render('subscriptions/plans-marketing-v2', { + res.render(`subscriptions/plans-marketing/${directory}/plans-marketing-v2`, { title: 'plans_and_pricing', currentView, plans, @@ -82,7 +120,7 @@ async function plansPage(req, res) { itm_campaign: 'plans', recommendedCurrency: currency, planFeatures, - plansV2Config, + plansConfig, groupPlans: GroupPlansData, groupPlanModalOptions, groupPlanModalDefaults, @@ -380,6 +418,25 @@ async function interstitialPaymentPage(req, res) { const showSkipLink = req.query?.skipLink === 'true' + let removePersonalPlanAssingment = { variant: 'default' } + try { + removePersonalPlanAssingment = + await SplitTestHandler.promises.getAssignment( + req, + res, + 'remove-personal-plan' + ) + } catch (error) { + logger.error( + { err: error }, + 'Failed to get assignment for remove-personal-plan test' + ) + } + + const { interstitialPaymentConfig, directory } = getPlansSplitOptions( + removePersonalPlanAssingment + ) + if (hasSubscription) { res.redirect('/user/subscription?hasSubscription=true') } else { @@ -392,18 +449,22 @@ async function interstitialPaymentPage(req, res) { 'geo-pricing-inr-group': geoPricingTestVariant, 'geo-pricing-inr-page': recommendedCurrency === 'INR' ? 'inr' : 'default', + 'remove-personal-plan-page': removePersonalPlanAssingment?.variant, } ) - res.render('subscriptions/interstitial-payment', { - title: 'subscribe', - itm_content: req.query?.itm_content, - itm_campaign: req.query?.itm_campaign, - itm_referrer: req.query?.itm_referrer, - recommendedCurrency, - interstitialPaymentConfig, - showSkipLink, - }) + res.render( + `subscriptions/plans-marketing/${directory}/interstitial-payment`, + { + title: 'subscribe', + itm_content: req.query?.itm_content, + itm_campaign: req.query?.itm_campaign, + itm_referrer: req.query?.itm_referrer, + recommendedCurrency, + interstitialPaymentConfig, + showSkipLink, + } + ) } } diff --git a/services/web/app/src/Features/Subscription/interstitialPaymentConfig.js b/services/web/app/src/Features/Subscription/st-personal-off-default/interstitialPaymentConfig.js similarity index 100% rename from services/web/app/src/Features/Subscription/interstitialPaymentConfig.js rename to services/web/app/src/Features/Subscription/st-personal-off-default/interstitialPaymentConfig.js diff --git a/services/web/app/src/Features/Subscription/plansV2Config.js b/services/web/app/src/Features/Subscription/st-personal-off-default/plansConfig.js similarity index 96% rename from services/web/app/src/Features/Subscription/plansV2Config.js rename to services/web/app/src/Features/Subscription/st-personal-off-default/plansConfig.js index 3aade2fd24..b6747e4d2c 100644 --- a/services/web/app/src/Features/Subscription/plansV2Config.js +++ b/services/web/app/src/Features/Subscription/st-personal-off-default/plansConfig.js @@ -1,4 +1,4 @@ -const plansV2Features = require('./plansV2Features') +const plansV2Features = require('./plansFeatures') const config = { individual: { diff --git a/services/web/app/src/Features/Subscription/plansV2Features.js b/services/web/app/src/Features/Subscription/st-personal-off-default/plansFeatures.js similarity index 100% rename from services/web/app/src/Features/Subscription/plansV2Features.js rename to services/web/app/src/Features/Subscription/st-personal-off-default/plansFeatures.js diff --git a/services/web/app/src/Features/Subscription/st-personal-off-variant/interstitialPaymentConfig.js b/services/web/app/src/Features/Subscription/st-personal-off-variant/interstitialPaymentConfig.js new file mode 100644 index 0000000000..b7ef58ee07 --- /dev/null +++ b/services/web/app/src/Features/Subscription/st-personal-off-variant/interstitialPaymentConfig.js @@ -0,0 +1,218 @@ +const config = { + tableHead: { + individual_free: {}, + individual_collaborator: {}, + individual_professional: {}, + student_student: { + showExtraContent: true, + }, + }, + highlightedColumn: { + index: 1, + text: { + monthly: 'MOST POPULAR', + annual: 'MOST POPULAR', + }, + }, + eventTrackingKey: 'paywall-plans-page-click', + showStudentsOnlyLabel: true, + features: [ + { + divider: false, + items: [ + { + feature: 'number_of_users', + info: 'number_of_users_info', + value: 'str', + plans: { + free: '1 user', + collaborator: '1 user', + professional: '1 user', + student: '1 user', + }, + }, + { + feature: 'max_collab_per_project', + info: 'max_collab_per_project_info', + value: 'richText', + plans: { + free: 'You + 1', + collaborator: 'You + 10', + professional: 'Unlimited', + student: 'You + 6', + }, + }, + ], + }, + { + 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', + collaborator: '4 minutes', + professional: '4 minutes', + student: '4 minutes', + }, + }, + { + feature: 'realtime_track_changes', + info: 'realtime_track_changes_info_v2', + value: 'bool', + plans: { + free: false, + collaborator: true, + professional: true, + student: true, + }, + }, + { + feature: 'full_doc_history', + info: 'full_doc_history_info_v2', + value: 'bool', + plans: { + free: false, + collaborator: true, + professional: true, + student: true, + }, + }, + { + feature: 'reference_search', + info: 'reference_search_info_v2', + value: 'bool', + plans: { + free: false, + collaborator: true, + professional: true, + student: true, + }, + }, + { + feature: 'git_integration_lowercase', + info: 'git_integration_lowercase_info', + value: 'bool', + plans: { + free: false, + collaborator: true, + professional: true, + student: 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, + collaborator: true, + professional: true, + student: true, + }, + }, + { + feature: 'unlimited_projects', + info: 'unlimited_projects_info', + value: 'bool', + plans: { + free: true, + collaborator: true, + professional: true, + student: true, + }, + }, + { + feature: 'thousands_templates', + info: 'hundreds_templates_info', + value: 'bool', + plans: { + free: true, + collaborator: true, + professional: true, + student: true, + }, + }, + { + feature: 'symbol_palette', + info: 'symbol_palette_info', + value: 'bool', + plans: { + free: false, + collaborator: true, + professional: true, + student: true, + }, + }, + { + feature: 'github_only_integration_lowercase', + info: 'github_only_integration_lowercase_info', + value: 'bool', + plans: { + free: false, + collaborator: true, + professional: true, + student: true, + }, + }, + { + feature: 'dropbox_integration_lowercase', + info: 'dropbox_integration_info', + value: 'bool', + plans: { + free: false, + collaborator: true, + professional: true, + student: true, + }, + }, + { + feature: 'mendeley_integration_lowercase', + info: 'mendeley_integration_lowercase_info', + value: 'bool', + plans: { + free: false, + collaborator: true, + professional: true, + student: true, + }, + }, + { + feature: 'zotero_integration_lowercase', + info: 'zotero_integration_lowercase_info', + value: 'bool', + plans: { + free: false, + collaborator: true, + professional: true, + student: true, + }, + }, + { + feature: 'priority_support', + info: 'priority_support_info', + value: 'bool', + plans: { + free: false, + collaborator: true, + professional: true, + student: true, + }, + }, + ], + }, + ], +} + +module.exports = config diff --git a/services/web/app/src/Features/Subscription/st-personal-off-variant/plansConfig.js b/services/web/app/src/Features/Subscription/st-personal-off-variant/plansConfig.js new file mode 100644 index 0000000000..7a39a1df20 --- /dev/null +++ b/services/web/app/src/Features/Subscription/st-personal-off-variant/plansConfig.js @@ -0,0 +1,62 @@ +const plansV2Features = require('./plansFeatures') + +const config = { + individual: { + tableHead: { + individual_free: {}, + individual_collaborator: {}, + individual_professional: {}, + }, + features: plansV2Features.individual, + highlightedColumn: { + index: 1, + text: { + monthly: 'MOST POPULAR', + annual: 'MOST POPULAR', + }, + }, + eventTrackingKey: 'plans-page-click', + additionalEventSegmentation: {}, + }, + group: { + tableHead: { + group_collaborator: {}, + group_professional: {}, + group_organization: {}, + }, + features: plansV2Features.group, + highlightedColumn: { + index: 0, + text: { + annual: 'MOST POPULAR', + }, + }, + eventTrackingKey: 'plans-page-click', + additionalEventSegmentation: {}, + }, + student: { + baseColspan: 2, + maxColumn: 3, + tableHead: { + student_free: { + colspan: 3, + }, + student_student: { + showExtraContent: false, + colspan: 3, + }, + }, + features: plansV2Features.student, + highlightedColumn: { + index: 1, + text: { + monthly: 'SAVE 20% ON ANNUAL PLAN', + annual: 'SAVING 20%', + }, + }, + eventTrackingKey: 'plans-page-click', + additionalEventSegmentation: {}, + }, +} + +module.exports = config diff --git a/services/web/app/src/Features/Subscription/st-personal-off-variant/plansFeatures.js b/services/web/app/src/Features/Subscription/st-personal-off-variant/plansFeatures.js new file mode 100644 index 0000000000..4c11ea3929 --- /dev/null +++ b/services/web/app/src/Features/Subscription/st-personal-off-variant/plansFeatures.js @@ -0,0 +1,612 @@ +const individualPlans = [ + { + divider: false, + items: [ + { + feature: 'number_of_users', + info: 'number_of_users_info', + value: 'str', + plans: { + free: '1 user', + collaborator: '1 user', + professional: '1 user', + }, + }, + { + feature: 'max_collab_per_project', + info: 'max_collab_per_project_info', + value: 'richText', + plans: { + free: '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', + collaborator: '4 minutes', + professional: '4 minutes', + }, + }, + { + feature: 'realtime_track_changes', + info: 'realtime_track_changes_info_v2', + value: 'bool', + plans: { + free: false, + collaborator: true, + professional: true, + }, + }, + { + feature: 'full_doc_history', + info: 'full_doc_history_info_v2', + value: 'bool', + plans: { + free: false, + collaborator: true, + professional: true, + }, + }, + { + feature: 'reference_search', + info: 'reference_search_info_v2', + value: 'bool', + plans: { + free: false, + collaborator: true, + professional: true, + }, + }, + { + feature: 'git_integration_lowercase', + info: 'git_integration_lowercase_info', + value: 'bool', + plans: { + free: false, + 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, + collaborator: true, + professional: true, + }, + }, + { + feature: 'unlimited_projects', + info: 'unlimited_projects_info', + value: 'bool', + plans: { + free: true, + collaborator: true, + professional: true, + }, + }, + { + feature: 'thousands_templates', + info: 'hundreds_templates_info', + value: 'bool', + plans: { + free: true, + collaborator: true, + professional: true, + }, + }, + { + feature: 'symbol_palette', + info: 'symbol_palette_info', + value: 'bool', + plans: { + free: false, + collaborator: true, + professional: true, + }, + }, + { + feature: 'github_only_integration_lowercase', + info: 'github_only_integration_lowercase_info', + value: 'bool', + plans: { + free: false, + collaborator: true, + professional: true, + }, + }, + { + feature: 'dropbox_integration_lowercase', + info: 'dropbox_integration_info', + value: 'bool', + plans: { + free: false, + collaborator: true, + professional: true, + }, + }, + { + feature: 'mendeley_integration_lowercase', + info: 'mendeley_integration_lowercase_info', + value: 'bool', + plans: { + free: false, + collaborator: true, + professional: true, + }, + }, + { + feature: 'zotero_integration_lowercase', + info: 'zotero_integration_lowercase_info', + value: 'bool', + plans: { + free: false, + collaborator: true, + professional: true, + }, + }, + { + feature: 'priority_support', + info: 'priority_support_info', + value: 'bool', + plans: { + free: false, + collaborator: true, + professional: true, + }, + }, + ], + }, +] + +const groupPlans = [ + { + divider: false, + items: [ + { + feature: 'number_of_users', + info: 'number_of_users_info', + value: 'str', + plans: { + group_standard: '2 users', + group_professional: '2 users', + organization: 'Contact sales', + }, + }, + { + feature: 'max_collab_per_project', + info: 'max_collab_per_project_info', + value: 'richText', + 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: 'personalized_onboarding', + info: 'personalized_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 user', + student: '1 user', + }, + }, + { + feature: 'max_collab_per_project', + info: 'max_collab_per_project_info', + value: 'str', + plans: { + free: 'You + 1', + student: 'You + 6', + }, + }, + ], + }, + { + 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', + }, + }, + { + feature: 'realtime_track_changes', + info: 'realtime_track_changes_info_v2', + value: 'bool', + plans: { + free: false, + student: true, + }, + }, + { + feature: 'full_doc_history', + info: 'full_doc_history_info_v2', + value: 'bool', + plans: { + free: false, + student: true, + }, + }, + { + feature: 'reference_search', + info: 'reference_search_info_v2', + value: 'bool', + plans: { + free: false, + student: true, + }, + }, + { + feature: 'git_integration_lowercase', + info: 'git_integration_lowercase_info', + value: 'bool', + plans: { + free: false, + student: 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, + }, + }, + { + feature: 'unlimited_projects', + info: 'unlimited_projects_info', + value: 'bool', + plans: { + free: true, + student: true, + }, + }, + { + feature: 'thousands_templates', + info: 'thousands_templates_info', + value: 'bool', + plans: { + free: true, + student: true, + }, + }, + { + feature: 'symbol_palette', + info: 'symbol_palette_info', + value: 'bool', + plans: { + free: false, + student: true, + }, + }, + { + feature: 'github_only_integration_lowercase', + info: 'github_only_integration_lowercase_info', + value: 'bool', + plans: { + free: false, + student: true, + }, + }, + { + feature: 'dropbox_integration_lowercase', + info: 'dropbox_integration_info', + value: 'bool', + plans: { + free: false, + student: true, + }, + }, + { + feature: 'mendeley_integration_lowercase', + info: 'mendeley_integration_lowercase_info', + value: 'bool', + plans: { + free: false, + student: true, + }, + }, + { + feature: 'zotero_integration_lowercase', + info: 'zotero_integration_lowercase_info', + value: 'bool', + plans: { + free: false, + student: true, + }, + }, + { + feature: 'priority_support', + info: 'priority_support_info', + value: 'bool', + plans: { + free: false, + student: true, + }, + }, + ], + }, +] + +module.exports = { + individual: individualPlans, + group: groupPlans, + student: studentPlans, +} diff --git a/services/web/app/views/subscriptions/interstitial-payment.pug b/services/web/app/views/subscriptions/plans-marketing/st-personal-off-default/interstitial-payment.pug similarity index 96% rename from services/web/app/views/subscriptions/interstitial-payment.pug rename to services/web/app/views/subscriptions/plans-marketing/st-personal-off-default/interstitial-payment.pug index 0391b9286b..4f34c0340c 100644 --- a/services/web/app/views/subscriptions/interstitial-payment.pug +++ b/services/web/app/views/subscriptions/plans-marketing/st-personal-off-default/interstitial-payment.pug @@ -1,6 +1,6 @@ -extends ../layout +extends ../../../layout -include ./plans-marketing/v2/_mixins +include ./v2/_mixins block vars - entrypoint = 'pages/user/subscription/plans-v2/plans-v2-main' diff --git a/services/web/app/views/subscriptions/plans-marketing-v2.pug b/services/web/app/views/subscriptions/plans-marketing/st-personal-off-default/plans-marketing-v2.pug similarity index 86% rename from services/web/app/views/subscriptions/plans-marketing-v2.pug rename to services/web/app/views/subscriptions/plans-marketing/st-personal-off-default/plans-marketing-v2.pug index f765d84aa8..4cc687de3a 100644 --- a/services/web/app/views/subscriptions/plans-marketing-v2.pug +++ b/services/web/app/views/subscriptions/plans-marketing/st-personal-off-default/plans-marketing-v2.pug @@ -1,4 +1,4 @@ -extends ../layout-marketing +extends ../../../layout-marketing block vars - entrypoint = 'pages/user/subscription/plans-v2/plans-v2-main' @@ -20,7 +20,7 @@ block content .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 + include ./v2/_cards_controls_tables .row.row-spaced-large.text-centered .col-xs-12 p.text-centered @@ -36,11 +36,11 @@ block content i.fa.fa-cc-paypal.fa-2x(aria-hidden="true")   span.sr-only Paypal accepted - include ./plans-marketing/v2/_university_info + include ./v2/_university_info - include ./plans-marketing/_quotes + include ../_quotes - include ./plans-marketing/v2/_faq + include ./v2/_faq .row.row-spaced-large .col-md-12 @@ -53,5 +53,5 @@ block content .row.row-spaced - include ./plans-marketing/_group_plan_modal + include ../_group_plan_modal != moduleIncludes("contactModalGeneral-marketing", locals) diff --git a/services/web/app/views/subscriptions/plans-marketing/v2/_cards_controls_tables.pug b/services/web/app/views/subscriptions/plans-marketing/st-personal-off-default/v2/_cards_controls_tables.pug similarity index 98% rename from services/web/app/views/subscriptions/plans-marketing/v2/_cards_controls_tables.pug rename to services/web/app/views/subscriptions/plans-marketing/st-personal-off-default/v2/_cards_controls_tables.pug index 69ccafa655..b1f108103d 100644 --- a/services/web/app/views/subscriptions/plans-marketing/v2/_cards_controls_tables.pug +++ b/services/web/app/views/subscriptions/plans-marketing/st-personal-off-default/v2/_cards_controls_tables.pug @@ -40,7 +40,7 @@ include ./_mixins .col-sm-12 +group_plans_license_picker() -+table_sticky_header_all(plansV2Config) ++table_sticky_header_all(plansConfig) .row.plans-v2-table-container(hidden data-ol-plans-v2-period='monthly') .col-sm-12(data-ol-plans-v2-view='individual') diff --git a/services/web/app/views/subscriptions/plans-marketing/v2/_faq.pug b/services/web/app/views/subscriptions/plans-marketing/st-personal-off-default/v2/_faq.pug similarity index 100% rename from services/web/app/views/subscriptions/plans-marketing/v2/_faq.pug rename to services/web/app/views/subscriptions/plans-marketing/st-personal-off-default/v2/_faq.pug diff --git a/services/web/app/views/subscriptions/plans-marketing/v2/_mixins.pug b/services/web/app/views/subscriptions/plans-marketing/st-personal-off-default/v2/_mixins.pug similarity index 98% rename from services/web/app/views/subscriptions/plans-marketing/v2/_mixins.pug rename to services/web/app/views/subscriptions/plans-marketing/st-personal-off-default/v2/_mixins.pug index c26cc98b36..2e33a25a2f 100644 --- a/services/web/app/views/subscriptions/plans-marketing/v2/_mixins.pug +++ b/services/web/app/views/subscriptions/plans-marketing/st-personal-off-default/v2/_mixins.pug @@ -141,15 +141,15 @@ mixin plans_v2_table(period, config) mixin table_individual(period) table.card.plans-v2-table.plans-v2-table-individual - +plans_v2_table(period, plansV2Config.individual) + +plans_v2_table(period, plansConfig.individual) mixin table_group table.card.plans-v2-table.plans-v2-table-group - +plans_v2_table('annual', plansV2Config.group) + +plans_v2_table('annual', plansConfig.group) mixin table_student(period) table.card.plans-v2-table.plans-v2-table-student - +plans_v2_table(period, plansV2Config.student) + +plans_v2_table(period, plansConfig.student) mixin table_head_individual_free(highlighted, period) .plans-v2-table-th-content @@ -193,7 +193,7 @@ mixin table_head_individual_professional(highlighted, eventTrackingKey, addition .plans-v2-table-btn-buy-container-mobile +btn_buy_individual_professional(highlighted, eventTrackingKey, additionalEventSegmentation, period) ul.plans-v2-table-th-content-benefit - li #{translate("unlimited_collabs")} + li !{translate("unlimited_collabs_rt",{},["b"])} li #{translate("all_premium_features")} .plans-v2-table-btn-buy-container-desktop +btn_buy_individual_professional(highlighted, eventTrackingKey, additionalEventSegmentation, period) @@ -566,21 +566,21 @@ mixin plans_v2_table_sticky_header(withSwitch, config) default span #{translate(translateKey)} -mixin table_sticky_header_all(plansV2Config) +mixin table_sticky_header_all(plansConfig) .row.plans-v2-table-sticky-header-container( data-ol-plans-v2-view='individual' ) - +plans_v2_table_sticky_header(true, plansV2Config.individual) + +plans_v2_table_sticky_header(true, plansConfig.individual) .row.plans-v2-table-sticky-header-container( hidden data-ol-plans-v2-view='group' ) - +plans_v2_table_sticky_header(false, plansV2Config.group) + +plans_v2_table_sticky_header(false, plansConfig.group) .row.plans-v2-table-sticky-header-container( hidden data-ol-plans-v2-view='student' ) - +plans_v2_table_sticky_header(true, plansV2Config.student) + +plans_v2_table_sticky_header(true, plansConfig.student) mixin monthly_annual_switch(initialState, eventTracking, eventSegmentation) - var monthlyAnnualToggleChecked = initialState === 'monthly' diff --git a/services/web/app/views/subscriptions/plans-marketing/v2/_university_info.pug b/services/web/app/views/subscriptions/plans-marketing/st-personal-off-default/v2/_university_info.pug similarity index 100% rename from services/web/app/views/subscriptions/plans-marketing/v2/_university_info.pug rename to services/web/app/views/subscriptions/plans-marketing/st-personal-off-default/v2/_university_info.pug diff --git a/services/web/app/views/subscriptions/plans-marketing/st-personal-off-variant/interstitial-payment.pug b/services/web/app/views/subscriptions/plans-marketing/st-personal-off-variant/interstitial-payment.pug new file mode 100644 index 0000000000..4f34c0340c --- /dev/null +++ b/services/web/app/views/subscriptions/plans-marketing/st-personal-off-variant/interstitial-payment.pug @@ -0,0 +1,53 @@ +extends ../../../layout + +include ./v2/_mixins + +block vars + - entrypoint = 'pages/user/subscription/plans-v2/plans-v2-main' + - var suppressFooter = true + - var suppressNavbarRight = true + +block append meta + meta(name="ol-recommendedCurrency" content=recommendedCurrency) + meta(name="ol-itm_content" content=itm_content) + +block content + main.content.content-alt#main-content + .content-page + .plans + .container + .row + .col-md-12 + .page-header.centered.plans-header.text-centered.top-page-header + h1.text-capitalize #{translate('choose_your_plan')} + + +monthly_annual_switch("monthly", "paywall-plans-page-toggle", '{}') + + +plans_v2_table_sticky_header(true, interstitialPaymentConfig) + + .row.plans-v2-table-container(data-ol-plans-v2-period='monthly') + .col-sm-12 + .row + table.card.plans-v2-table.plans-v2-table-individual + +plans_v2_table('monthly', interstitialPaymentConfig) + + .row.plans-v2-table-container(hidden data-ol-plans-v2-period='annual') + .col-sm-12 + .row + table.card.plans-v2-table.plans-v2-table-individual + +plans_v2_table('annual', interstitialPaymentConfig) + + //- 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) + + if (showSkipLink) + .row.row-spaced-small.text-center + a(href='/project' + event-tracking="skip-button-click" + event-tracking-mb="true" + event-tracking-trigger="click" + event-segmentation='{"location": "interstitial-page"}' + ) + | #{translate("continue_with_free_plan")} + + != moduleIncludes("contactModalGeneral-marketing", locals) diff --git a/services/web/app/views/subscriptions/plans-marketing/st-personal-off-variant/plans-marketing-v2.pug b/services/web/app/views/subscriptions/plans-marketing/st-personal-off-variant/plans-marketing-v2.pug new file mode 100644 index 0000000000..4cc687de3a --- /dev/null +++ b/services/web/app/views/subscriptions/plans-marketing/st-personal-off-variant/plans-marketing-v2.pug @@ -0,0 +1,57 @@ +extends ../../../layout-marketing + +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) + meta(name="ol-currentView" content=currentView) + +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 ./v2/_cards_controls_tables + .row.row-spaced-large.text-centered + .col-xs-12 + p.text-centered + strong #{translate("all_prices_displayed_are_in_currency", {recommendedCurrency})} + |   + span #{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 ./v2/_university_info + + include ../_quotes + + include ./v2/_faq + + .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 ../_group_plan_modal + != moduleIncludes("contactModalGeneral-marketing", locals) diff --git a/services/web/app/views/subscriptions/plans-marketing/st-personal-off-variant/v2/_cards_controls_tables.pug b/services/web/app/views/subscriptions/plans-marketing/st-personal-off-variant/v2/_cards_controls_tables.pug new file mode 100644 index 0000000000..b1f108103d --- /dev/null +++ b/services/web/app/views/subscriptions/plans-marketing/st-personal-off-variant/v2/_cards_controls_tables.pug @@ -0,0 +1,65 @@ +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' + event-tracking="plans-page-toggle-plan" + event-tracking-mb="true" + event-tracking-trigger="click" + event-segmentation='{"button": "individual"}' + ) + button.btn.btn-default-outline #{translate("indvidual_plans")} + li.plans-v2-top-switch-group( + data-ol-plans-v2-view-tab='group' + event-tracking="plans-page-toggle-plan" + event-tracking-mb="true" + event-tracking-trigger="click" + event-segmentation='{"button": "group"}' + ) + button.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' + event-tracking="plans-page-toggle-plan" + event-tracking-mb="true" + event-tracking-trigger="click" + event-segmentation='{"button": "student"}' + ) + button.btn.btn-default-outline( + href="#" + ) #{translate("student_plans")} + ++monthly_annual_switch("annual", "plans-page-toggle-period") + +.row(hidden data-ol-plans-v2-license-picker-container) + .col-sm-12 + +group_plans_license_picker() + ++table_sticky_header_all(plansConfig) + +.row.plans-v2-table-container(hidden data-ol-plans-v2-period='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(data-ol-plans-v2-period='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) diff --git a/services/web/app/views/subscriptions/plans-marketing/st-personal-off-variant/v2/_faq.pug b/services/web/app/views/subscriptions/plans-marketing/st-personal-off-variant/v2/_faq.pug new file mode 100644 index 0000000000..4e8ae14c6d --- /dev/null +++ b/services/web/app/views/subscriptions/plans-marketing/st-personal-off-variant/v2/_faq.pug @@ -0,0 +1,43 @@ +.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_what_is_the_difference_between_users_and_collaborators_question')} + p !{translate('faq_what_is_the_difference_between_users_and_collaborators_answer_first_paragraph', {}, [{name: 'strong'}])} + br + p #{translate('faq_what_is_the_difference_between_users_and_collaborators_answer_second_paragraph')} + .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_i_have_free_account_want_subscription_how_question')} + p !{translate('faq_i_have_free_account_want_subscription_how_answer_first_paragraph', {}, [{ name: 'a', attrs: { href: "/for/universities", target: '_blank'}}])} + br + p !{translate('faq_i_have_free_account_want_subscription_how_answer_second_paragraph', {}, [{ name: 'a', attrs: { href: "/learn/how-to/Overleaf_Accounts_and_Subscriptions", target: '_blank'}}])} + .row + .col-md-12 + h3 #{translate('faq_the_individual_standard_plan_10_collab_question')} + p #{translate('faq_the_individual_standard_plan_10_collab_first_paragraph')} + br + p !{translate('faq_the_individual_standard_plan_10_collab_second_paragraph', {}, [{ name: 'a', attrs: { href: "/learn/how-to/Overleaf_premium_features#Account_and_project_level_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_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_pay_by_invoice_question')} + p #{translate('faq_pay_by_invoice_answer_v2')} diff --git a/services/web/app/views/subscriptions/plans-marketing/st-personal-off-variant/v2/_mixins.pug b/services/web/app/views/subscriptions/plans-marketing/st-personal-off-variant/v2/_mixins.pug new file mode 100644 index 0000000000..9ae1f31ffe --- /dev/null +++ b/services/web/app/views/subscriptions/plans-marketing/st-personal-off-variant/v2/_mixins.pug @@ -0,0 +1,598 @@ +mixin features_premium + li   + li + strong #{translate('all_premium_features')} + li #{translate('sync_dropbox_github')} + li #{translate('full_doc_history')} + li #{translate('track_changes')} + li + #{translate('more').toLowerCase()} + +mixin gen_localized_price_for_plan_view(plan, view) + span #{settings.localizedPlanPricing[recommendedCurrency][plan][view]} + +mixin plans_v2_table(period, config) + - var baseColspan = config.baseColspan || 1 + - var maxColumn = config.maxColumn || 4 + - var discountedColumn = config.discountedColumn || {} + tr + th(colspan=baseColspan) + - for (var i = 0; i < maxColumn; i++) + - var tableHeadKey = Object.keys(config.tableHead)[i] + - var tableHeadOptions = Object.values(config.tableHead)[i] || {} + - var colspan = tableHeadOptions.colspan || baseColspan + - var highlighted = i === config.highlightedColumn.index + - var discountHighlighted = i === discountedColumn.index + - var eventTrackingKey = config.eventTrackingKey + - var additionalEventSegmentation = config.additionalEventSegmentation || {} + - + if (discountHighlighted) { + var thClass = 'plans-v2-table-discount-highlighted' + } else if (highlighted) { + var thClass = 'plans-v2-table-green-highlighted' + } else if (i === config.highlightedColumn.index - 1) { + var thClass = 'plans-v2-table-cell-before-green-highlighted-column' + } else { + var thClass = '' + } + th( + class=thClass + colspan=colspan + ) + if (discountHighlighted) + p.plans-v2-table-discount-highlighted-text !{config.discountedColumn.text[period]} + if (highlighted) + p.plans-v2-table-green-highlighted-text !{config.highlightedColumn.text[period]} + case tableHeadKey + when 'individual_free' + +table_head_individual_free(highlighted, period) + when 'individual_collaborator' + +table_head_individual_collaborator(highlighted, eventTrackingKey, additionalEventSegmentation, period) + when 'individual_professional' + +table_head_individual_professional(highlighted, eventTrackingKey, additionalEventSegmentation, period) + when 'group_collaborator' + +table_head_group_collaborator(highlighted, eventTrackingKey, additionalEventSegmentation) + when 'group_professional' + +table_head_group_professional(highlighted, eventTrackingKey, additionalEventSegmentation) + when 'group_organization' + +table_head_group_organization(highlighted, eventTrackingKey, additionalEventSegmentation) + when 'student_free' + +table_head_student_free(highlighted, period) + when 'student_student' + +table_head_student_student(highlighted, eventTrackingKey, additionalEventSegmentation, period, tableHeadOptions.showExtraContent) + when 'student_university' + +table_head_student_university(highlighted, eventTrackingKey, additionalEventSegmentation, period) + + for featuresPerSection in config.features + - var dividerColspan = Object.values(config.tableHead).reduce((prev, curr) => (prev) + (curr.colspan || 1), baseColspan) + if featuresPerSection.divider + tr.plans-v2-table-divider + td( + colspan=dividerColspan + class=((config.highlightedColumn.index === Object.keys(config.tableHead).length - 1) ? 'plans-v2-table-divider-highlighted' : '') + ) + div + b.plans-v2-table-divider-label #{translate(featuresPerSection.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(featuresPerSection.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(featuresPerSection.dividerInfo), + data-placement="top" + ) #{translate("learn_more_lowercase")} + span ) + for feature, featureIndex in featuresPerSection.items + tr( + class=(featureIndex === (featuresPerSection.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}` + colspan=baseColspan + ) + .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)} + for plan, planIndex in Object.keys(feature.plans) + - var tableHeadOptions = Object.values(config.tableHead)[planIndex] || {} + - var colspan = tableHeadOptions.colspan || baseColspan + - + if (planIndex === discountedColumn.index) { + var tdClass = 'plans-v2-table-discount-highlighted' + } else if (planIndex === config.highlightedColumn.index) { + var tdClass = 'plans-v2-table-green-highlighted' + } else if (planIndex === config.highlightedColumn.index - 1) { + var tdClass = 'plans-v2-table-cell-before-green-highlighted-column' + } else { + var tdClass = '' + } + td( + class=tdClass + colspan=colspan + ) + +table_cell(feature, plan) + +mixin table_individual(period) + table.card.plans-v2-table.plans-v2-table-individual + +plans_v2_table(period, plansConfig.individual) + +mixin table_group + table.card.plans-v2-table.plans-v2-table-group + +plans_v2_table('annual', plansConfig.group) + +mixin table_student(period) + table.card.plans-v2-table.plans-v2-table-student + +plans_v2_table(period, plansConfig.student) + +mixin table_head_individual_free(highlighted, period) + .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(highlighted) + ul.plans-v2-table-th-content-benefit + li #{translate("one_collaborator")} + .plans-v2-table-btn-buy-container-desktop + +btn_buy_individual_free(highlighted) + +mixin table_head_individual_collaborator(highlighted, eventTrackingKey, additionalEventSegmentation, period) + .plans-v2-table-th-content + 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(highlighted, eventTrackingKey, additionalEventSegmentation, period) + 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_collaborator(highlighted, eventTrackingKey, additionalEventSegmentation, period) + +mixin table_head_individual_professional(highlighted, eventTrackingKey, additionalEventSegmentation, period) + .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(highlighted, eventTrackingKey, additionalEventSegmentation, period) + ul.plans-v2-table-th-content-benefit + li !{translate("unlimited_collabs_rt",{},["b"])} + li #{translate("all_premium_features")} + .plans-v2-table-btn-buy-container-desktop + +btn_buy_individual_professional(highlighted, eventTrackingKey, additionalEventSegmentation, period) + +mixin table_head_group_collaborator(highlighted, eventTrackingKey, additionalEventSegmentation) + .plans-v2-table-th-content + p.plans-v2-table-th-content-title #{translate("group_standard")} + .plans-v2-table-price-container + strike.plans-v2-table-price-before-discount + +gen_localized_price_for_plan_view('collaborator', 'annual') + p.plans-v2-table-price + span(data-ol-plans-v2-group-price-per-user='collaborator') #{initialLocalizedGroupPrice.pricePerUser.collaborator} + p.plans-v2-table-price-period-label + | per user / year + .plans-v2-table-btn-buy-container-mobile + +btn_buy_group_collaborator(highlighted, eventTrackingKey) + +additional_link_group(eventTrackingKey, additionalEventSegmentation, 'group_collaborator') + ul.plans-v2-table-th-content-benefit + li #{translate("up_to")} !{translate("x_collaborators_per_project", {collaboratorsCount: '10'})} + li + +table_head_group_total_per_year('collaborator') + .plans-v2-table-btn-buy-container-desktop + +btn_buy_group_collaborator(highlighted, eventTrackingKey) + +additional_link_group(eventTrackingKey, additionalEventSegmentation, 'group_collaborator') + +mixin table_head_group_professional(highlighted, eventTrackingKey, additionalEventSegmentation) + .plans-v2-table-th-content + p.plans-v2-table-th-content-title #{translate("group_professional")} + .plans-v2-table-price-container + strike.plans-v2-table-price-before-discount + +gen_localized_price_for_plan_view('professional', 'annual') + p.plans-v2-table-price + span(data-ol-plans-v2-group-price-per-user='professional') #{initialLocalizedGroupPrice.pricePerUser.professional} + p.plans-v2-table-price-period-label + | per user / year + .plans-v2-table-btn-buy-container-mobile + +btn_buy_group_professional(highlighted, eventTrackingKey) + +additional_link_group(eventTrackingKey, additionalEventSegmentation, 'group_professional') + ul.plans-v2-table-th-content-benefit + li #{translate("unlimited_collaborators_in_each_project")} + li + +table_head_group_total_per_year('professional') + .plans-v2-table-btn-buy-container-desktop + +btn_buy_group_professional(highlighted, eventTrackingKey) + +additional_link_group(eventTrackingKey, additionalEventSegmentation, 'group_professional') + +mixin table_head_group_total_per_year(groupPlan) + - var initialLicenseSize = '2' + span.plans-v2-group-total-price(data-ol-plans-v2-group-total-price=groupPlan) #{initialLocalizedGroupPrice.price[groupPlan]} + |   + for licenseSize in groupPlanModalOptions.sizes + span( + hidden=(licenseSize !== initialLicenseSize) + data-ol-plans-v2-table-th-group-license-size=licenseSize + ) !{translate("total_per_year_for_x_users", {licenseSize})} + +mixin table_head_group_organization(highlighted, eventTrackingKey, additionalEventSegmentation) + - var segmentation = JSON.stringify(Object.assign({}, {button: 'group_organization-link', location: 'table-header-list', period: 'annual'}, additionalEventSegmentation)) + .plans-v2-table-th-content + p.plans-v2-table-th-content-title #{translate("organization")} + .plans-v2-table-comments-icon + i.fa.fa-comments-o + .plans-v2-table-btn-buy-container-mobile + +btn_buy_group_organization(highlighted, eventTrackingKey) + 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( + target="_blank" + href="/for/contact-sales" + event-tracking="plans-page-click" + event-tracking-mb="true" + event-tracking-trigger="click" + event-segmentation=segmentation + ) #{translate("also_available_as_on_premises")} + .plans-v2-table-btn-buy-container-desktop + +btn_buy_group_organization(highlighted, eventTrackingKey) + small.plans-v2-table-th-content-additional-link.invisible(aria-hidden="true") + +mixin table_head_student_free(highlighted, period) + 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(highlighted) + ul.plans-v2-table-th-content-benefit + li #{translate("one_collaborator")} + .plans-v2-table-btn-buy-container-desktop + +btn_buy_student_free(highlighted) + +mixin table_head_student_student(highlighted, eventTrackingKey, additionalEventSegmentation, period, showExtraContent) + div.plans-v2-table-th-content + 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(highlighted, eventTrackingKey, additionalEventSegmentation, period) + ul.plans-v2-table-th-content-benefit + li !{translate("x_collaborators_per_project", {collaboratorsCount: '6'})} + li #{translate("all_premium_features")} + if showExtraContent + li + b !{translate("for_students_only")} + + .plans-v2-table-btn-buy-container-desktop + +btn_buy_student_student(highlighted, eventTrackingKey, additionalEventSegmentation, period) + +mixin table_head_student_university(highlighted, eventTrackingKey, additionalEventSegmentation, period) + 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(highlighted, eventTrackingKey, additionalEventSegmentation, period) + 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(highlighted, eventTrackingKey, additionalEventSegmentation, period) + +mixin table_head_price(plan, period) + div.plans-v2-table-price-container + if plan !== 'free' && period === 'annual' + strike.plans-v2-table-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) + - var planValue = feature.plans[plan] + - var featureName = feature.feature + + .plans-v2-table-cell( + data-ol-plans-v2-table-cell-plan=plan + data-ol-plans-v2-table-cell-feature=featureName + ) + if (feature.value === 'richText') + | !{planValue} + else if (feature.value === 'str') + | #{planValue} + else if (feature.value === 'bool') + if (planValue) + 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("number_of_users_with_colon")} + 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 + event-tracking="plans-page-group-size" + event-tracking-mb="true" + event-tracking-trigger="click" + event-tracking-element="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 + event-tracking="plans-page-edu-discount" + event-tracking-mb="true" + event-tracking-trigger="click" + event-tracking-element="checkbox" + ) + span #{translate("apply_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("apply_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("apply_educational_discount_info"), + data-placement="bottom" + ) #{translate("learn_more_lowercase")} + span ) + +mixin btn_buy_individual(highlighted, discountHighlighted, eventTrackingKey, subscriptionPlan, period) + a.btn.plans-v2-table-btn-buy( + data-ol-start-new-subscription=subscriptionPlan + data-ol-event-tracking-key=eventTrackingKey + data-ol-item-view=period + class=(discountHighlighted ? 'btn-dark-blue' : (highlighted ? 'btn-primary' : 'btn-default')) + ) + if (period === 'monthly') + span #{translate("try_for_free")} + else + span #{translate("buy_now_no_exclamation_mark")} + +mixin btn_buy_individual_free() + if (!getSessionUser()) + a.btn.plans-v2-table-btn-buy( + href="/register" + class=(highlighted ? 'btn-primary' : 'btn-default') + ) + span #{translate("try_for_free")} + else + a.btn.plans-v2-table-btn-buy.invisible( + aria-hidden="true" + class=(highlighted ? 'btn-primary' : 'btn-default') + ) + +mixin btn_buy_individual_collaborator(highlighted, eventTrackingKey, additionalEventSegmentation, period) + +btn_buy_individual(highlighted, false, eventTrackingKey, 'collaborator', period) + if (period === 'monthly') + +additional_link_buy(eventTrackingKey, additionalEventSegmentation, 'collaborator', period) + +mixin btn_buy_individual_professional(highlighted, eventTrackingKey, additionalEventSegmentation, period) + +btn_buy_individual(highlighted, false, eventTrackingKey, 'professional', period) + if (period === 'monthly') + +additional_link_buy(eventTrackingKey, additionalEventSegmentation, 'professional', period) + +mixin btn_buy_group_collaborator(highlighted, eventTrackingKey) + a.btn.plans-v2-table-btn-buy( + data-ol-start-new-subscription='group_collaborator' + data-ol-event-tracking-key=eventTrackingKey + data-ol-item-view='annual' + data-ol-has-custom-href + data-ol-location='table-header' + class=(highlighted ? 'btn-primary' : 'btn-default') + ) + span.hidden-desktop #{translate("customize")} + span.hidden-mobile #{translate("customize_your_plan")} + +mixin btn_buy_group_professional(highlighted, eventTrackingKey) + a.btn.plans-v2-table-btn-buy( + data-ol-start-new-subscription='group_professional' + data-ol-event-tracking-key=eventTrackingKey + data-ol-item-view='annual' + data-ol-has-custom-href + data-ol-location='table-header' + class=(highlighted ? 'btn-primary' : 'btn-default') + ) + span.hidden-desktop #{translate("customize")} + span.hidden-mobile #{translate("customize_your_plan")} + +mixin btn_buy_group_organization(highlighted, eventTrackingKey) + a.btn.plans-v2-table-btn-buy( + data-ol-start-new-subscription='group_organization' + data-ol-event-tracking-key=eventTrackingKey + data-ol-item-view='annual' + data-ol-has-custom-href + data-ol-location='table-header' + href='/for/contact-sales' + target='_blank' + class=(highlighted ? 'btn-primary' : 'btn-default') + ) + span #{translate("contact_us_lowercase")} + +mixin btn_buy_student_free(highlighted) + if (!getSessionUser()) + a.btn.plans-v2-table-btn-buy( + href="/register" + class=(highlighted ? 'btn-primary' : 'btn-default') + ) + span #{translate("try_for_free")} + +mixin btn_buy_student_student(highlighted, eventTrackingKey, additionalEventSegmentation, period) + a.btn.plans-v2-table-btn-buy( + data-ol-start-new-subscription='student' + data-ol-event-tracking-key=eventTrackingKey + data-ol-item-view=period + data-ol-location='card' + class=(highlighted ? 'btn-primary' : 'btn-default') + ) + if (period === 'monthly') + span #{translate("try_for_free")} + else + span #{translate("buy_now_no_exclamation_mark")} + if (period === 'monthly') + +additional_link_buy(eventTrackingKey, additionalEventSegmentation, 'student', period) + +mixin btn_buy_student_university(highlighted, eventTrackingKey, additionalEventSegmentation, period) + - var segmentation = JSON.stringify(Object.assign({}, {button: 'student-university', location: 'table-header-list', period}, additionalEventSegmentation)) + a.btn.plans-v2-table-btn-buy( + href="/for/contact-sales" + target="_blank" + event-tracking=eventTrackingKey + event-tracking-mb="true" + event-tracking-trigger="click" + event-segmentation=segmentation + class=(highlighted ? 'btn-primary' : 'btn-default') + ) + span #{translate("contact_us_lowercase")} + +mixin additional_link_group(eventTrackingKey, additionalEventSegmentation, plan) + - var buttonSegmentation = plan + '-link' + - var segmentation = JSON.stringify(Object.assign({}, {button: buttonSegmentation, location: 'table-header'}, additionalEventSegmentation)) + small.plans-v2-table-th-content-additional-link + | #{translate("or")} + a( + href="/for/contact-sales" + target="_blank" + event-tracking=eventTrackingKey + event-tracking-mb="true" + event-tracking-trigger="click" + event-segmentation=segmentation + ) #{translate("contact_us_lowercase")} + +mixin additional_link_buy(eventTrackingKey, additionalEventSegmentation, plan, period) + - var buttonSegmentation = plan + '-link' + - var segmentation = JSON.stringify(Object.assign({}, {button: buttonSegmentation, location: 'table-header', period}, additionalEventSegmentation)) + - var itmCampaign = itm_campaign ? { itm_campaign } : {itm_campaign: 'plans'} + - var itmReferrer = itm_referrer ? { itm_referrer } : {} + - var qs = new URLSearchParams({planCode: plan, currency: recommendedCurrency, itm_content: 'card', ...itmCampaign, ...itmReferrer}) + small.plans-v2-table-th-content-additional-link + | #{translate("or")} + a( + href=`/user/subscription/new?${qs.toString()}` + event-tracking=eventTrackingKey + event-tracking-mb="true" + event-tracking-trigger="click" + event-segmentation=segmentation + ) #{translate("buy_now_no_exclamation_mark")} + +mixin plans_v2_table_sticky_header(withSwitch, config) + - var tableHeadKeys = Object.keys(config.tableHead) + .row.plans-v2-table-sticky-header.sticky( + data-ol-plans-v2-table-sticky-header + class=(withSwitch ? 'plans-v2-table-sticky-header-with-switch' : 'plans-v2-table-sticky-header-without-switch') + ) + - for (var i = 0; i < tableHeadKeys.length; i++) + - var tableHeadKey = tableHeadKeys[i] + - var translateKey = tableHeadKey.split('_')[1] + - + if (config.discountedColumn?.index === i) { + var elClass = 'plans-v2-table-sticky-header-item-discount-highlighted' + } else if (config.highlightedColumn.index === i) { + var elClass = 'plans-v2-table-sticky-header-item-green-highlighted' + } else { + var elClass = '' + } + .plans-v2-table-sticky-header-item( + class=elClass + ) + case tableHeadKey + when 'individual_collaborator' + span #{translate('standard')} + when 'group_professional' + span #{translate(tableHeadKey)} + when 'group_collaborator' + span #{translate('group_standard')} + default + span #{translate(translateKey)} + +mixin table_sticky_header_all(plansConfig) + .row.plans-v2-table-sticky-header-container( + data-ol-plans-v2-view='individual' + ) + +plans_v2_table_sticky_header(true, plansConfig.individual) + .row.plans-v2-table-sticky-header-container( + hidden + data-ol-plans-v2-view='group' + ) + +plans_v2_table_sticky_header(false, plansConfig.group) + .row.plans-v2-table-sticky-header-container( + hidden + data-ol-plans-v2-view='student' + ) + +plans_v2_table_sticky_header(true, plansConfig.student) + +mixin monthly_annual_switch(initialState, eventTracking, eventSegmentation) + - var monthlyAnnualToggleChecked = initialState === 'monthly' + .row + .col-md-4.col-md-offset-4.text-centered.plans-v2-m-a-switch-container(data-ol-plans-v2-m-a-switch-container) + .plans-v2-m-a-switch-annual-text-container + span.underline(data-ol-plans-v2-m-a-switch-text='annual') #{translate("annual")} + .tooltip.in.left.plans-v2-m-a-tooltip( + role="tooltip" + data-ol-plans-v2-m-a-tooltip + class=monthlyAnnualToggleChecked ? 'plans-v2-m-a-tooltip-monthly-selected' : '' + ) + .tooltip-arrow + .tooltip-inner + span(hidden=!monthlyAnnualToggleChecked data-ol-tooltip-period='monthly') #{translate("save_20_percent_by_paying_annually")} + span(hidden=monthlyAnnualToggleChecked data-ol-tooltip-period='annual') #{translate("saving_20_percent")} + + label.plans-v2-m-a-switch(data-ol-plans-v2-m-a-switch) + input( + type="checkbox" + checked=monthlyAnnualToggleChecked + role="switch" + autocomplete="off" + event-tracking=eventTracking + event-tracking-mb="true" + event-tracking-trigger="click" + event-tracking-element="checkbox" + event-segmentation=eventSegmentation + ) + span + span(data-ol-plans-v2-m-a-switch-text='monthly') #{translate("monthly")} diff --git a/services/web/app/views/subscriptions/plans-marketing/st-personal-off-variant/v2/_university_info.pug b/services/web/app/views/subscriptions/plans-marketing/st-personal-off-variant/v2/_university_info.pug new file mode 100644 index 0000000000..916303993d --- /dev/null +++ b/services/web/app/views/subscriptions/plans-marketing/st-personal-off-variant/v2/_university_info.pug @@ -0,0 +1,15 @@ +.row.row-spaced-large.text-centered( + data-ol-plans-university-info-container + hidden +) + .col-sm-8.col-sm-offset-2.col-xs-12.card.plans-v2-university-info + h3.plans-v2-university-info-header #{translate('would_you_like_to_see_a_university_subscription')} + p.plans-v2-university-info-text #{translate('student_and_faculty_support_make_difference')} + a.btn.plans-v2-btn-header.text-capitalize.plans-v2-btn-university-info( + target="_blank" + href="/for/support-an-overleaf-university-subscription" + event-tracking="plans-page-click" + event-tracking-mb="true" + event-tracking-trigger="click" + event-segmentation='{"button": "university-support"}' + ) #{translate('show_your_support')} \ No newline at end of file diff --git a/services/web/locales/en.json b/services/web/locales/en.json index accc079996..4a6a89b9a9 100644 --- a/services/web/locales/en.json +++ b/services/web/locales/en.json @@ -1674,6 +1674,7 @@ "unlimited": "Unlimited", "unlimited_collaborators_in_each_project": "Unlimited collaborators in each project", "unlimited_collabs": "Unlimited collaborators", + "unlimited_collabs_rt": "<0>Unlimited collaborators", "unlimited_private": "Unlimited private projects", "unlimited_private_info": "All your projects are private by default. Invite collaborators to read or edit by email address or by sending them a secret link.", "unlimited_projects": "Unlimited projects", diff --git a/services/web/test/unit/src/Subscription/SubscriptionControllerTests.js b/services/web/test/unit/src/Subscription/SubscriptionControllerTests.js index 75f2c54459..33936edd0a 100644 --- a/services/web/test/unit/src/Subscription/SubscriptionControllerTests.js +++ b/services/web/test/unit/src/Subscription/SubscriptionControllerTests.js @@ -177,7 +177,9 @@ describe('SubscriptionController', function () { describe('groupPlanModal data', function () { it('should pass local currency if valid', function (done) { this.res.render = (page, opts) => { - page.should.equal('subscriptions/plans-marketing-v2') + page.should.equal( + 'subscriptions/plans-marketing/st-personal-off-default/plans-marketing-v2' + ) opts.groupPlanModalDefaults.currency.should.equal('GBP') done() } @@ -189,7 +191,9 @@ describe('SubscriptionController', function () { it('should fallback to USD when valid', function (done) { this.res.render = (page, opts) => { - page.should.equal('subscriptions/plans-marketing-v2') + page.should.equal( + 'subscriptions/plans-marketing/st-personal-off-default/plans-marketing-v2' + ) opts.groupPlanModalDefaults.currency.should.equal('USD') done() } @@ -201,7 +205,9 @@ describe('SubscriptionController', function () { it('should pass valid options for group plan modal and discard invalid', function (done) { this.res.render = (page, opts) => { - page.should.equal('subscriptions/plans-marketing-v2') + page.should.equal( + 'subscriptions/plans-marketing/st-personal-off-default/plans-marketing-v2' + ) opts.groupPlanModalDefaults.size.should.equal('42') opts.groupPlanModalDefaults.plan_code.should.equal('collaborator') opts.groupPlanModalDefaults.currency.should.equal('GBP') @@ -231,7 +237,9 @@ describe('SubscriptionController', function () { describe('with a user without subscription', function () { it('should render the interstitial payment page', function (done) { this.res.render = (page, opts) => { - page.should.equal('subscriptions/interstitial-payment') + page.should.equal( + 'subscriptions/plans-marketing/st-personal-off-default/interstitial-payment' + ) done() } this.SubscriptionController.interstitialPaymentPage(this.req, this.res)