Просмотр исходного кода

Add plans page split test variant with new layout (#6450)

* Add plans page split test variant with new layout

* Set itm_content to toggle if group modal clicked through via variant view toggle button

* Change split test name to be more specific

GitOrigin-RevId: 0fa48b1b74eea84f15e630e3a62b36be5549da9e
Thomas 4 лет назад
Родитель
Сommit
635a478f36

+ 10 - 0
services/web/app/src/Features/Subscription/SubscriptionController.js

@@ -18,6 +18,7 @@ const AnalyticsManager = require('../Analytics/AnalyticsManager')
 const RecurlyEventHandler = require('./RecurlyEventHandler')
 const { expressify } = require('../../util/promises')
 const OError = require('@overleaf/o-error')
+const SplitTestHandler = require('../SplitTests/SplitTestHandler')
 
 const groupPlanModalOptions = Settings.groupPlanModalOptions
 const validGroupPlanModalOptions = {
@@ -56,6 +57,14 @@ async function plansPage(req, res) {
 
   AnalyticsManager.recordEventForSession(req.session, 'plans-page-view')
 
+  const assignment = await SplitTestHandler.promises.getAssignment(
+    req,
+    'plans-page-layout'
+  )
+
+  const newPlansPageVariant =
+    assignment && assignment.variant === 'new-plans-page'
+
   res.render('subscriptions/plans-marketing', {
     title: 'plans_and_pricing',
     plans,
@@ -66,6 +75,7 @@ async function plansPage(req, res) {
     groupPlans: GroupPlansData,
     groupPlanModalOptions,
     groupPlanModalDefaults,
+    newPlansPageVariant,
   })
 }
 

+ 84 - 43
services/web/app/views/subscriptions/plans-marketing.pug

@@ -34,53 +34,94 @@ block content
 						.col-md-8.col-md-offset-2
 							p.text-centered #{translate("sl_benefits_plans")}
 
-					+allCardsAndControls()
-
-					.row.row-spaced-large.text-centered
-						.col-xs-12
-							p.text-centered !{translate('also_provides_free_plan', {}, [{ name: 'a', attrs: { href: '/register' }}])}
-							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
-							div.text-centered #{translate('change_plans_any_time')}<br/> #{translate('billed_after_x_days', {len:'7'})}
-							br
-							div.text-centered #{translate('subject_to_additional_vat')}<br/> #{translate('select_country_vat')}
+					if (newPlansPageVariant)
+						+allCardsAndControlsForVariant
+					else
+						+allCardsAndControls()
 
-					.row.row-spaced-large
-						.col-md-8.col-md-offset-2
-							.card.text-centered
-								.card-header
-									h2 #{translate('looking_multiple_licenses')}
-								span #{translate('reduce_costs_group_licenses')}
+					if (newPlansPageVariant)
+						.row.features-table(event-tracking="features-table-viewed" event-tracking-ga="subscription-funnel" event-tracking-trigger="scroll" event-tracking-send-once="true" event-tracking-label="exp-")
+							.col-sm-12(data-ol-view='monthly')
+								+table_premium
+							.col-sm-12(hidden data-ol-view='annual')
+								+table_premium
+							.col-sm-12(hidden data-ol-view='student')
+								+table_student
+
+						.row.row-spaced-large
+							.col-md-8.col-md-offset-2
+								.card.text-centered
+									.card-header
+										h2 #{translate('looking_multiple_licenses')}
+									span #{translate('reduce_costs_group_licenses')}
+									br
+									br
+									a.btn.btn-default(
+										href="#groups"
+										data-ol-open-group-plan-modal
+										data-ol-location='callout'
+									) #{translate('find_out_more')}
+
+						.row.row-spaced-large.text-centered
+							.col-xs-12
+								p.text-centered !{translate('also_provides_free_plan', {}, [{ name: 'a', attrs: { href: '/register' }}])}
+								i.fa.fa-cc-mastercard.fa-2x(aria-hidden="true") &nbsp;
+								span.sr-only Mastercard accepted
+								i.fa.fa-cc-visa.fa-2x(aria-hidden="true") &nbsp;
+								span.sr-only Visa accepted
+								i.fa.fa-cc-amex.fa-2x(aria-hidden="true") &nbsp;
+								span.sr-only Amex accepted
+								i.fa.fa-cc-paypal.fa-2x(aria-hidden="true") &nbsp;
+								span.sr-only Paypal accepted
+								div.text-centered #{translate('change_plans_any_time')}<br/> #{translate('billed_after_x_days', {len:'7'})}
 								br
+								div.text-centered #{translate('subject_to_additional_vat')}<br/> #{translate('select_country_vat')}
+					else
+						.row.row-spaced-large.text-centered
+							.col-xs-12
+								p.text-centered !{translate('also_provides_free_plan', {}, [{ name: 'a', attrs: { href: '/register' }}])}
+								i.fa.fa-cc-mastercard.fa-2x(aria-hidden="true") &nbsp;
+								span.sr-only Mastercard accepted
+								i.fa.fa-cc-visa.fa-2x(aria-hidden="true") &nbsp;
+								span.sr-only Visa accepted
+								i.fa.fa-cc-amex.fa-2x(aria-hidden="true") &nbsp;
+								span.sr-only Amex accepted
+								i.fa.fa-cc-paypal.fa-2x(aria-hidden="true") &nbsp;
+								span.sr-only Paypal accepted
+								div.text-centered #{translate('change_plans_any_time')}<br/> #{translate('billed_after_x_days', {len:'7'})}
 								br
-								a.btn.btn-default(
-									href="#groups"
-									data-ol-open-group-plan-modal
-									data-ol-location='callout'
-								) #{translate('find_out_more')}
+								div.text-centered #{translate('subject_to_additional_vat')}<br/> #{translate('select_country_vat')}
 
-					.row.row-spaced-large
-						.col-sm-12
-							.page-header.plans-header.plans-subheader.text-centered
-								h2 #{translate('compare_plan_features')}
-					.row
-						.col-md-6.col-md-offset-3
-							+plan_switch('table')
-						.col-md-3.text-right
-							+currency_dropdown
-					.row(event-tracking="features-table-viewed" event-tracking-ga="subscription-funnel" event-tracking-trigger="scroll" event-tracking-send-once="true" event-tracking-label="exp-")
-						.col-sm-12(data-ol-view='monthly')
-							+table_premium
-						.col-sm-12(hidden data-ol-view='annual')
-							+table_premium
-						.col-sm-12(hidden data-ol-view='student')
-							+table_student
+						.row.row-spaced-large
+							.col-md-8.col-md-offset-2
+								.card.text-centered
+									.card-header
+										h2 #{translate('looking_multiple_licenses')}
+									span #{translate('reduce_costs_group_licenses')}
+									br
+									br
+									a.btn.btn-default(
+										href="#groups"
+										data-ol-open-group-plan-modal
+										data-ol-location='callout'
+									) #{translate('find_out_more')}
+
+						.row.row-spaced-large
+							.col-sm-12
+								.page-header.plans-header.plans-subheader.text-centered
+									h2 #{translate('compare_plan_features')}
+						.row
+							.col-md-6.col-md-offset-3
+								+plan_switch('table')
+							.col-md-3.text-right
+								+currency_dropdown
+						.row(event-tracking="features-table-viewed" event-tracking-ga="subscription-funnel" event-tracking-trigger="scroll" event-tracking-send-once="true" event-tracking-label="exp-")
+							.col-sm-12(data-ol-view='monthly')
+								+table_premium
+							.col-sm-12(hidden data-ol-view='annual')
+								+table_premium
+							.col-sm-12(hidden data-ol-view='student')
+								+table_student
 
 					include ./plans-marketing/_quotes
 

+ 106 - 0
services/web/app/views/subscriptions/plans-marketing/_mixins.pug

@@ -65,6 +65,24 @@ mixin card_student_monthly(location)
 		span
 			+price_student_monthly
 	+features_student(location, 'monthly')
+mixin card_student_annual_variant(location)
+	.best-value
+		strong #{translate('best_value')}
+	.card-header
+		h2 #{translate("student")} (#{translate("annual")})
+	h5.tagline #{translate('tagline_student_annual')}
+	.circle
+		span
+			+price_student_annual
+	+btn_buy_student(location, 'annual')
+mixin card_student_monthly_variant(location)
+	.card-header
+		h2 #{translate("student")}
+	h5.tagline #{translate('tagline_student_monthly')}
+	.circle
+		span
+			+price_student_monthly
+	+btn_buy_student(location, 'monthly')
 
 //- Features Lists, used within cards
 mixin features_collaborator(location)
@@ -192,6 +210,27 @@ mixin plan_switch(location)
 				href="#"
 			) #{translate("special_price_student")}
 
+mixin plan_switch_variant()
+	ul.nav.nav-pills
+		li.active(data-ol-view-tab='monthly')
+			a.btn.btn-default-outline(
+				href="#"
+			) #{translate("monthly")}
+		li(data-ol-view-tab='annual')
+			a.btn.btn-default-outline(
+				href="#"
+			) #{translate("annual")}
+		li(data-ol-view-tab='student')
+			a.btn.btn-default-outline(
+				href="#"
+			) #{translate("special_price_student")}
+		li()
+			a.btn.btn-default-outline(
+				href="#groups"
+				data-ol-open-group-plan-modal
+				data-ol-location='toggle'
+			) #{translate("group_plans")}
+
 mixin allCardsAndControls(controlsRowSpaced, listLocation)
 	- var location = listLocation ? 'card_' + listLocation : 'card'
 	.row.top-switch(class=(controlsRowSpaced ? "row-spaced" : ""))
@@ -248,3 +287,70 @@ mixin allCardsAndControls(controlsRowSpaced, listLocation)
 					.col-md-4
 						.card.card-last
 							+card_student_monthly(location)
+
+mixin allCardsAndControlsForVariant()
+	- var location = listLocation ? 'card_' + listLocation : 'card'
+	.row.top-switch(class=(controlsRowSpaced ? "row-spaced" : ""))
+		.col-lg-6.col-lg-offset-3.col-md-8.col-md-offset-1
+			+plan_switch_variant('card')
+		.col-md-2.text-right
+			+currency_dropdown
+
+	.row
+		.col-md-10.col-md-offset-1
+			.row
+				for view in ['monthly', 'annual']
+					.card-group.text-centered(data-ol-view=view hidden=(view==='annual'))
+						.col-md-4
+							.card.card-first
+								.card-header
+									h2 #{translate("personal")}
+								h5.tagline #{translate("tagline_personal")}
+								.circle
+									+price_personal
+								ul.list-unstyled
+									li #{translate("one_collaborator")}
+								+btn_buy_personal(location)
+						.col-md-4
+							.card.card-highlighted
+								.best-value
+									strong #{translate('best_value')}
+								.card-header
+									h2 #{translate("collaborator")}
+								h5.tagline #{translate("tagline_collaborator")}
+								.circle
+									+price_collaborator
+								ul.list-unstyled
+									li
+										strong #{translate("collabs_per_proj", {collabcount:10})}
+								+btn_buy_collaborator(location)
+						.col-md-4
+							.card.card-last
+								.card-header
+									h2 #{translate("professional")}
+								h5.tagline #{translate("tagline_professional")}
+								.circle
+									+price_professional
+								ul.list-unstyled
+									li
+										strong #{translate("unlimited_collabs")}
+								+btn_buy_professional(location)
+
+				.card-group.text-centered(hidden data-ol-view='student')
+					.col-md-4
+						.card.card-first
+							.card-header
+								h2 #{translate("free")}
+							h5.tagline #{translate("tagline_free")}
+							.circle #{translate("free")}
+							ul.list-unstyled
+								li #{translate("one_collaborator")}
+							+btn_buy_free(location)
+
+					.col-md-4
+						.card.card-highlighted
+							+card_student_annual_variant(location)
+
+					.col-md-4
+						.card.card-last
+							+card_student_monthly_variant(location)

+ 15 - 2
services/web/frontend/js/features/plans/group-plan-modal/index.js

@@ -53,6 +53,11 @@ function updateGroupPlanView() {
   ).hidden = size >= 10
 }
 
+function getGroupModalOpeningLocation() {
+  const modalEl = $('[data-ol-group-plan-modal]')
+  return modalEl.data('ol-modal-opening-location')
+}
+
 const modalEl = $('[data-ol-group-plan-modal]')
 modalEl
   .on('shown.bs.modal', function () {
@@ -63,8 +68,11 @@ modalEl
     history.replaceState(null, document.title, window.location.pathname)
   })
 
-function showGroupPlanModal() {
+function showGroupPlanModal(location) {
   modalEl.modal()
+  if (location) {
+    modalEl.data('ol-modal-opening-location', location)
+  }
   eventTracking.send(
     'subscription-funnel',
     'plans-page',
@@ -93,6 +101,11 @@ document.querySelectorAll('[data-ol-purchase-group-plan]').forEach(el =>
     const itmContent = getMeta('ol-itm_content')
     if (itmContent) {
       queryParams.set('itm_content', itmContent)
+    } else {
+      const openingLocation = getGroupModalOpeningLocation()
+      if (openingLocation === 'toggle') {
+        queryParams.set('itm_content', openingLocation)
+      }
     }
     eventTracking.sendMB('groups-modal-click', {
       plan: planCode,
@@ -115,7 +128,7 @@ document.querySelectorAll('[data-ol-open-group-plan-modal]').forEach(el => {
       location,
       period: 'annual',
     })
-    showGroupPlanModal()
+    showGroupPlanModal(location)
   })
 })
 

+ 3 - 0
services/web/frontend/stylesheets/app/plans.less

@@ -132,6 +132,9 @@
       margin-left: @line-height-computed / 2;
     }
   }
+  .features-table {
+    margin-top: 20px;
+  }
 }
 
 #changePlanSection {

+ 4 - 3
services/web/locales/en.json

@@ -598,9 +598,9 @@
   "send": "Send",
   "sending": "Sending",
   "invalid_password": "Invalid Password",
-  "invalid_password_not_set":  "Password is required",
-  "invalid_password_too_short":  "Password too short, minimum __minLength__",
-  "invalid_password_too_long":  "Maximum password length __maxLength__ exceeded",
+  "invalid_password_not_set": "Password is required",
+  "invalid_password_too_short": "Password too short, minimum __minLength__",
+  "invalid_password_too_long": "Maximum password length __maxLength__ exceeded",
   "invalid_password_invalid_character": "Password contains an invalid character",
   "invalid_password_contains_email": "Password can not contain email address",
   "error": "Error",
@@ -887,6 +887,7 @@
   "monthly": "Monthly",
   "personal": "Personal",
   "free": "Free",
+  "group_plans": "Group plans",
   "one_collaborator": "Only one collaborator",
   "collaborator": "Collaborator",
   "collabs_per_proj": "__collabcount__ collaborators per project",