From d5a75149237aaa566de8331d05e84fe4ff981d8c Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Thu, 13 Oct 2016 13:47:05 +0100 Subject: [PATCH 01/15] 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 --- .../SubscriptionController.coffee | 26 +- .../SubscriptionViewModelBuilder.coffee | 5 +- .../app/views/subscriptions/dashboard.jade | 11 +- .../web/app/views/subscriptions/plans.jade | 256 +++++++++--------- services/web/public/coffee/ide.coffee | 18 +- .../ide/pdf/controllers/PdfController.coffee | 8 +- .../public/coffee/main/account-upgrade.coffee | 13 +- .../coffee/main/new-subscription.coffee | 7 +- services/web/public/coffee/main/plans.coffee | 198 +++++++++++++- .../coffee/main/subscription-dashboard.coffee | 31 ++- .../SubscriptionControllerTests.coffee | 24 +- 11 files changed, 418 insertions(+), 179 deletions(-) diff --git a/services/web/app/coffee/Features/Subscription/SubscriptionController.coffee b/services/web/app/coffee/Features/Subscription/SubscriptionController.coffee index 9b812d8d17..fd5b6accc4 100644 --- a/services/web/app/coffee/Features/Subscription/SubscriptionController.coffee +++ b/services/web/app/coffee/Features/Subscription/SubscriptionController.coffee @@ -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? - res.render viewName, - title: "plans_and_pricing" - plans: plans - baseUrl: baseUrl - gaExperiments: Settings.gaExperiments.plansPage - recomendedCurrency:recomendedCurrency + 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) -> diff --git a/services/web/app/coffee/Features/Subscription/SubscriptionViewModelBuilder.coffee b/services/web/app/coffee/Features/Subscription/SubscriptionViewModelBuilder.coffee index 44c31c8d60..8e2fc2032e 100644 --- a/services/web/app/coffee/Features/Subscription/SubscriptionViewModelBuilder.coffee +++ b/services/web/app/coffee/Features/Subscription/SubscriptionViewModelBuilder.coffee @@ -44,7 +44,7 @@ module.exports = allPlans = {} plans.forEach (plan)-> allPlans[plan.planCode] = plan - + result = allPlans: allPlans @@ -54,7 +54,7 @@ module.exports = result.studentAccounts = _.filter plans, (plan)-> plan.planCode.indexOf("student") != -1 - + result.groupMonthlyPlans = _.filter plans, (plan)-> plan.groupPlan and !plan.annual @@ -68,4 +68,3 @@ module.exports = !plan.groupPlan and plan.annual and plan.planCode.indexOf("student") == -1 return result - diff --git a/services/web/app/views/subscriptions/dashboard.jade b/services/web/app/views/subscriptions/dashboard.jade index 34493e5a8c..175c8d1e4f 100644 --- a/services/web/app/views/subscriptions/dashboard.jade +++ b/services/web/app/views/subscriptions/dashboard.jade @@ -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,8 +46,8 @@ block content |   | #{translate("your_billing_details_were_saved")} .card(ng-if="view == 'overview'") - .page-header - h1 #{translate("your_subscription")} + .page-header(x-current-plan="#{subscription.planCode}") + h1 #{translate("your_subscription")} - if (subscription && user._id+'' == subscription.admin_id+'') case subscription.state @@ -56,7 +56,8 @@ block content when "active" p !{translate("currently_subscribed_to_plan", {planName:"" + subscription.name + ""})} - a(href, ng-click="changePlan = true") !{translate("change_plan")}. + span(ng-show="!isNextGenPlan") + a(href, ng-click="changePlan = true") !{translate("change_plan")}. p !{translate("next_payment_of_x_collectected_on_y", {paymentAmmount:"" + subscription.price + "", collectionDate:"" + subscription.nextPaymentDueAt + ""})} p.pull-right p diff --git a/services/web/app/views/subscriptions/plans.jade b/services/web/app/views/subscriptions/plans.jade index 9db21fa3a6..256951a064 100644 --- a/services/web/app/views/subscriptions/plans.jade +++ b/services/web/app/views/subscriptions/plans.jade @@ -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,133 +57,138 @@ block content ng-click="changeCurreny(currency)" ) {{currency}} ({{value['symbol']}}) - .row(ng-cloak) - .col-md-10.col-md-offset-1 - .row - .card-group.text-centered(ng-if="ui.view == 'monthly' || ui.view == 'annual'") - .col-md-4 - .card.card-first - .card-header - h2 #{translate("personal")} - .circle #{translate("free")} - ul.list-unstyled - li #{translate("one_collaborator")} - li   - li   - li   - li - br - a.btn.btn-info( - href="/register" - style=(getLoggedInUserId() === undefined ? "" : "visibility: hidden") - ) #{translate("sign_up_now")} - .col-md-4 - .card.card-highlighted - .card-header - h2 #{translate("collaborator")} - .circle - span(ng-if="ui.view == 'monthly'") - | {{plans[currencyCode]['collaborator']['monthly']}} - span.small /mo - span(ng-if="ui.view == 'annual'") - | {{plans[currencyCode]['collaborator']['annual']}} - 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 #{translate("sync_to_github")} - li - br - a.btn.btn-info( + div + .row(ng-cloak) + .col-md-10.col-md-offset-1 + .row + .card-group.text-centered(ng-if="ui.view == 'monthly' || ui.view == 'annual'") + .col-md-4 + .card.card-first + .card-header + h2 #{translate("personal")} + .circle #{translate("free")} + ul.list-unstyled + li #{translate("one_collaborator")} + li   + li   + li   + li + br + a.btn.btn-info( + href="/register" + style=(getLoggedInUserId() === undefined ? "" : "visibility: hidden") + ) #{translate("sign_up_now")} + .col-md-4 + .card.card-highlighted + .card-header + h2 #{translate("collaborator")} + .circle + span(ng-if="ui.view == 'monthly'") + | {{plans[currencyCode]['collaborator']['monthly']}} + span.small /mo + span(ng-if="ui.view == 'annual'") + | {{plans[currencyCode]['collaborator']['annual']}} + 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 #{translate("sync_to_github")} + li + br + a.btn.btn-info( + + 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")} + .col-md-4 + .card.card-last + .card-header + h2 #{translate("professional")} + .circle + span(ng-if="ui.view == 'monthly'") + | {{plans[currencyCode]['professional']['monthly']}} + span.small /mo + span(ng-if="ui.view == 'annual'") + | {{plans[currencyCode]['professional']['annual']}} + span.small /yr + ul.list-unstyled + li + strong #{translate("unlimited_collabs")} + li #{translate("full_doc_history")} + li #{translate("sync_to_dropbox")} + li #{translate("sync_to_github")} + li + br + a.btn.btn-info( + ng-href="#{baseUrl}/user/subscription/new?planCode=professional{{ ui.view == 'annual' && '-annual' || planQueryString}}¤cy={{currencyCode}}", 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'") + .col-md-4 + .card.card-first + .card-header + h2 #{translate("personal")} + .circle #{translate("free")} + ul.list-unstyled + li #{translate("one_collaborator")} + li   + li   + li   + li + br + a.btn.btn-info( + href="/register" + style=(getLoggedInUserId() === undefined ? "" : "visibility: hidden") + ) #{translate("sign_up_now")} + + .col-md-4 + .card.card-highlighted + .card-header + h2 #{translate("student")} + .circle + span + | {{plans[currencyCode]['student']['monthly']}} + 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 #{translate("sync_to_github")} + li + br + a.btn.btn-info( + 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 + .card.card-last + .card-header + h2 #{translate("student")} (#{translate("annual")}) + .circle + span + | {{plans[currencyCode]['student']['annual']}} + 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 #{translate("sync_to_github")} + li + br + a.btn.btn-info( + ng-href="#{baseUrl}/user/subscription/new?planCode=student-annual{{ plansVariant == 'default' ? '' : '_'+plansVariant }}¤cy={{currencyCode}}", + ng-click="signUpNowClicked('student')" + ) #{translate("buy_now")} - ng-href="#{baseUrl}/user/subscription/new?planCode=collaborator{{ ui.view == 'annual' && '-annual' || planQueryString}}¤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")} - .col-md-4 - .card.card-last - .card-header - h2 #{translate("professional")} - .circle - span(ng-if="ui.view == 'monthly'") - | {{plans[currencyCode]['professional']['monthly']}} - span.small /mo - span(ng-if="ui.view == 'annual'") - | {{plans[currencyCode]['professional']['annual']}} - span.small /yr - ul.list-unstyled - li - strong #{translate("unlimited_collabs")} - li #{translate("full_doc_history")} - li #{translate("sync_to_dropbox")} - li #{translate("sync_to_github")} - li - br - a.btn.btn-info( - ng-href="#{baseUrl}/user/subscription/new?planCode=professional{{ ui.view == 'annual' && '-annual' || planQueryString}}¤cy={{currencyCode}}", 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'") - .col-md-4 - .card.card-first - .card-header - h2 #{translate("personal")} - .circle #{translate("free")} - ul.list-unstyled - li #{translate("one_collaborator")} - li   - li   - li   - li - br - a.btn.btn-info( - href="/register" - style=(getLoggedInUserId() === undefined ? "" : "visibility: hidden") - ) #{translate("sign_up_now")} - - .col-md-4 - .card.card-highlighted - .card-header - h2 #{translate("student")} - .circle - span - | {{plans[currencyCode]['student']['monthly']}} - 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 #{translate("sync_to_github")} - li - br - a.btn.btn-info( - ng-href="#{baseUrl}/user/subscription/new?planCode=student{{planQueryString}}¤cy={{currencyCode}}", ng-click="signUpNowClicked('student')" - ) #{translate("start_free_trial")} - - .col-md-4 - .card.card-last - .card-header - h2 #{translate("student")} (#{translate("annual")}) - .circle - span - | {{plans[currencyCode]['student']['annual']}} - 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 #{translate("sync_to_github")} - li - br - a.btn.btn-info( - ng-href="#{baseUrl}/user/subscription/new?planCode=student-annual¤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}}'})} diff --git a/services/web/public/coffee/ide.coffee b/services/web/public/coffee/ide.coffee index 607b8556aa..4e7721badd 100644 --- a/services/web/public/coffee/ide.coffee +++ b/services/web/public/coffee/ide.coffee @@ -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 @@ -75,7 +87,7 @@ define [ # Only run the header AB test for newly registered users. _abTestStartDate = new Date(Date.UTC(2016, 8, 28)) _userSignUpDate = new Date(window.user.signUpDate) - + $scope.shouldABTestHeaderLabels = _userSignUpDate > _abTestStartDate $scope.headerLabelsABVariant = "" @@ -92,7 +104,7 @@ define [ # Tracking code. $scope.$watch "ui.view", (newView, oldView) -> if newView? and newView != "editor" and newView != "pdf" - event_tracking.sendMBOnce "ide-open-view-#{ newView }-once" + event_tracking.sendMBOnce "ide-open-view-#{ newView }-once" $scope.$watch "ui.chatOpen", (isOpen) -> event_tracking.sendMBOnce "ide-open-chat-once" if isOpen @@ -105,7 +117,7 @@ define [ # End of tracking code. window._ide = ide - + ide.validFileRegex = '^[^\*\/]*$' # Don't allow * and / ide.project_id = $scope.project_id = window.project_id diff --git a/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee b/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee index 790f2384a1..c2559b1faf 100644 --- a/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee +++ b/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee @@ -29,12 +29,12 @@ define [ $scope.$watch "shouldShowLogs", (shouldShow) -> if shouldShow - $scope.$applyAsync () -> + $scope.$applyAsync () -> $scope.shouldDropUp = getFilesDropdownTopCoordAsRatio() > 0.65 # log hints tracking $scope.logHintsNegFeedbackValues = logHintsFeedback.feedbackOpts - + $scope.trackLogHintsLearnMore = () -> event_tracking.sendMB "logs-hints-learn-more" @@ -108,7 +108,7 @@ define [ _csrf: window.csrfToken }, {params: params} - parseCompileResponse = (response) -> + parseCompileResponse = (response) -> # keep last url last_pdf_url = $scope.pdf.url @@ -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) -> diff --git a/services/web/public/coffee/main/account-upgrade.coffee b/services/web/public/coffee/main/account-upgrade.coffee index be842b6907..f2767bfbb1 100644 --- a/services/web/public/coffee/main/account-upgrade.coffee +++ b/services/web/public/coffee/main/account-upgrade.coffee @@ -10,10 +10,9 @@ 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'}" - if couponCode? - url = "#{url}&cc=#{couponCode}" - $scope.startedFreeTrial = true - w.location = url + ga?('send', 'event', 'subscription-funnel', 'upgraded-free-trial', source) + url = "/user/subscription/new?planCode=#{$scope.startTrialPlanCode}&ssp=true" + if couponCode? + url = "#{url}&cc=#{couponCode}" + $scope.startedFreeTrial = true + w.location = url diff --git a/services/web/public/coffee/main/new-subscription.coffee b/services/web/public/coffee/main/new-subscription.coffee index d006c6173c..61961cfccb 100644 --- a/services/web/public/coffee/main/new-subscription.coffee +++ b/services/web/public/coffee/main/new-subscription.coffee @@ -5,12 +5,15 @@ define [ App.controller "NewSubscriptionController", ($scope, MultiCurrencyPricing, abTestManager, $http, sixpack, event_tracking, ccUtils)-> throw new Error("Recurly API Library Missing.") if typeof recurly is "undefined" - + $scope.currencyCode = MultiCurrencyPricing.currencyCode $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 } diff --git a/services/web/public/coffee/main/plans.coffee b/services/web/public/coffee/main/plans.coffee index 4f21c4b5a8..6db59aa0e4 100644 --- a/services/web/public/coffee/main/plans.coffee +++ b/services/web/public/coffee/main/plans.coffee @@ -5,12 +5,171 @@ define [ App.factory "MultiCurrencyPricing", () -> - + currencyCode = window.recomendedCurrency return { currencyCode:currencyCode - plans: + + 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: "$" student: @@ -23,7 +182,7 @@ define [ monthly: "$30" annual: "$360" - EUR: + EUR: symbol: "€" student: monthly: "€7" @@ -34,7 +193,7 @@ define [ professional: monthly: "€28" annual: "€336" - + GBP: symbol: "£" student: @@ -117,7 +276,7 @@ define [ professional: monthly: "$35" annual: "$420" - + CHF: symbol: "Fr" student: @@ -141,36 +300,51 @@ define [ professional: monthly: "$40" annual: "$480" + } - + App.controller "PlansController", ($scope, $modal, event_tracking, abTestManager, MultiCurrencyPricing, $http, sixpack) -> - App.controller "PlansController", ($scope, $modal, event_tracking, abTestManager, MultiCurrencyPricing, $http) -> + $scope.plansVariant = 'default' + $scope.shouldABTestPlans = window.shouldABTestPlans + + 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 $scope.signUpNowClicked = (plan, annual)-> if $scope.ui.view == "annual" plan = "#{plan}_annual" - - event_tracking.send 'subscription-funnel', 'sign_up_now_button', plan + + 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" event_tracking.send 'subscription-funnel', 'plans-page', 'monthly-prices' - + $scope.switchToStudent = -> $scope.ui.view = "student" event_tracking.send 'subscription-funnel', 'plans-page', 'student-prices' @@ -178,7 +352,7 @@ define [ $scope.switchToAnnual = -> $scope.ui.view = "annual" event_tracking.send 'subscription-funnel', 'plans-page', 'student-prices' - + $scope.openGroupPlanModal = () -> $modal.open { templateUrl: "groupPlanModalTemplate" diff --git a/services/web/public/coffee/main/subscription-dashboard.coffee b/services/web/public/coffee/main/subscription-dashboard.coffee index 7476d814e1..22d68baea5 100644 --- a/services/web/public/coffee/main/subscription-dashboard.coffee +++ b/services/web/public/coffee/main/subscription-dashboard.coffee @@ -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 @@ -53,9 +53,9 @@ define [ price = "" App.controller "ConfirmChangePlanController", ($scope, $modalInstance, $http)-> - + $scope.confirmChangePlan = -> - body = + body = plan_code: $scope.plan.planCode _csrf : window.csrfToken @@ -74,7 +74,7 @@ define [ $scope.confirmLeaveGroup = -> $scope.inflight = true $http({ - url: "/subscription/group/user", + url: "/subscription/group/user", method: "DELETE", params: {admin_user_id: $scope.admin_id, _csrf: window.csrfToken} }).success -> @@ -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 @@ -118,7 +130,7 @@ define [ $scope.studentPrice = $scope.currencySymbol + (totalPriceExTax + taxAmmount) $scope.downgradeToStudent = -> - body = + body = plan_code: 'student' _csrf : window.csrfToken $scope.inflight = true @@ -129,7 +141,7 @@ define [ console.log "something went wrong changing plan" $scope.cancelSubscription = -> - body = + body = _csrf : window.csrfToken $scope.inflight = true @@ -158,7 +170,7 @@ define [ $scope.exendTrial = -> - body = + body = _csrf : window.csrfToken $scope.inflight = true $http.put("/user/subscription/extend", body) @@ -166,6 +178,3 @@ define [ location.reload() .error -> console.log "something went wrong changing plan" - - - diff --git a/services/web/test/UnitTests/coffee/Subscription/SubscriptionControllerTests.coffee b/services/web/test/UnitTests/coffee/Subscription/SubscriptionControllerTests.coffee index 1f935e420f..3a43c8988e 100644 --- a/services/web/test/UnitTests/coffee/Subscription/SubscriptionControllerTests.coffee +++ b/services/web/test/UnitTests/coffee/Subscription/SubscriptionControllerTests.coffee @@ -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) -> From 8c1d110688a885ec848b94baed32c401aa7c2d39 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Fri, 21 Oct 2016 16:21:21 +0100 Subject: [PATCH 02/15] Remove debug logs --- .../coffee/Features/Subscription/SubscriptionController.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/services/web/app/coffee/Features/Subscription/SubscriptionController.coffee b/services/web/app/coffee/Features/Subscription/SubscriptionController.coffee index fd5b6accc4..47b9b4bc8e 100644 --- a/services/web/app/coffee/Features/Subscription/SubscriptionController.coffee +++ b/services/web/app/coffee/Features/Subscription/SubscriptionController.coffee @@ -35,13 +35,11 @@ module.exports = SubscriptionController = 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 From c1ebc65a3b0ae9a53ff09123ccc582e426070c10 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Mon, 24 Oct 2016 10:41:32 +0100 Subject: [PATCH 03/15] Move convert to top --- services/web/public/coffee/main/plans.coffee | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/services/web/public/coffee/main/plans.coffee b/services/web/public/coffee/main/plans.coffee index 6db59aa0e4..4817c2d12c 100644 --- a/services/web/public/coffee/main/plans.coffee +++ b/services/web/public/coffee/main/plans.coffee @@ -333,13 +333,11 @@ define [ $scope.currencyCode = newCurrency $scope.signUpNowClicked = (plan, annual)-> - if $scope.ui.view == "annual" - 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', () -> + if $scope.ui.view == "annual" + plan = "#{plan}_annual" + event_tracking.send 'subscription-funnel', 'sign_up_now_button', plan $scope.switchToMonthly = -> $scope.ui.view = "monthly" From 8dfd4879413f839963addad39995b18f91f2a862 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Mon, 24 Oct 2016 11:00:09 +0100 Subject: [PATCH 04/15] Add plan to event tracking --- services/web/public/coffee/main/account-upgrade.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/web/public/coffee/main/account-upgrade.coffee b/services/web/public/coffee/main/account-upgrade.coffee index f2767bfbb1..bbbc4e9e12 100644 --- a/services/web/public/coffee/main/account-upgrade.coffee +++ b/services/web/public/coffee/main/account-upgrade.coffee @@ -6,7 +6,7 @@ define [ $scope.buttonClass = "btn-primary" $scope.startFreeTrial = (source, couponCode) -> - event_tracking.sendMB "subscription-start-trial", { source } + event_tracking.sendMB "subscription-start-trial", { source, plan: $scope.startTrialPlanCode } w = window.open() sixpack.convert "track-changes-discount", -> From 5cf82e4ef7b2858442d93713f159fa2cec6278a8 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Mon, 24 Oct 2016 11:08:19 +0100 Subject: [PATCH 05/15] Add Metabase events --- services/web/public/coffee/main/plans.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/web/public/coffee/main/plans.coffee b/services/web/public/coffee/main/plans.coffee index 4817c2d12c..79ed3afe46 100644 --- a/services/web/public/coffee/main/plans.coffee +++ b/services/web/public/coffee/main/plans.coffee @@ -312,6 +312,7 @@ define [ if $scope.shouldABTestPlans sixpack.participate 'plans-1610', ['default', 'heron', 'ibis'], (chosenVariation, rawResponse)-> $scope.plansVariant = chosenVariation + event_tracking.sendMB 'plans-page', {plans_variant: chosenVariation} if chosenVariation in ['heron', 'ibis'] # overwrite student plans with alternative for currency, _v of $scope.plans @@ -333,6 +334,7 @@ define [ $scope.currencyCode = newCurrency $scope.signUpNowClicked = (plan, annual)-> + event_tracking.sendMB 'plans-page-start-trial', {plan} if $scope.shouldABTestPlans and plan in ['student', 'collaborator'] sixpack.convert 'plans-1610', () -> if $scope.ui.view == "annual" From c051b56abf752dc2858b485aea8f3f4271527652 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Mon, 24 Oct 2016 11:24:28 +0100 Subject: [PATCH 06/15] Cloak plans until they have loaded --- services/web/app/views/subscriptions/plans.jade | 2 +- services/web/public/coffee/main/plans.coffee | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/services/web/app/views/subscriptions/plans.jade b/services/web/app/views/subscriptions/plans.jade index 256951a064..e4bc7b7271 100644 --- a/services/web/app/views/subscriptions/plans.jade +++ b/services/web/app/views/subscriptions/plans.jade @@ -57,7 +57,7 @@ block content ng-click="changeCurreny(currency)" ) {{currency}} ({{value['symbol']}}) - div + div(ng-show="showPlans") .row(ng-cloak) .col-md-10.col-md-offset-1 .row diff --git a/services/web/public/coffee/main/plans.coffee b/services/web/public/coffee/main/plans.coffee index 79ed3afe46..2ea958b876 100644 --- a/services/web/public/coffee/main/plans.coffee +++ b/services/web/public/coffee/main/plans.coffee @@ -306,6 +306,8 @@ define [ App.controller "PlansController", ($scope, $modal, event_tracking, abTestManager, MultiCurrencyPricing, $http, sixpack) -> + $scope.showPlans = false + $scope.plansVariant = 'default' $scope.shouldABTestPlans = window.shouldABTestPlans @@ -318,6 +320,9 @@ define [ for currency, _v of $scope.plans $scope.plans[currency]['student'] = MultiCurrencyPricing[chosenVariation][currency]['student'] $scope.plans[currency]['collaborator'] = MultiCurrencyPricing[chosenVariation][currency]['collaborator'] + $scope.showPlans = true + else + $scope.showPlans = true $scope.plans = MultiCurrencyPricing.plans From 667c7ce520445965abda3f2ce1ddaa058d4d3fe8 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Mon, 24 Oct 2016 11:47:01 +0100 Subject: [PATCH 07/15] Show correct number of collaborators for plans --- services/web/app/views/subscriptions/plans.jade | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/services/web/app/views/subscriptions/plans.jade b/services/web/app/views/subscriptions/plans.jade index e4bc7b7271..d87f601889 100644 --- a/services/web/app/views/subscriptions/plans.jade +++ b/services/web/app/views/subscriptions/plans.jade @@ -91,7 +91,9 @@ block content span.small /yr ul.list-unstyled li - strong #{translate("collabs_per_proj", {collabcount:10})} + strong(ng-show="plansVariant == 'default'") #{translate("collabs_per_proj", {collabcount:10})} + strong(ng-show="plansVariant == 'heron'") #{translate("collabs_per_proj", {collabcount:8})} + strong(ng-show="plansVariant == 'ibis'") #{translate("collabs_per_proj", {collabcount:12})} li #{translate("full_doc_history")} li #{translate("sync_to_dropbox")} li #{translate("sync_to_github")} @@ -156,7 +158,9 @@ block content span.small /mo ul.list-unstyled li - strong #{translate("collabs_per_proj", {collabcount:6})} + strong(ng-show="plansVariant == 'default'") #{translate("collabs_per_proj", {collabcount:6})} + strong(ng-show="plansVariant == 'heron'") #{translate("collabs_per_proj", {collabcount:4})} + strong(ng-show="plansVariant == 'ibis'") #{translate("collabs_per_proj", {collabcount:8})} li #{translate("full_doc_history")} li #{translate("sync_to_dropbox")} li #{translate("sync_to_github")} @@ -177,7 +181,9 @@ block content span.small /yr ul.list-unstyled li - strong #{translate("collabs_per_proj", {collabcount:6})} + strong(ng-show="plansVariant == 'default'") #{translate("collabs_per_proj", {collabcount:6})} + strong(ng-show="plansVariant == 'heron'") #{translate("collabs_per_proj", {collabcount:4})} + strong(ng-show="plansVariant == 'ibis'") #{translate("collabs_per_proj", {collabcount:8})} li #{translate("full_doc_history")} li #{translate("sync_to_dropbox")} li #{translate("sync_to_github")} From c09139961049ed16234858e31dd57cca8271c0a1 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Tue, 25 Oct 2016 09:47:22 +0100 Subject: [PATCH 08/15] Remove track-changes-discount experiment --- .../web/public/coffee/main/account-upgrade.coffee | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/services/web/public/coffee/main/account-upgrade.coffee b/services/web/public/coffee/main/account-upgrade.coffee index bbbc4e9e12..7d72fe0c13 100644 --- a/services/web/public/coffee/main/account-upgrade.coffee +++ b/services/web/public/coffee/main/account-upgrade.coffee @@ -9,10 +9,9 @@ define [ event_tracking.sendMB "subscription-start-trial", { source, plan: $scope.startTrialPlanCode } w = window.open() - sixpack.convert "track-changes-discount", -> - ga?('send', 'event', 'subscription-funnel', 'upgraded-free-trial', source) - url = "/user/subscription/new?planCode=#{$scope.startTrialPlanCode}&ssp=true" - if couponCode? - url = "#{url}&cc=#{couponCode}" - $scope.startedFreeTrial = true - w.location = url + ga?('send', 'event', 'subscription-funnel', 'upgraded-free-trial', source) + url = "/user/subscription/new?planCode=#{$scope.startTrialPlanCode}&ssp=true" + if couponCode? + url = "#{url}&cc=#{couponCode}" + $scope.startedFreeTrial = true + w.location = url From e268275e77294fe4edcaa9a714f85e2d79c6fc07 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Tue, 25 Oct 2016 10:47:14 +0100 Subject: [PATCH 09/15] Fix participate/convert flow for plan tests --- .../successful_subscription.jade | 2 +- services/web/public/coffee/ide.coffee | 7 ------- .../public/coffee/main/account-upgrade.coffee | 20 ++++++++++++------- services/web/public/coffee/main/plans.coffee | 2 -- .../coffee/main/subscription-dashboard.coffee | 6 ++++++ 5 files changed, 20 insertions(+), 17 deletions(-) diff --git a/services/web/app/views/subscriptions/successful_subscription.jade b/services/web/app/views/subscriptions/successful_subscription.jade index 8413f5e036..17ac4f3594 100644 --- a/services/web/app/views/subscriptions/successful_subscription.jade +++ b/services/web/app/views/subscriptions/successful_subscription.jade @@ -2,7 +2,7 @@ extends ../layout block content .content.content-alt - .container + .container(ng-controller="SuccessfulSubscriptionController") .row .col-md-8.col-md-offset-2 .card(ng-cloak) diff --git a/services/web/public/coffee/ide.coffee b/services/web/public/coffee/ide.coffee index 4e7721badd..ac4240e114 100644 --- a/services/web/public/coffee/ide.coffee +++ b/services/web/public/coffee/ide.coffee @@ -68,22 +68,15 @@ define [ $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 $scope.chat = {} - # Only run the header AB test for newly registered users. _abTestStartDate = new Date(Date.UTC(2016, 8, 28)) _userSignUpDate = new Date(window.user.signUpDate) diff --git a/services/web/public/coffee/main/account-upgrade.coffee b/services/web/public/coffee/main/account-upgrade.coffee index 7d72fe0c13..0da68fddfb 100644 --- a/services/web/public/coffee/main/account-upgrade.coffee +++ b/services/web/public/coffee/main/account-upgrade.coffee @@ -6,12 +6,18 @@ define [ $scope.buttonClass = "btn-primary" $scope.startFreeTrial = (source, couponCode) -> - event_tracking.sendMB "subscription-start-trial", { source, plan: $scope.startTrialPlanCode } + plan = 'collaborator_free_trial_7_days' w = window.open() - ga?('send', 'event', 'subscription-funnel', 'upgraded-free-trial', source) - url = "/user/subscription/new?planCode=#{$scope.startTrialPlanCode}&ssp=true" - if couponCode? - url = "#{url}&cc=#{couponCode}" - $scope.startedFreeTrial = true - w.location = url + sixpack.participate 'plans-1610', ['default', 'heron', 'ibis'], (chosenVariation, rawResponse)-> + if $scope.shouldABTestPlans and chosenVariation in ['heron', 'ibis'] + plan = "collaborator_#{chosenVariation}" + + ga?('send', 'event', 'subscription-funnel', 'upgraded-free-trial', source) + url = "/user/subscription/new?planCode=#{plan}&ssp=true" + if couponCode? + url = "#{url}&cc=#{couponCode}" + + $scope.startedFreeTrial = true + event_tracking.sendMB "subscription-start-trial", { source, plan} + w.location = url diff --git a/services/web/public/coffee/main/plans.coffee b/services/web/public/coffee/main/plans.coffee index 2ea958b876..e08c495b29 100644 --- a/services/web/public/coffee/main/plans.coffee +++ b/services/web/public/coffee/main/plans.coffee @@ -340,8 +340,6 @@ define [ $scope.signUpNowClicked = (plan, annual)-> event_tracking.sendMB 'plans-page-start-trial', {plan} - if $scope.shouldABTestPlans and plan in ['student', 'collaborator'] - sixpack.convert 'plans-1610', () -> if $scope.ui.view == "annual" plan = "#{plan}_annual" event_tracking.send 'subscription-funnel', 'sign_up_now_button', plan diff --git a/services/web/public/coffee/main/subscription-dashboard.coffee b/services/web/public/coffee/main/subscription-dashboard.coffee index 22d68baea5..71bc198e6d 100644 --- a/services/web/public/coffee/main/subscription-dashboard.coffee +++ b/services/web/public/coffee/main/subscription-dashboard.coffee @@ -1,12 +1,18 @@ define [ "base" ], (App)-> + + App.controller 'SuccessfulSubscriptionController', ($scope, sixpack) -> + sixpack.convert 'plans-1610', () -> + + SUBSCRIPTION_URL = "/user/subscription/update" setupReturly = _.once -> recurly?.configure window.recurlyApiKey PRICES = {} + App.controller "CurrenyDropdownController", ($scope, MultiCurrencyPricing, $q)-> # $scope.plans = MultiCurrencyPricing.plans From ae2d030a32a755dd6e921fb571723983c65da498 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Tue, 25 Oct 2016 11:46:52 +0100 Subject: [PATCH 10/15] Don't call participate if should not test plans --- .../web/public/coffee/main/account-upgrade.coffee | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/services/web/public/coffee/main/account-upgrade.coffee b/services/web/public/coffee/main/account-upgrade.coffee index 0da68fddfb..f2c9ac21a0 100644 --- a/services/web/public/coffee/main/account-upgrade.coffee +++ b/services/web/public/coffee/main/account-upgrade.coffee @@ -9,15 +9,19 @@ define [ plan = 'collaborator_free_trial_7_days' w = window.open() - sixpack.participate 'plans-1610', ['default', 'heron', 'ibis'], (chosenVariation, rawResponse)-> - if $scope.shouldABTestPlans and chosenVariation in ['heron', 'ibis'] - plan = "collaborator_#{chosenVariation}" - + go = () -> ga?('send', 'event', 'subscription-funnel', 'upgraded-free-trial', source) url = "/user/subscription/new?planCode=#{plan}&ssp=true" if couponCode? url = "#{url}&cc=#{couponCode}" - $scope.startedFreeTrial = true event_tracking.sendMB "subscription-start-trial", { source, plan} w.location = url + + if $scope.shouldABTestPlans + sixpack.participate 'plans-1610', ['default', 'heron', 'ibis'], (chosenVariation, rawResponse)-> + if chosenVariation in ['heron', 'ibis'] + plan = "collaborator_#{chosenVariation}" + go() + else + go() From dfd13e0815b35725bd9259cfe172dd338b952c4b Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Wed, 26 Oct 2016 14:24:00 +0100 Subject: [PATCH 11/15] Update AB test timestamp --- .../coffee/Features/Subscription/SubscriptionController.coffee | 2 +- services/web/public/coffee/ide.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/services/web/app/coffee/Features/Subscription/SubscriptionController.coffee b/services/web/app/coffee/Features/Subscription/SubscriptionController.coffee index 47b9b4bc8e..0b9abbc91e 100644 --- a/services/web/app/coffee/Features/Subscription/SubscriptionController.coffee +++ b/services/web/app/coffee/Features/Subscription/SubscriptionController.coffee @@ -32,7 +32,7 @@ module.exports = SubscriptionController = baseUrl: baseUrl gaExperiments: Settings.gaExperiments.plansPage recomendedCurrency:recomendedCurrency - shouldABTestPlans: currentUser == null or (currentUser?.signUpDate? and currentUser.signUpDate >= (new Date('2011-10-18'))) + shouldABTestPlans: currentUser == null or (currentUser?.signUpDate? and currentUser.signUpDate >= (new Date('2016-10-26'))) user_id = AuthenticationController.getLoggedInUserId(req) if user_id? UserGetter.getUser user_id, {signUpDate: 1}, (err, user) -> diff --git a/services/web/public/coffee/ide.coffee b/services/web/public/coffee/ide.coffee index ac4240e114..85780dde29 100644 --- a/services/web/public/coffee/ide.coffee +++ b/services/web/public/coffee/ide.coffee @@ -69,7 +69,7 @@ define [ $scope.shouldABTestPlans = false - if $scope.user.signUpDate >= '2011-10-18' + if $scope.user.signUpDate >= '2016-10-26' $scope.shouldABTestPlans = true $scope.settings = window.userSettings From cb4380fa78c296cd3cb88e4b80d862559e097699 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Wed, 26 Oct 2016 12:01:49 +0100 Subject: [PATCH 12/15] fix problem with setting syntax validation option --- .../ide/editor/directives/aceEditor.coffee | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor.coffee index 87b525120f..0fdb806e83 100644 --- a/services/web/public/coffee/ide/editor/directives/aceEditor.coffee +++ b/services/web/public/coffee/ide/editor/directives/aceEditor.coffee @@ -15,9 +15,13 @@ define [ # set the path for ace workers if using a CDN (from editor.jade) if window.aceWorkerPath != "" + syntaxValidationEnabled = true ace.config.set('workerPath', "#{window.aceWorkerPath}") else - ace.config.setDefaultValue("session", "useWorker", false) + syntaxValidationEnabled = false + + # By default, don't use workers - enable them per-session as required + ace.config.setDefaultValue("session", "useWorker", false) # Ace loads its script itself, so we need to hook in to be able to clear # the cache. @@ -202,8 +206,12 @@ define [ editor.setReadOnly !!value scope.$watch "syntaxValidation", (value) -> - session = editor.getSession() - session.setOption("useWorker", value); + # ignore undefined settings here + # only instances of ace with an explicit value should set useWorker + # the history instance will have syntaxValidation undefined + if value? and syntaxValidationEnabled + session = editor.getSession() + session.setOption("useWorker", value); editor.setOption("scrollPastEnd", true) @@ -227,10 +235,16 @@ define [ catch mode = "ace/mode/text" - editor.setSession(new EditSession(lines, mode)) + # create our new session + session = new EditSession(lines, mode) - session = editor.getSession() session.setUseWrapMode(true) + # use syntax validation only when explicitly set + if scope.syntaxValidation? and syntaxValidationEnabled + session.setOption("useWorker", scope.syntaxValidation); + + # now attach session to editor + editor.setSession(session) doc = session.getDocument() doc.on "change", onChange From eab7d46fc5a93166fc3907115d73de58a88b4509 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Wed, 26 Oct 2016 15:15:18 +0100 Subject: [PATCH 13/15] update latex syntax validator (e4b016e) --- .../web/public/js/ace-1.2.5/mode-latex.js | 36 ++++++++++++++----- .../web/public/js/ace-1.2.5/worker-latex.js | 2 +- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/services/web/public/js/ace-1.2.5/mode-latex.js b/services/web/public/js/ace-1.2.5/mode-latex.js index c87324efe4..f183d7c263 100644 --- a/services/web/public/js/ace-1.2.5/mode-latex.js +++ b/services/web/public/js/ace-1.2.5/mode-latex.js @@ -214,18 +214,21 @@ var createLatexWorker = function (session) { var suppressions = []; var hints = []; var changeHandler = null; + var docChangePending = false; + var firstPass = true; var worker = new WorkerClient(["ace"], "ace/mode/latex_worker", "LatexWorker"); worker.attachToDocument(doc); - - doc.on("change", function () { + var docChangeHandler = doc.on("change", function () { + docChangePending = true; if(changeHandler) { clearTimeout(changeHandler); changeHandler = null; } }); - selection.on("changeCursor", function () { + var cursorHandler = selection.on("changeCursor", function () { + if (docChangePending) { return; } ; changeHandler = setTimeout(function () { updateMarkers({cursorMoveOnly:true}); suppressions = []; @@ -307,11 +310,20 @@ var createLatexWorker = function (session) { } } if (!cursorMoveOnly || suppressedChanges) { - session.setAnnotations(annotations); + if (firstPass) { + if (annotations.length > 0) { + var originalAnnotations = session.getAnnotations(); + session.setAnnotations(originalAnnotations.concat(annotations)); + }; + firstPass = false; + } else { + session.setAnnotations(annotations); + } }; }; worker.on("lint", function(results) { + if(docChangePending) { docChangePending = false; }; hints = results.data; if (hints.length > 100) { hints = hints.slice(0, 100); // limit to 100 errors @@ -319,14 +331,22 @@ var createLatexWorker = function (session) { updateMarkers(); }); worker.on("terminate", function() { + if(changeHandler) { + clearTimeout(changeHandler); + changeHandler = null; + } + doc.off("change", docChangeHandler); + selection.off("changeCursor", cursorHandler); for (var key in savedRange) { var range = savedRange[key]; - range.start.detach(); - range.end.detach(); + if (range.start !== cursorAnchor) { range.start.detach(); } + if (range.end !== cursorAnchor) { range.end.detach(); } session.removeMarker(range.id); - delete savedRange[key]; } - + savedRange = {}; + hints = []; + suppressions = []; + session.clearAnnotations(); }); return worker; diff --git a/services/web/public/js/ace-1.2.5/worker-latex.js b/services/web/public/js/ace-1.2.5/worker-latex.js index c933f8db5f..20c377dc83 100644 --- a/services/web/public/js/ace-1.2.5/worker-latex.js +++ b/services/web/public/js/ace-1.2.5/worker-latex.js @@ -1755,7 +1755,7 @@ var InterpretTokens = function (TokeniseResult, ErrorReporter) { }; if (endToken) { - TokenErrorFromTo(token, endToken, "invalid environment command" + text.substring(token[2], endToken[3] || endToken[2])); + TokenErrorFromTo(token, endToken, "invalid environment command " + text.substring(token[2], endToken[3] || endToken[2])); } else { TokenError(token, "invalid environment command"); }; From 1538f140f365b1f0bf672cee5be9785bc38e7492 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Thu, 27 Oct 2016 09:41:51 +0100 Subject: [PATCH 14/15] update test timestamp --- .../coffee/Features/Subscription/SubscriptionController.coffee | 2 +- services/web/public/coffee/ide.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/services/web/app/coffee/Features/Subscription/SubscriptionController.coffee b/services/web/app/coffee/Features/Subscription/SubscriptionController.coffee index 0b9abbc91e..51b3db8f56 100644 --- a/services/web/app/coffee/Features/Subscription/SubscriptionController.coffee +++ b/services/web/app/coffee/Features/Subscription/SubscriptionController.coffee @@ -32,7 +32,7 @@ module.exports = SubscriptionController = baseUrl: baseUrl gaExperiments: Settings.gaExperiments.plansPage recomendedCurrency:recomendedCurrency - shouldABTestPlans: currentUser == null or (currentUser?.signUpDate? and currentUser.signUpDate >= (new Date('2016-10-26'))) + shouldABTestPlans: currentUser == null or (currentUser?.signUpDate? and currentUser.signUpDate >= (new Date('2016-10-27'))) user_id = AuthenticationController.getLoggedInUserId(req) if user_id? UserGetter.getUser user_id, {signUpDate: 1}, (err, user) -> diff --git a/services/web/public/coffee/ide.coffee b/services/web/public/coffee/ide.coffee index 85780dde29..fd6c1440ce 100644 --- a/services/web/public/coffee/ide.coffee +++ b/services/web/public/coffee/ide.coffee @@ -69,7 +69,7 @@ define [ $scope.shouldABTestPlans = false - if $scope.user.signUpDate >= '2016-10-26' + if $scope.user.signUpDate >= '2016-10-27' $scope.shouldABTestPlans = true $scope.settings = window.userSettings From f396f5b09e2e4df720971c2b6184903d5311e7e0 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Thu, 27 Oct 2016 09:57:46 +0100 Subject: [PATCH 15/15] update prices in front-end --- services/web/public/coffee/main/plans.coffee | 36 ++++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/services/web/public/coffee/main/plans.coffee b/services/web/public/coffee/main/plans.coffee index e08c495b29..538152bf43 100644 --- a/services/web/public/coffee/main/plans.coffee +++ b/services/web/public/coffee/main/plans.coffee @@ -24,8 +24,8 @@ define [ monthly: "€5" annual: "€50" collaborator: - monthly: "€10" - annual: "€120" + monthly: "€11" + annual: "€132" GBP: student: monthly: "£5" @@ -59,22 +59,22 @@ define [ monthly: "40 kr" annual: "400 kr" collaborator: - monthly: "80 kr" - annual: "960 kr" + monthly: "70 kr" + annual: "840 kr" AUD: student: monthly: "$8" annual: "$80" collaborator: - monthly: "$16" - annual: "$192" + monthly: "$15" + annual: "$180" NZD: student: monthly: "$8" annual: "$80" collaborator: - monthly: "$16" - annual: "$192" + monthly: "$15" + annual: "$180" CHF: student: monthly: "Fr 6" @@ -103,15 +103,15 @@ define [ monthly: "€9" annual: "€90" collaborator: - monthly: "€16" - annual: "€192" + monthly: "€17" + annual: "€204" GBP: student: monthly: "£7" annual: "£70" collaborator: - monthly: "£13" - annual: "£156" + monthly: "£14" + annual: "£168" SEK: student: monthly: "75 kr" @@ -138,22 +138,22 @@ define [ monthly: "68 kr" annual: "680 kr" collaborator: - monthly: "122 kr" - annual: "1464 kr" + monthly: "110 kr" + annual: "1320 kr" AUD: student: monthly: "$13" annual: "$130" collaborator: - monthly: "$24" - annual: "$288" + monthly: "$22" + annual: "$264" NZD: student: monthly: "$14" annual: "$140" collaborator: - monthly: "$25" - annual: "$300" + monthly: "$22" + annual: "$264" CHF: student: monthly: "Fr 10"