Merge pull request #2015 from overleaf/ta-recurly-upgrade

Upgrade Recurly

GitOrigin-RevId: 9a7c4804d2fafa31ea634498359dbfd95416b2ae
This commit is contained in:
Timothée Alby 2019-07-31 10:23:13 +02:00 committed by sharelatex
parent 018b2cc474
commit b9ab0edf69
12 changed files with 102 additions and 70 deletions

View file

@ -415,7 +415,8 @@ module.exports = RecurlyWrapper = {
'base64'
)}`,
Accept: 'application/xml',
'Content-Type': 'application/xml; charset=utf-8'
'Content-Type': 'application/xml; charset=utf-8',
'X-Api-Version': Settings.apis.recurly.apiVersion
}
const { expect404 } = options
delete options.expect404

View file

@ -117,29 +117,33 @@ html(
include scribtex-modal
block requirejs
script(type='text/javascript').
// minimal requirejs configuration (can be extended/overridden)
window.requirejs = {
"paths" : {
"moment": "libs/#{lib('moment')}",
"fineuploader": "libs/#{lib('fineuploader')}",
"main": "#{buildJsPath('main.js', {hashedPath:settings.useMinifiedJs, removeExtension:true})}",
"libraries": "#{buildJsPath('libraries.js', {hashedPath:settings.useMinifiedJs, removeExtension:true})}",
},
"config":{
"moment":{
"noGlobal": true
block requirejs-config
script(type='text/javascript').
// minimal requirejs configuration (can be extended/overridden)
window.requirejs = {
"paths" : {
"moment": "libs/#{lib('moment')}",
"fineuploader": "libs/#{lib('fineuploader')}",
"main": "#{buildJsPath('main.js', {hashedPath:settings.useMinifiedJs, removeExtension:true})}",
"libraries": "#{buildJsPath('libraries.js', {hashedPath:settings.useMinifiedJs, removeExtension:true})}",
"recurly": "https://js.recurly.com/v4/recurly.js"
},
"config":{
"moment":{
"noGlobal": true
}
}
}
};
script(
data-main=buildJsPath('main.js', {hashedPath:false}),
baseurl=fullJsPath,
src=buildJsPath('libs/require.js', {hashedPath:true})
)
};
block requirejs-init
script(
data-main=buildJsPath('main.js', {hashedPath:false}),
baseurl=fullJsPath,
src=buildJsPath('libs/require.js', {hashedPath:true})
)
!= moduleIncludes("contactModal", locals)
include v1-tooltip
include sentry

View file

@ -2,6 +2,13 @@ extends ../layout
include ./dashboard/_team_name_mixin
block requirejs-init
script(
data-main=buildJsPath("main-recurly.js", {hashedPath:false}),
baseurl=fullJsPath,
src=buildJsPath('libs/require.js', {hashedPath:true})
)
block content
.content.content-alt(ng-cloak)
.container
@ -12,7 +19,7 @@ block content
p You already have a subscription
.card
.page-header
h1 #{translate("your_subscription")}
h1 #{translate("your_subscription")}
-var hasDisplayedSubscription = false
-if (personalSubscription)

View file

@ -1,4 +1,3 @@
script(src="https://js.recurly.com/v3/recurly.js")
script(type='text/javascript').
window.recurlyApiKey = "!{settings.apis.recurly.publicKey}"
window.subscription = !{StringHelper.stringifyJsonForScript(personalSubscription)}
@ -8,7 +7,7 @@ div(ng-controller="RecurlySubscriptionController")
div(ng-show="!showCancellation")
case personalSubscription.recurly.state
when "active"
p !{translate("currently_subscribed_to_plan", {planName:"<strong>" + personalSubscription.plan.name + "</strong>"})}
p !{translate("currently_subscribed_to_plan", {planName:"<strong>" + personalSubscription.plan.name + "</strong>"})}
a(href, ng-click="switchToChangePlanView()", ng-if="showChangePlanButton") !{translate("change_plan")}.
-if (personalSubscription.recurly.trialEndsAtFormatted && personalSubscription.recurly.trial_ends_at > Date.now())
p You're on a free trial which ends on <strong ng-non-bindable>#{personalSubscription.recurly.trialEndsAtFormatted}</strong>
@ -18,7 +17,7 @@ div(ng-controller="RecurlySubscriptionController")
p
a(href=personalSubscription.recurly.billingDetailsLink, target="_blank").btn.btn-info #{translate("update_your_billing_details")}
| &nbsp;
a(href, ng-click="switchToCancellationView()").btn.btn-primary !{translate("cancel_your_subscription")}
a(href, ng-click="switchToCancellationView()", ng-hide="recurlyLoadError").btn.btn-primary !{translate("cancel_your_subscription")}
when "canceled"
p !{translate("currently_subscribed_to_plan", {planName:"<strong>" + personalSubscription.plan.name + "</strong>"})}
p !{translate("subscription_canceled_and_terminate_on_x", {terminateDate:"<strong>" + personalSubscription.recurly.nextPaymentDueAt + "</strong>"})}
@ -26,11 +25,14 @@ div(ng-controller="RecurlySubscriptionController")
input(type="hidden", name="_csrf", value=csrfToken)
input(type="submit",value="Reactivate your subscription").btn.btn-success
when "expired"
p !{translate("your_subscription_has_expired")}
p !{translate("your_subscription_has_expired")}
a(href="/user/subscription/plans") !{translate("create_new_subscription")}
default
p !{translate("problem_with_subscription_contact_us")}
.alert.alert-warning(ng-show="recurlyLoadError")
strong #{translate('payment_provider_unreachable_error')}
include ./_change_plans_mixins
div(ng-show="showChangePlan", ng-cloak)
h2 !{translate("change_plan")}

View file

@ -1,5 +1,12 @@
extends ../layout
block requirejs-init
script(
data-main=buildJsPath("main-recurly.js", {hashedPath:false}),
baseurl=fullJsPath,
src=buildJsPath('libs/require.js', {hashedPath:true})
)
block scripts
script(type='text/javascript').
window.countryCode = '#{countryCode}'
@ -15,7 +22,9 @@ block content
.row.card-group
.col-md-5.col-md-push-4
.card.card-highlighted.card-border
.page-header
.alert.alert-danger(ng-show="recurlyLoadError")
strong #{translate('payment_provider_unreachable_error')}
.page-header(ng-hide="recurlyLoadError")
.row
.col-xs-9
h2 {{planName}}
@ -26,13 +35,13 @@ block content
data-toggle="dropdown",
dropdown-toggle
)
| {{currencyCode}} ({{allCurrencies[currencyCode]['symbol']}})
| {{currencyCode}} ({{allCurrencies[currencyCode]['symbol']}})
span.caret
ul.dropdown-menu(role="menu")
li(ng-repeat="(currency, value) in availableCurrencies")
a(
ng-click="changeCurrency(currency)",
) {{currency}} ({{value['symbol']}})
) {{currency}} ({{value['symbol']}})
.row(ng-if="planCode == 'student-annual' || planCode == 'student-monthly' || planCode == 'student_free_trial_7_days'")
.col-xs-12
p.student-disclaimer #{translate('student_disclaimer')}
@ -40,16 +49,16 @@ block content
hr.thin
.row
.col-md-12.text-center
div(ng-if="trialLength")
div(ng-if="trialLength")
span !{translate("first_few_days_free", {trialLen:'{{trialLength}}'})}
span(ng-if="discountMonths && discountRate") &nbsp; - {{discountMonths}} #{translate("month")}s {{discountRate}}% Off
div(ng-if="price")
strong {{availableCurrencies[currencyCode]['symbol']}}{{price.next.total}}
strong {{availableCurrencies[currencyCode]['symbol']}}{{price.next.total}}
span(ng-if="monthlyBilling") #{translate("every")} #{translate("month")}
span(ng-if="!monthlyBilling") #{translate("every")} #{translate("year")}
div(ng-if="normalPrice")
span.small Normally {{availableCurrencies[currencyCode]['symbol']}}{{normalPrice}}
.row
.row(ng-hide="recurlyLoadError")
div()
.col-md-12()
form(
@ -57,7 +66,7 @@ block content
novalidate
)
div.payment-method-toggle
a.payment-method-toggle-switch(
href
@ -77,7 +86,7 @@ block content
)
i.fa.fa-cc-paypal.fa-2x(aria-hidden="true")
span.sr-only Pay with PayPal
.alert.alert-warning.small(ng-show="genericError")
strong {{genericError}}
@ -132,7 +141,7 @@ block content
name="year"
data-recurly="year"
)
.col-xs-6
.form-group.has-feedback(ng-class="validation.errorFields.cvv ? 'has-external-error' : ''")
label #{translate("security_code")}
@ -184,14 +193,14 @@ block content
ng-blur="applyCoupon()"
ng-model="data.coupon"
)
p(ng-if="paymentMethod.value === 'paypal'") #{translate("paypal_upgrade")}
div.price-breakdown(ng-if="price.next.tax !== '0.00'")
hr.thin
span Total:
strong {{availableCurrencies[currencyCode]['symbol']}}{{price.next.total}}
span ({{availableCurrencies[currencyCode]['symbol']}}{{price.next.subtotal}} + {{availableCurrencies[currencyCode]['symbol']}}{{price.next.tax}} tax)
span Total:
strong {{availableCurrencies[currencyCode]['symbol']}}{{price.next.total}}
span ({{availableCurrencies[currencyCode]['symbol']}}{{price.next.subtotal}} + {{availableCurrencies[currencyCode]['symbol']}}{{price.next.tax}} tax)
span(ng-if="monthlyBilling") #{translate("every")} #{translate("month")}
span(ng-if="!monthlyBilling") #{translate("every")} #{translate("year")}
hr.thin
@ -199,9 +208,9 @@ block content
div.payment-submit
button.btn.btn-success.btn-block(
ng-click="submit()"
ng-disabled="processing || !isFormValid(simpleCCForm);"
)
span(ng-show="processing")
ng-disabled="processing || !isFormValid(simpleCCForm);"
)
span(ng-show="processing")
i.fa.fa-spinner.fa-spin(aria-hidden="true")
span.sr-only #{translate('processing')}
| &nbsp;
@ -215,13 +224,13 @@ block content
a.btn-primary.btn.plansPageStudentLink(
href,
ng-click="switchToStudent()"
) #{translate("half_price_student")}
) #{translate("half_price_student")}
.card.card-first
.paymentPageFeatures
h3 #{translate("unlimited_projects")}
p #{translate("create_unlimited_projects")}
h3
if plan.features.collaborators == -1
- var collaboratorCount = 'Unlimited'
@ -229,21 +238,21 @@ block content
- var collaboratorCount = plan.features.collaborators
| #{translate("collabs_per_proj", {collabcount:collaboratorCount})}
p #{translate("work_on_single_version")}. #{translate("view_collab_edits")} in real time.
h3 #{translate("full_doc_history")}
p #{translate("see_what_has_been")}
span.added #{translate("added")}
| #{translate("and")}
span.removed #{translate("removed")}.
p #{translate("see_what_has_been")}
span.added #{translate("added")}
| #{translate("and")}
span.removed #{translate("removed")}.
| #{translate("restore_to_any_older_version")}.
h3 #{translate("sync_to_dropbox")}
p
| #{translate("acces_work_from_anywhere")}.
| #{translate("acces_work_from_anywhere")}.
| #{translate("work_offline_and_sync_with_dropbox")}.
hr
p.small.text-center(ng-non-bindable) We're confident that you'll love #{settings.appName}, but if not you can cancel anytime. We'll give you your money back, no questions asked, if you let us know within 30 days.

View file

@ -136,6 +136,7 @@ module.exports = settings =
url: "http://#{process.env['GITHUB_SYNC_HOST'] or 'localhost'}:3022"
recurly:
apiKey: process.env['RECURLY_API_KEY'] or ''
apiVersion: process.env['RECURLY_API_VERSION']
subdomain: process.env['RECURLY_SUBDOMAIN'] or ''
publicKey: process.env['RECURLY_PUBLIC_KEY'] or ''
geoIpLookup:

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,8 @@
// main bundle plus recurly (loaded externaly from CDN) and all files requiring
// Recurly JS
define([
'main',
'recurly',
'main/subscription-dashboard',
'main/new-subscription'
], function() {})

View file

@ -22,8 +22,6 @@ define([
'main/bonus',
'main/system-messages',
'main/translations',
'main/subscription-dashboard',
'main/new-subscription',
'main/annual-upgrade',
'main/announcements',
'main/register-users',

View file

@ -4,7 +4,7 @@
no-return-assign
*/
/* global recurly,_,define */
define(['base', 'directives/creditCards', 'libs/recurly-4.8.5'], App =>
define(['base', 'directives/creditCards'], App =>
App.controller('NewSubscriptionController', function(
$scope,
MultiCurrencyPricing,
@ -12,10 +12,12 @@ define(['base', 'directives/creditCards', 'libs/recurly-4.8.5'], App =>
event_tracking,
ccUtils
) {
if (typeof recurly === 'undefined') {
throw new Error('Recurly API Library Missing.')
if (typeof recurly === 'undefined' || !recurly) {
$scope.recurlyLoadError = true
return
}
$scope.recurlyLoadError = false
$scope.currencyCode = MultiCurrencyPricing.currencyCode
$scope.allCurrencies = MultiCurrencyPricing.plans
$scope.availableCurrencies = {}

View file

@ -3,7 +3,7 @@
max-len
*/
/* global define,history */
define(['base', 'libs/recurly-4.8.5'], function(App, recurly) {
define(['base'], function(App) {
App.factory('MultiCurrencyPricing', function() {
const currencyCode = window.recomendedCurrency

View file

@ -19,8 +19,11 @@ define(['base'], function(App) {
const SUBSCRIPTION_URL = '/user/subscription/update'
const ensureRecurlyIsSetup = _.once(() => {
if (!recurly) return
if (typeof recurly === 'undefined' || !recurly) {
return false
}
recurly.configure(window.recurlyApiKey)
return true
})
App.controller('MetricsEmailController', function($scope, $http) {
@ -60,7 +63,7 @@ define(['base'], function(App) {
App.factory('RecurlyPricing', function($q, MultiCurrencyPricing) {
return {
loadDisplayPriceWithTax: function(planCode, currency, taxRate) {
ensureRecurlyIsSetup()
if (!ensureRecurlyIsSetup()) return
const currencySymbol = MultiCurrencyPricing.plans[currency].symbol
const pricing = recurly.Pricing()
return $q(function(resolve, reject) {
@ -89,7 +92,7 @@ define(['base'], function(App) {
$modal,
RecurlyPricing
) {
ensureRecurlyIsSetup()
if (!ensureRecurlyIsSetup()) return
$scope.changePlan = () =>
$modal.open({
@ -164,7 +167,9 @@ define(['base'], function(App) {
})
App.controller('RecurlySubscriptionController', function($scope) {
$scope.showChangePlanButton = !subscription.groupPlan
const recurlyIsSetup = ensureRecurlyIsSetup()
$scope.showChangePlanButton = recurlyIsSetup && !subscription.groupPlan
$scope.recurlyLoadError = !recurlyIsSetup
$scope.switchToDefaultView = () => {
$scope.showCancellation = false
@ -188,6 +193,7 @@ define(['base'], function(App) {
RecurlyPricing,
$http
) {
if (!ensureRecurlyIsSetup()) return
const subscription = window.subscription
const sevenDaysTime = new Date()
sevenDaysTime.setDate(sevenDaysTime.getDate() + 7)