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

new ab framework up and running

Henry Oswald 12 лет назад
Родитель
Сommit
54b9cdc3e4

+ 5 - 2
services/web/app/views/layout.jade

@@ -127,7 +127,10 @@ html(itemscope, itemtype='http://schema.org/Product')
 				};
 				};
 
 
 		span(ng-controller="AbTestController")
 		span(ng-controller="AbTestController")
-		script.
-			window.ab.plan14 = {step:1}
+		//- script.
+		//- 	window.ab = [
+		//- 		{step:1, bucket:"14d", testName:"trial_len"},
+		//- 		{step:2, bucket:"30d", testName:"trial_len"}
+		//- 	]
 
 
 
 

+ 4 - 1
services/web/app/views/subscriptions/new.jade

@@ -27,4 +27,7 @@ block content
 
 
 		Recurly.buildSubscriptionForm(recurlySubscriptionFormConfig);
 		Recurly.buildSubscriptionForm(recurlySubscriptionFormConfig);
 
 
-
+		window.ab = [
+			{step:1, bucket:"14d", testName:"trial_len"},
+			{step:1, bucket:"30d", testName:"trial_len"}
+		]

+ 5 - 4
services/web/app/views/subscriptions/plans.jade

@@ -7,7 +7,8 @@ block content
 				.row
 				.row
 					.col-md-12
 					.col-md-12
 						.page-header.centered.plans-header.text-centered
 						.page-header.centered.plans-header.text-centered
-							h1 #{translate("start_x_day_trial", {len:30})}
+
+							h1(ng-cloak) #{translate("start_x_day_trial", {len:'{{trial_len}}'})}
 				.row
 				.row
 					.col-md-8.col-md-offset-2
 					.col-md-8.col-md-offset-2
 						p.text-centered #{translate("sl_benefits_plans")}
 						p.text-centered #{translate("sl_benefits_plans")}
@@ -63,7 +64,7 @@ block content
 									li
 									li
 										br
 										br
 										a.btn.btn-info(
 										a.btn.btn-info(
-											ng-href="#{baseUrl}/user/subscription/new?planCode=collaborator{{ ui.view == 'annual' && '-annual' || '_free_trial'}}", ng-click="signUpNowClicked('collaborator')"
+											ng-href="#{baseUrl}/user/subscription/new?planCode=collaborator{{ ui.view == 'annual' && '-annual' || planQueryString}}", ng-click="signUpNowClicked('collaborator')"
 										)
 										)
 											span(ng-show="ui.view != 'annual'") #{translate("start_free_trial")}
 											span(ng-show="ui.view != 'annual'") #{translate("start_free_trial")}
 											span(ng-show="ui.view == 'annual'") #{translate("buy_now")}
 											span(ng-show="ui.view == 'annual'") #{translate("buy_now")}
@@ -85,7 +86,7 @@ block content
 									li
 									li
 										br
 										br
 										a.btn.btn-info(
 										a.btn.btn-info(
-											ng-href="#{baseUrl}/user/subscription/new?planCode=professional{{ ui.view == 'annual' && '-annual' || '_free_trial'}}", ng-click="signUpNowClicked('professional')"
+											ng-href="#{baseUrl}/user/subscription/new?planCode=professional{{ ui.view == 'annual' && '-annual' || planQueryString}}", ng-click="signUpNowClicked('professional')"
 										)
 										)
 											span(ng-show="ui.view != 'annual'") #{translate("start_free_trial")}
 											span(ng-show="ui.view != 'annual'") #{translate("start_free_trial")}
 											span(ng-show="ui.view == 'annual'") #{translate("buy_now")}
 											span(ng-show="ui.view == 'annual'") #{translate("buy_now")}
@@ -117,7 +118,7 @@ block content
 									li
 									li
 										br
 										br
 										a.btn.btn-info(
 										a.btn.btn-info(
-											ng-href="#{baseUrl}/user/subscription/new?planCode=student_free_trial", ng-click="signUpNowClicked('student')"
+											ng-href="#{baseUrl}/user/subscription/new?planCode=student{{planQueryString}}", ng-click="signUpNowClicked('student')"
 										) #{translate("start_free_trial")}
 										) #{translate("start_free_trial")}
 							.card
 							.card
 								.card-header
 								.card-header

+ 0 - 198
services/web/app/views/subscriptions/plans_14_day_free_trial.jade

@@ -1,198 +0,0 @@
-extends ../layout
-
-block content
-	.content-alt
-		.content.plans(ng-controller="PlansController")
-			.container
-				.row
-					.col-md-12
-						.page-header.centered.plans-header.text-centered
-							h1 #{translate("start_x_day_trial", {len:14})}
-				.row
-					.col-md-8.col-md-offset-2
-						p.text-centered #{translate("sl_benefits_plans")}
-
-				.row(ng-cloak)
-					.col-md-12
-						ul.nav.nav-pills
-							li(ng-class="{'active': ui.view == 'monthly'}")
-								a(
-									href,
-									ng-click="switchToMonthly()"
-								) #{translate("monthly")}
-							li(ng-class="{'active': ui.view == 'annual'}")
-								a(
-									href
-									ng-click="switchToAnnual()"
-								) #{translate("annual")}
-							li(ng-class="{'active': ui.view == 'student'}")
-								a(
-									href,
-									ng-click="switchToStudent()"
-								) #{translate("half_price_student")} 
-
-				.row(ng-cloak)
-					.col-md-12
-						.card-group.text-centered(ng-if="ui.view == 'monthly' || ui.view == 'annual'")
-							.card
-								.card-header
-									h2 #{translate("personal")} 
-								.circle #{translate("free")} 
-								ul.list-unstyled
-									li #{translate("one_collaborator")}
-									li  
-									li  
-									li
-										br
-										a.btn.btn-info(href="/register") #{translate("sign_up_now")}
-							.card.highlighted
-								.card-header
-									h2 #{translate("collaborator")}
-								.circle
-									span(ng-if="ui.view == 'monthly'")
-										| $15
-										span.small /mo
-									span(ng-if="ui.view == 'annual'")
-										| $180
-										span.small /yr
-								ul.list-unstyled
-									li 
-										strong #{translate("collabs_per_proj", {collabcount:10})}
-									li #{translate("full_doc_history")}
-									li #{translate("sync_to_dropbox")}
-									li
-										br
-										a.btn.btn-info(
-											ng-href="#{baseUrl}/user/subscription/new?planCode=collaborator{{ ui.view == 'annual' && '-annual' || '_free_trial_14_days'}}", ng-click="signUpNowClicked('collaborator')"
-										)
-											span(ng-show="ui.view != 'annual'") #{translate("start_free_trial")}
-											span(ng-show="ui.view == 'annual'") #{translate("buy_now")}
-
-							.card
-								.card-header
-									h2 #{translate("professional")}
-								.circle 
-									span(ng-if="ui.view == 'monthly'")
-										| $30
-										span.small /mo
-									span(ng-if="ui.view == 'annual'")
-										| $360
-										span.small /yr
-								ul.list-unstyled
-									li
-										strong #{translate("unlimited_collabs")}
-									li #{translate("full_doc_history")}
-									li #{translate("sync_to_dropbox")}
-									li
-										br
-										a.btn.btn-info(
-											ng-href="#{baseUrl}/user/subscription/new?planCode=professional{{ ui.view == 'annual' && '-annual' || '_free_trial_14_days'}}", ng-click="signUpNowClicked('professional')"
-										)
-											span(ng-show="ui.view != 'annual'") #{translate("start_free_trial")}
-											span(ng-show="ui.view == 'annual'") #{translate("buy_now")}
-
-						.card-group.text-centered(ng-if="ui.view == 'student'")
-							.card
-								.card-header
-									h2 #{translate("personal")}
-								.circle #{translate("free")}
-								ul.list-unstyled
-									li #{translate("one_collaborator")}
-									li  
-									li  
-									li
-										br
-										a.btn.btn-info(href="/register") #{translate("sign_up_now")}
-							.card.highlighted
-								.card-header
-									h2 #{translate("student")}
-								.circle
-									span
-										| $8
-										span.small /mo
-								ul.list-unstyled
-									li
-										strong #{translate("collabs_per_proj", {collabcount:6})}
-									li #{translate("full_doc_history")}
-									li #{translate("sync_to_dropbox")}
-									li
-										br
-										a.btn.btn-info(
-											ng-href="#{baseUrl}/user/subscription/new?planCode=student_free_trial_14_days", ng-click="signUpNowClicked('student')"
-										) #{translate("start_free_trial")}
-							.card
-								.card-header
-									h2 #{translate("student")} (#{translate("annual")})
-								.circle
-									span
-										| $80
-										span.small /yr
-								ul.list-unstyled
-									li
-										strong #{translate("collabs_per_proj", {collabcount:6})}
-									li #{translate("full_doc_history")}
-									li #{translate("sync_to_dropbox")}
-									li
-										br
-										a.btn.btn-info(
-											ng-href="#{baseUrl}/user/subscription/new?planCode=student-annual", ng-click="signUpNowClicked('student')"
-										) #{translate("buy_now")}
-
-				.row(ng-cloak)
-					p.text-centered #{translate("choose_plan_works_for_you", {len:14})}
-					
-				.row(ng-cloak)
-					.col-md-8.col-md-offset-2
-						.alert.alert-info.text-centered
-							| #{translate("interested_in_group_licence")}
-							br
-							a(href, ng-click="openGroupPlanModal()") #{translate("get_in_touch_for_details")}
-						
-					script(type="text/ng-template", id="groupPlanModalTemplate")
-						.modal-header
-							h3 #{translate("group_plan_enquiry")}
-						.modal-body
-							form(name='form1', autocomplete='off', enctype='multipart/form-data', method='post', novalidate='', action='https://sharelatex.wufoo.com/forms/z7x3p3/#public', _lpchecked='1')
-								.form-group
-									label(for='Field9') #{translate("name")}
-									input.form-control(name='Field9', type='text', value='', maxlength='255', tabindex='1', onkeyup='')
-								
-								.form-group
-									label(for='Field11') #{translate("email")}
-									input.form-control(name='Field11', type='email', spellcheck='false', value='', maxlength='255', tabindex='2')
-								
-								.form-group
-									label(for='Field12') #{translate("university")}
-									input.form-control(name='Field12', type='text', value='', maxlength='255', tabindex='3', onkeyup='')
-									
-								.form-group
-									label(for='Field13') #{translate("position")}
-									input.form-control(name='Field13', type='text', value='', maxlength='255', tabindex='4', onkeyup='')
-								
-								.form-group
-									input.btn.btn-primary.btn-large(name='saveForm', type='submit', value='Send')
-								div(style='display: none;')
-									label(for='comment') Do Not Fill This Out
-									textarea#comment(name='comment', rows='1', cols='1')
-									input#idstamp(type='hidden', name='idstamp', value='xkgLkZnS/AQW71jCS1d0XrrFjq26lJryIPVk2rx0YkU=')
-
-
-				.row
-					.col-md-12
-						.page-header.plans-header.plans-subheader.text-centered
-							h2 #{translate("enjoy_these_features")}
-					.col-md-4
-						.card.features.text-centered
-							i.fa.fa-file-text-o.fa-5x
-							h4 #{translate("unlimited_projects")}
-							p #{translate("create_unlimited_projects")}
-					.col-md-4
-						.card.features.text-centered
-							i.fa.fa-clock-o.fa-5x
-							h4 #{translate("full_doc_history")}
-							p #{translate("never_loose_work")}
-					.col-md-4
-						.card.features.text-centered
-							i.fa.fa-dropbox.fa-5x
-							h4 #{translate("sync_to_dropbox")}
-							p #{translate("access_projects_anywhere")}

+ 6 - 0
services/web/app/views/subscriptions/successful_subscription.jade

@@ -32,3 +32,9 @@ block content
 									img(src="/img/about/james_allen.jpg") 
 									img(src="/img/about/james_allen.jpg") 
 						p
 						p
 							a.btn.btn-primary(href="/project") < #{translate("back_to_your_projects")}
 							a.btn.btn-primary(href="/project") < #{translate("back_to_your_projects")}
+
+	script(type="text/javascript").
+		window.ab = [
+			{step:2, bucket:"14d", testName:"trial_len"},
+			{step:2, bucket:"30d", testName:"trial_len"}
+		]

+ 24 - 13
services/web/public/coffee/analytics/AbTestingManager.coffee

@@ -5,15 +5,15 @@ define [
 	
 	
 	App.factory "abTestManager", ($http, ipCookie) ->
 	App.factory "abTestManager", ($http, ipCookie) ->
 
 
-		_buildCookieKey = (testName)-> "sl_abt_#{testName}"
+		_buildCookieKey = (testName, bucket)-> "sl_abt_#{testName}_#{bucket}"
 
 
-		_getTestCookie = (testName)->
-			cookieKey = _buildCookieKey(testName)
+		_getTestCookie = (testName, bucket)->
+			cookieKey = _buildCookieKey(testName, bucket)
 			return ipCookie(cookieKey)
 			return ipCookie(cookieKey)
 
 
-		_persistCookieStep = (testName, newStep)->
-			ipCookie(_buildCookieKey(testName), step:newStep, {expires:10})
-			ga('send', 'event', 'ab_tests', testName, {step:newStep})
+		_persistCookieStep = (testName, bucket, newStep)->
+			ipCookie(_buildCookieKey(testName, bucket), {step:newStep}, {expires:100})
+			ga('send', 'event', 'ab_tests', "#{testName}:#{bucket}", {step:newStep})
 
 
 		_checkIfStepIsNext = (cookieStep, newStep)->
 		_checkIfStepIsNext = (cookieStep, newStep)->
 			if !cookieStep? and newStep != 0
 			if !cookieStep? and newStep != 0
@@ -25,18 +25,29 @@ define [
 			else 
 			else 
 				return false
 				return false
 
 
-		processTestWithStep: processTestWithStep = (testName, newStep)->
-			currentCookieStep = _getTestCookie(testName)?.step
+		_getUsersHash = (testName)->
+			sl_user_test_token = "sl_utt"
+			user_uuid = ipCookie(sl_user_test_token)
+			if !user_uuid?
+				user_uuid = Math.random()
+				ipCookie(sl_user_test_token, user_uuid, {expires:365})
+			hash = CryptoJS.MD5("#{user_uuid}:#{testName}")
+			return hash
+
+		processTestWithStep: processTestWithStep = (testName, bucket, newStep)->
+			currentCookieStep = _getTestCookie(testName, bucket)?.step
 			if _checkIfStepIsNext(currentCookieStep, newStep)
 			if _checkIfStepIsNext(currentCookieStep, newStep)
-				_persistCookieStep(testName, newStep)
+				_persistCookieStep(testName, bucket, newStep)
 
 
-		getABTestBucket: getABTestBucket = (user_id, test_name, buckets) ->
-			hash = CryptoJS.MD5("#{user_id}:#{test_name}")
+		getABTestBucket: getABTestBucket = (test_name, buckets) ->
+			hash = _getUsersHash(test_name)
 			bucketIndex = parseInt(hash.toString().slice(0,2), 16) % (buckets?.length or 2)
 			bucketIndex = parseInt(hash.toString().slice(0,2), 16) % (buckets?.length or 2)
 			return buckets[bucketIndex]
 			return buckets[bucketIndex]
 
 
+
+
 	App.controller "AbTestController", ($scope, abTestManager)->
 	App.controller "AbTestController", ($scope, abTestManager)->
 		testKeys = _.keys(window.ab)
 		testKeys = _.keys(window.ab)
 
 
-		_.each testKeys, (testName)->
-			abTestManager.processTestWithStep testName, window.ab[testName]?.step
+		_.each window.ab, (event)->
+			abTestManager.processTestWithStep event.testName, event.bucket, event.step

+ 12 - 6
services/web/public/coffee/ide.coffee

@@ -17,6 +17,7 @@ define [
 	"ide/hotkeys/index"
 	"ide/hotkeys/index"
 	"ide/directives/layout"
 	"ide/directives/layout"
 	"ide/services/ide"
 	"ide/services/ide"
+	"analytics/AbTestingmanager"
 	"directives/focus"
 	"directives/focus"
 	"directives/fineUpload"
 	"directives/fineUpload"
 	"directives/scroll"
 	"directives/scroll"
@@ -36,7 +37,7 @@ define [
 	PdfManager
 	PdfManager
 	BinaryFilesManager
 	BinaryFilesManager
 ) ->
 ) ->
-	App.controller "IdeController", ["$scope", "$timeout", "ide", ($scope, $timeout, ide) ->
+	App.controller "IdeController", ($scope, $timeout, ide, abTestManager) ->
 		# Don't freak out if we're already in an apply callback
 		# Don't freak out if we're already in an apply callback
 		$scope.$originalApply = $scope.$apply
 		$scope.$originalApply = $scope.$apply
 		$scope.$apply = (fn = () ->) ->
 		$scope.$apply = (fn = () ->) ->
@@ -61,10 +62,17 @@ define [
 		$scope.anonymous = window.anonymous
 		$scope.anonymous = window.anonymous
 
 
 		$scope.chat = {}
 		$scope.chat = {}
-		
+
 		$scope.startFreeTrial = (source) ->
 		$scope.startFreeTrial = (source) ->
-			ga?('send', 'event', 'subscription-funnel', 'upgraded-free-trial', source)
-			window.open("/user/subscription/new?planCode=student_free_trial")
+
+			buckets = [
+				{ bucketName:"30d", planCode: "student_free_trial" }
+				{ bucketName:"14d", planCode: "student_free_trial_14_days" }
+			]
+			bucket = abTestManager.getABTestBucket "trial_len", buckets
+			abTestManager.processTestWithStep("trial_len", bucket.bucketName, 0)
+
+			window.open("/user/subscription/new?planCode=#{bucket.planCode}")
 			$scope.startedFreeTrial = true
 			$scope.startedFreeTrial = true
 
 
 		window._ide = ide
 		window._ide = ide
@@ -105,7 +113,5 @@ define [
 				$scope.darkTheme = true
 				$scope.darkTheme = true
 			else
 			else
 				$scope.darkTheme = false
 				$scope.darkTheme = false
-			
-	]
 
 
 	angular.bootstrap(document.body, ["SharelatexApp"])
 	angular.bootstrap(document.body, ["SharelatexApp"])

+ 11 - 1
services/web/public/coffee/main/plans.coffee

@@ -1,8 +1,18 @@
 define [
 define [
 	"base"
 	"base"
 ], (App) ->
 ], (App) ->
-	App.controller "PlansController", ($scope, $modal, event_tracking) ->
+	App.controller "PlansController", ($scope, $modal, event_tracking, abTestManager) ->
 		
 		
+
+		buckets = [
+			{ bucketName:"30d", queryString: "_free_trial", trial_len:30 }
+			{ bucketName:"14d", queryString: "_free_trial_14_days", trial_len:14 }
+		]
+		bucket = abTestManager.getABTestBucket "trial_len", buckets
+
+		$scope.trial_len = bucket.trial_len
+		$scope.planQueryString = bucket.queryString
+
 		$scope.ui =
 		$scope.ui =
 			view: "monthly"
 			view: "monthly"