mirror of
https://github.com/overleaf/overleaf.git
synced 2024-09-16 02:52:31 -04:00
Add AB test for plans (+15 squashed commits)
Squashed commits: [45c2237] Add a `subscription-form-switch-to-student` event [1ad9b8f] change experiment name, and re-enable switch-to-student workflow [f7cdb78] Remove debug [4b9778a] Incorporate collaborator alternative plans [701e80b] Add collaborator plans for heron and ibis [287aa0f] AB test plans from editor page [c74052e] Fix change-plan view for default plans [1a947d6] Use correct plan codes [1eecda7] Adjust prices [69c4c7b] Introduce two plans [8b8d5f8] Rename sixpack experiment [c332002] Fix up the change-plan page [c7af52d] Overhaul change-plan page, show only plans from current generation [33d86bf] update plan [5bbd946] Add a basic plans AB test
This commit is contained in:
parent
d0f9a07197
commit
d5a7514923
11 changed files with 418 additions and 179 deletions
|
@ -8,6 +8,7 @@ Settings = require 'settings-sharelatex'
|
|||
logger = require('logger-sharelatex')
|
||||
GeoIpLookup = require("../../infrastructure/GeoIpLookup")
|
||||
SubscriptionDomainHandler = require("./SubscriptionDomainHandler")
|
||||
UserGetter = require "../User/UserGetter"
|
||||
|
||||
module.exports = SubscriptionController =
|
||||
|
||||
|
@ -21,14 +22,27 @@ module.exports = SubscriptionController =
|
|||
if req.query.v?
|
||||
viewName = "#{viewName}_#{req.query.v}"
|
||||
logger.log viewName:viewName, "showing plans page"
|
||||
currentUser = null
|
||||
GeoIpLookup.getCurrencyCode req.query?.ip || req.ip, (err, recomendedCurrency)->
|
||||
return next(err) if err?
|
||||
render = () ->
|
||||
res.render viewName,
|
||||
title: "plans_and_pricing"
|
||||
plans: plans
|
||||
baseUrl: baseUrl
|
||||
gaExperiments: Settings.gaExperiments.plansPage
|
||||
recomendedCurrency:recomendedCurrency
|
||||
shouldABTestPlans: currentUser == null or (currentUser?.signUpDate? and currentUser.signUpDate >= (new Date('2011-10-18')))
|
||||
user_id = AuthenticationController.getLoggedInUserId(req)
|
||||
if user_id?
|
||||
console.log '>> user is logged in'
|
||||
UserGetter.getUser user_id, {signUpDate: 1}, (err, user) ->
|
||||
return next(err) if err?
|
||||
currentUser = user
|
||||
render()
|
||||
else
|
||||
console.log '>> not logged in'
|
||||
render()
|
||||
|
||||
#get to show the recurly.js page
|
||||
paymentPage: (req, res, next) ->
|
||||
|
|
|
@ -68,4 +68,3 @@ module.exports =
|
|||
!plan.groupPlan and plan.annual and plan.planCode.indexOf("student") == -1
|
||||
|
||||
return result
|
||||
|
||||
|
|
|
@ -12,8 +12,8 @@ block scripts
|
|||
|
||||
mixin printPlan(plan)
|
||||
-if (!plan.hideFromUsers)
|
||||
tr(ng-controller="ChangePlanFormController")
|
||||
td(ng-init="plan=#{JSON.stringify(plan)}")
|
||||
tr(ng-controller="ChangePlanFormController", ng-init="plan=#{JSON.stringify(plan)}", ng-show="shouldShowPlan(plan.planCode)")
|
||||
td
|
||||
strong #{plan.name}
|
||||
td {{refreshPrice(plan.planCode)}}
|
||||
-if (plan.annual)
|
||||
|
@ -46,7 +46,7 @@ block content
|
|||
|
|
||||
| #{translate("your_billing_details_were_saved")}
|
||||
.card(ng-if="view == 'overview'")
|
||||
.page-header
|
||||
.page-header(x-current-plan="#{subscription.planCode}")
|
||||
h1 #{translate("your_subscription")}
|
||||
|
||||
- if (subscription && user._id+'' == subscription.admin_id+'')
|
||||
|
@ -56,6 +56,7 @@ block content
|
|||
|
||||
when "active"
|
||||
p !{translate("currently_subscribed_to_plan", {planName:"<strong>" + subscription.name + "</strong>"})}
|
||||
span(ng-show="!isNextGenPlan")
|
||||
a(href, ng-click="changePlan = true") !{translate("change_plan")}.
|
||||
p !{translate("next_payment_of_x_collectected_on_y", {paymentAmmount:"<strong>" + subscription.price + "</strong>", collectionDate:"<strong>" + subscription.nextPaymentDueAt + "</strong>"})}
|
||||
p.pull-right
|
||||
|
|
|
@ -3,6 +3,7 @@ block scripts
|
|||
script(type='text/javascript').
|
||||
window.recomendedCurrency = '#{recomendedCurrency}'
|
||||
window.abCurrencyFlag = '#{abCurrencyFlag}'
|
||||
window.shouldABTestPlans = #{shouldABTestPlans || false}
|
||||
|
||||
script(type='text/javascript').
|
||||
(function() {var s=document.createElement('script'); s.type='text/javascript';s.async=true;
|
||||
|
@ -56,6 +57,7 @@ block content
|
|||
ng-click="changeCurreny(currency)"
|
||||
) {{currency}} ({{value['symbol']}})
|
||||
|
||||
div
|
||||
.row(ng-cloak)
|
||||
.col-md-10.col-md-offset-1
|
||||
.row
|
||||
|
@ -97,7 +99,7 @@ block content
|
|||
br
|
||||
a.btn.btn-info(
|
||||
|
||||
ng-href="#{baseUrl}/user/subscription/new?planCode=collaborator{{ ui.view == 'annual' && '-annual' || planQueryString}}¤cy={{currencyCode}}", ng-click="signUpNowClicked('collaborator')"
|
||||
ng-href="#{baseUrl}/user/subscription/new?planCode=collaborator{{ (ui.view == 'annual' ? '-annual' : '') + (plansVariant == 'default' ? planQueryString : '_'+plansVariant)}}¤cy={{currencyCode}}", ng-click="signUpNowClicked('collaborator')"
|
||||
)
|
||||
span(ng-show="ui.view != 'annual'") #{translate("start_free_trial")}
|
||||
span(ng-show="ui.view == 'annual'") #{translate("buy_now")}
|
||||
|
@ -161,7 +163,8 @@ block content
|
|||
li
|
||||
br
|
||||
a.btn.btn-info(
|
||||
ng-href="#{baseUrl}/user/subscription/new?planCode=student{{planQueryString}}¤cy={{currencyCode}}", ng-click="signUpNowClicked('student')"
|
||||
ng-href="#{baseUrl}/user/subscription/new?planCode=student{{ plansVariant == 'default' ? planQueryString : '_'+plansVariant }}¤cy={{currencyCode}}",
|
||||
ng-click="signUpNowClicked('student')"
|
||||
) #{translate("start_free_trial")}
|
||||
|
||||
.col-md-4
|
||||
|
@ -181,9 +184,12 @@ block content
|
|||
li
|
||||
br
|
||||
a.btn.btn-info(
|
||||
ng-href="#{baseUrl}/user/subscription/new?planCode=student-annual¤cy={{currencyCode}}", ng-click="signUpNowClicked('student')"
|
||||
ng-href="#{baseUrl}/user/subscription/new?planCode=student-annual{{ plansVariant == 'default' ? '' : '_'+plansVariant }}¤cy={{currencyCode}}",
|
||||
ng-click="signUpNowClicked('student')"
|
||||
) #{translate("buy_now")}
|
||||
|
||||
|
||||
|
||||
.row.row-spaced(ng-cloak)
|
||||
p.text-centered #{translate("choose_plan_works_for_you", {len:'{{trial_len}}'})}
|
||||
|
||||
|
|
|
@ -66,6 +66,18 @@ define [
|
|||
pdfLayout: 'sideBySide'
|
||||
}
|
||||
$scope.user = window.user
|
||||
|
||||
|
||||
$scope.startTrialPlanCode = 'collaborator_free_trial_7_days'
|
||||
$scope.shouldABTestPlans = false
|
||||
$scope._plansVariant = 'default'
|
||||
if $scope.user.signUpDate >= '2011-10-18'
|
||||
$scope.shouldABTestPlans = true
|
||||
sixpack.participate 'plans-1610', ['default', 'heron', 'ibis'], (chosenVariation, rawResponse)->
|
||||
$scope._plansVariant = chosenVariation
|
||||
if chosenVariation in ['heron', 'ibis']
|
||||
$scope.startTrialPlanCode = "collaborator_#{chosenVariation}"
|
||||
|
||||
$scope.settings = window.userSettings
|
||||
$scope.anonymous = window.anonymous
|
||||
|
||||
|
|
|
@ -469,7 +469,7 @@ define [
|
|||
|
||||
event_tracking.sendMB "subscription-start-trial", { source }
|
||||
|
||||
window.open("/user/subscription/new?planCode=student_free_trial_7_days")
|
||||
window.open("/user/subscription/new?planCode=#{$scope.startTrialPlanCode}")
|
||||
$scope.startedFreeTrial = true
|
||||
|
||||
App.factory "synctex", ["ide", "$http", "$q", (ide, $http, $q) ->
|
||||
|
|
|
@ -10,9 +10,8 @@ define [
|
|||
|
||||
w = window.open()
|
||||
sixpack.convert "track-changes-discount", ->
|
||||
sixpack.participate 'in-editor-free-trial-plan', ['student', 'collaborator'], (planName, rawResponse)->
|
||||
ga?('send', 'event', 'subscription-funnel', 'upgraded-free-trial', source)
|
||||
url = "/user/subscription/new?planCode=#{planName}_free_trial_7_days&ssp=#{planName == 'collaborator'}"
|
||||
url = "/user/subscription/new?planCode=#{$scope.startTrialPlanCode}&ssp=true"
|
||||
if couponCode?
|
||||
url = "#{url}&cc=#{couponCode}"
|
||||
$scope.startedFreeTrial = true
|
||||
|
|
|
@ -10,7 +10,10 @@ define [
|
|||
$scope.plans = MultiCurrencyPricing.plans
|
||||
|
||||
$scope.switchToStudent = ()->
|
||||
window.location = "/user/subscription/new?planCode=student_free_trial_7_days¤cy=#{$scope.currencyCode}&cc=#{$scope.data.coupon}"
|
||||
currentPlanCode = window.plan_code
|
||||
planCode = currentPlanCode.replace('collaborator', 'student')
|
||||
event_tracking.sendMB 'subscription-form-switch-to-student', { plan: window.plan_code }
|
||||
window.location = "/user/subscription/new?planCode=#{planCode}¤cy=#{$scope.currencyCode}&cc=#{$scope.data.coupon}"
|
||||
|
||||
event_tracking.sendMB "subscription-form", { plan : window.plan_code }
|
||||
|
||||
|
|
|
@ -10,6 +10,165 @@ define [
|
|||
|
||||
return {
|
||||
currencyCode:currencyCode
|
||||
|
||||
heron:
|
||||
USD:
|
||||
student:
|
||||
monthly: "$6"
|
||||
annual: "$60"
|
||||
collaborator:
|
||||
monthly: "$12"
|
||||
annual: "$144"
|
||||
EUR:
|
||||
student:
|
||||
monthly: "€5"
|
||||
annual: "€50"
|
||||
collaborator:
|
||||
monthly: "€10"
|
||||
annual: "€120"
|
||||
GBP:
|
||||
student:
|
||||
monthly: "£5"
|
||||
annual: "£50"
|
||||
collaborator:
|
||||
monthly: "£10"
|
||||
annual: "£120"
|
||||
SEK:
|
||||
student:
|
||||
monthly: "45 kr"
|
||||
annual: "450 kr"
|
||||
collaborator:
|
||||
monthly: "90 kr"
|
||||
annual: "1080 kr"
|
||||
CAD:
|
||||
student:
|
||||
monthly: "$7"
|
||||
annual: "$70"
|
||||
collaborator:
|
||||
monthly: "$14"
|
||||
annual: "$168"
|
||||
NOK:
|
||||
student:
|
||||
monthly: "45 kr"
|
||||
annual: "450 kr"
|
||||
collaborator:
|
||||
monthly: "90 kr"
|
||||
annual: "1080 kr"
|
||||
DKK:
|
||||
student:
|
||||
monthly: "40 kr"
|
||||
annual: "400 kr"
|
||||
collaborator:
|
||||
monthly: "80 kr"
|
||||
annual: "960 kr"
|
||||
AUD:
|
||||
student:
|
||||
monthly: "$8"
|
||||
annual: "$80"
|
||||
collaborator:
|
||||
monthly: "$16"
|
||||
annual: "$192"
|
||||
NZD:
|
||||
student:
|
||||
monthly: "$8"
|
||||
annual: "$80"
|
||||
collaborator:
|
||||
monthly: "$16"
|
||||
annual: "$192"
|
||||
CHF:
|
||||
student:
|
||||
monthly: "Fr 6"
|
||||
annual: "Fr 60"
|
||||
collaborator:
|
||||
monthly: "Fr 12"
|
||||
annual: "Fr 144"
|
||||
SGD:
|
||||
student:
|
||||
monthly: "$8"
|
||||
annual: "$80"
|
||||
collaborator:
|
||||
monthly: "$16"
|
||||
annual: "$192"
|
||||
|
||||
ibis:
|
||||
USD:
|
||||
student:
|
||||
monthly: "$10"
|
||||
annual: "$100"
|
||||
collaborator:
|
||||
monthly: "$18"
|
||||
annual: "$216"
|
||||
EUR:
|
||||
student:
|
||||
monthly: "€9"
|
||||
annual: "€90"
|
||||
collaborator:
|
||||
monthly: "€16"
|
||||
annual: "€192"
|
||||
GBP:
|
||||
student:
|
||||
monthly: "£7"
|
||||
annual: "£70"
|
||||
collaborator:
|
||||
monthly: "£13"
|
||||
annual: "£156"
|
||||
SEK:
|
||||
student:
|
||||
monthly: "75 kr"
|
||||
annual: "750 kr"
|
||||
collaborator:
|
||||
monthly: "140 kr"
|
||||
annual: "1680 kr"
|
||||
CAD:
|
||||
student:
|
||||
monthly: "$12"
|
||||
annual: "$120"
|
||||
collaborator:
|
||||
monthly: "$22"
|
||||
annual: "$264"
|
||||
NOK:
|
||||
student:
|
||||
monthly: "75 kr"
|
||||
annual: "750 kr"
|
||||
collaborator:
|
||||
monthly: "140 kr"
|
||||
annual: "1680 kr"
|
||||
DKK:
|
||||
student:
|
||||
monthly: "68 kr"
|
||||
annual: "680 kr"
|
||||
collaborator:
|
||||
monthly: "122 kr"
|
||||
annual: "1464 kr"
|
||||
AUD:
|
||||
student:
|
||||
monthly: "$13"
|
||||
annual: "$130"
|
||||
collaborator:
|
||||
monthly: "$24"
|
||||
annual: "$288"
|
||||
NZD:
|
||||
student:
|
||||
monthly: "$14"
|
||||
annual: "$140"
|
||||
collaborator:
|
||||
monthly: "$25"
|
||||
annual: "$300"
|
||||
CHF:
|
||||
student:
|
||||
monthly: "Fr 10"
|
||||
annual: "Fr 100"
|
||||
collaborator:
|
||||
monthly: "Fr 18"
|
||||
annual: "Fr 216"
|
||||
SGD:
|
||||
student:
|
||||
monthly: "$14"
|
||||
annual: "$140"
|
||||
collaborator:
|
||||
monthly: "$25"
|
||||
annual: "$300"
|
||||
|
||||
plans:
|
||||
USD:
|
||||
symbol: "$"
|
||||
|
@ -141,23 +300,35 @@ define [
|
|||
professional:
|
||||
monthly: "$40"
|
||||
annual: "$480"
|
||||
|
||||
}
|
||||
|
||||
|
||||
App.controller "PlansController", ($scope, $modal, event_tracking, abTestManager, MultiCurrencyPricing, $http, sixpack) ->
|
||||
|
||||
$scope.plansVariant = 'default'
|
||||
$scope.shouldABTestPlans = window.shouldABTestPlans
|
||||
|
||||
App.controller "PlansController", ($scope, $modal, event_tracking, abTestManager, MultiCurrencyPricing, $http) ->
|
||||
if $scope.shouldABTestPlans
|
||||
sixpack.participate 'plans-1610', ['default', 'heron', 'ibis'], (chosenVariation, rawResponse)->
|
||||
$scope.plansVariant = chosenVariation
|
||||
if chosenVariation in ['heron', 'ibis']
|
||||
# overwrite student plans with alternative
|
||||
for currency, _v of $scope.plans
|
||||
$scope.plans[currency]['student'] = MultiCurrencyPricing[chosenVariation][currency]['student']
|
||||
$scope.plans[currency]['collaborator'] = MultiCurrencyPricing[chosenVariation][currency]['collaborator']
|
||||
|
||||
$scope.plans = MultiCurrencyPricing.plans
|
||||
|
||||
$scope.currencyCode = MultiCurrencyPricing.currencyCode
|
||||
|
||||
$scope.trial_len = 7
|
||||
|
||||
$scope.planQueryString = '_free_trial_7_days'
|
||||
|
||||
$scope.ui =
|
||||
view: "monthly"
|
||||
|
||||
|
||||
$scope.changeCurreny = (newCurrency)->
|
||||
$scope.currencyCode = newCurrency
|
||||
|
||||
|
@ -166,6 +337,9 @@ define [
|
|||
plan = "#{plan}_annual"
|
||||
|
||||
event_tracking.send 'subscription-funnel', 'sign_up_now_button', plan
|
||||
# TODO: double check this is correct
|
||||
if $scope.shouldABTestPlans and plan in ['student', 'collaborator']
|
||||
sixpack.convert 'plans-1610', () ->
|
||||
|
||||
$scope.switchToMonthly = ->
|
||||
$scope.ui.view = "monthly"
|
||||
|
|
|
@ -9,7 +9,7 @@ define [
|
|||
|
||||
App.controller "CurrenyDropdownController", ($scope, MultiCurrencyPricing, $q)->
|
||||
|
||||
$scope.plans = MultiCurrencyPricing.plans
|
||||
# $scope.plans = MultiCurrencyPricing.plans
|
||||
$scope.currencyCode = MultiCurrencyPricing.currencyCode
|
||||
|
||||
$scope.changeCurrency = (newCurrency)->
|
||||
|
@ -31,7 +31,7 @@ define [
|
|||
$scope.currencyCode = MultiCurrencyPricing.currencyCode
|
||||
|
||||
$scope.pricing = MultiCurrencyPricing
|
||||
$scope.plans = MultiCurrencyPricing.plans
|
||||
# $scope.plans = MultiCurrencyPricing.plans
|
||||
$scope.currencySymbol = MultiCurrencyPricing.plans[MultiCurrencyPricing.currencyCode].symbol
|
||||
|
||||
$scope.currencyCode = MultiCurrencyPricing.currencyCode
|
||||
|
@ -87,6 +87,8 @@ define [
|
|||
|
||||
|
||||
App.controller "UserSubscriptionController", ($scope, MultiCurrencyPricing, $http, sixpack, $modal) ->
|
||||
$scope.plans = MultiCurrencyPricing.plans
|
||||
|
||||
freeTrialEndDate = new Date(subscription?.trial_ends_at)
|
||||
|
||||
sevenDaysTime = new Date()
|
||||
|
@ -96,6 +98,16 @@ define [
|
|||
freeTrialExpiresUnderSevenDays = freeTrialEndDate < sevenDaysTime
|
||||
|
||||
$scope.view = 'overview'
|
||||
$scope.getSuffix = (planCode) ->
|
||||
planCode?.match(/(.*?)_(.*)/)?[2] || null
|
||||
$scope.subscriptionSuffix = $scope.getSuffix(window?.subscription?.planCode)
|
||||
if $scope.subscriptionSuffix == 'free_trial_7_days'
|
||||
$scope.subscriptionSuffix = ''
|
||||
$scope.isNextGenPlan = $scope.subscriptionSuffix in ['heron', 'ibis']
|
||||
|
||||
$scope.shouldShowPlan = (planCode) ->
|
||||
$scope.getSuffix(planCode) not in ['heron', 'ibis']
|
||||
|
||||
isMonthlyCollab = subscription?.planCode?.indexOf("collaborator") != -1 and subscription?.planCode?.indexOf("ann") == -1
|
||||
stillInFreeTrial = freeTrialInFuture and freeTrialExpiresUnderSevenDays
|
||||
|
||||
|
@ -166,6 +178,3 @@ define [
|
|||
location.reload()
|
||||
.error ->
|
||||
console.log "something went wrong changing plan"
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ mockSubscriptions =
|
|||
describe "SubscriptionController sanboxed", ->
|
||||
|
||||
beforeEach ->
|
||||
@user = {email:"tom@yahoo.com", _id: 'one'}
|
||||
@user = {email:"tom@yahoo.com", _id: 'one', signUpDate: new Date('2000-10-01')}
|
||||
@activeRecurlySubscription = mockSubscriptions["subscription-123-active"]
|
||||
|
||||
@AuthenticationController =
|
||||
|
@ -63,6 +63,8 @@ describe "SubscriptionController sanboxed", ->
|
|||
getCurrencyCode:sinon.stub()
|
||||
@SubscriptionDomainHandler =
|
||||
getDomainLicencePage:sinon.stub()
|
||||
@UserGetter =
|
||||
getUser: sinon.stub().callsArgWith(2, null, @user)
|
||||
@SubscriptionController = SandboxedModule.require modulePath, requires:
|
||||
'../Authentication/AuthenticationController': @AuthenticationController
|
||||
'./SubscriptionHandler': @SubscriptionHandler
|
||||
|
@ -76,6 +78,7 @@ describe "SubscriptionController sanboxed", ->
|
|||
warn:->
|
||||
"settings-sharelatex": @settings
|
||||
"./SubscriptionDomainHandler":@SubscriptionDomainHandler
|
||||
"../User/UserGetter": @UserGetter
|
||||
|
||||
|
||||
@res = new MockResponse()
|
||||
|
@ -92,12 +95,31 @@ describe "SubscriptionController sanboxed", ->
|
|||
@GeoIpLookup.getCurrencyCode.callsArgWith(1, null, @stubbedCurrencyCode)
|
||||
@res.callback = done
|
||||
@SubscriptionController.plansPage(@req, @res)
|
||||
@UserGetter.getUser = sinon.stub().callsArgWith(2, null, @user)
|
||||
|
||||
it "should set the recommended currency from the geoiplookup", (done)->
|
||||
@res.renderedVariables.recomendedCurrency.should.equal(@stubbedCurrencyCode)
|
||||
@GeoIpLookup.getCurrencyCode.calledWith(@req.ip).should.equal true
|
||||
done()
|
||||
|
||||
it 'should fetch the current user', (done) ->
|
||||
@UserGetter.getUser.callCount.should.equal 1
|
||||
done()
|
||||
|
||||
it 'should decide not to AB test the plans', (done) ->
|
||||
@res.renderedVariables.shouldABTestPlans.should.equal false
|
||||
done()
|
||||
|
||||
describe 'when user is not logged in', (done) ->
|
||||
|
||||
beforeEach ->
|
||||
@AuthenticationController.getLoggedInUserId.returns(null)
|
||||
|
||||
it 'should not fetch the current user', (done) ->
|
||||
@UserGetter.getUser.callCount.should.equal 0
|
||||
done()
|
||||
|
||||
|
||||
describe "editBillingDetailsPage", ->
|
||||
describe "with a user with a subscription", ->
|
||||
beforeEach (done) ->
|
||||
|
|
Loading…
Reference in a new issue