mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Let users upgrade to group plans via subscription dashboard (#4704)
Users on an individual plan don't have a way to upgrade to a group subscription without contacting support. As a temporary measure, we're adding a way to do this by re-using the existing group plan modal from the plans pages, to allow users to configure and upgrade to a group plan directly. This is currently only available for USD, EUR, and GBP - since although we now support other currencies in Recurly, the group plans modal does not yet support them. The user however can not change currency here, their group subscription will be in the same currency as their current individual subscription. The group plan modal has been duplicated rather than extended, to keep this code seperate as it is potentially only a stopgap measure - and we don't want to be untangling the additional logic from the existing modal/template later down the line. GitOrigin-RevId: f310eb10ef00d43076981589ee45893e7d9ab881
This commit is contained in:
parent
c6da905e5b
commit
5f550b0a11
6 changed files with 189 additions and 1 deletions
|
@ -121,6 +121,7 @@ async function userSubscriptionPage(req, res) {
|
|||
const data = {
|
||||
title: 'your_subscription',
|
||||
plans,
|
||||
groupPlans: GroupPlansData,
|
||||
user,
|
||||
hasSubscription,
|
||||
fromPlansPage,
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
script(type="text/ng-template", id="groupPlanModalUpgradeTemplate")
|
||||
.modal-header
|
||||
h3 Save 30% or more with a group license
|
||||
.modal-body.plans
|
||||
.container-fluid
|
||||
.row
|
||||
.col-md-6.text-center
|
||||
.circle.circle-lg
|
||||
| {{ displayPrice }}
|
||||
span.small / year
|
||||
br
|
||||
span.circle-subtext For {{ selected.size }} users
|
||||
ul.list-unstyled
|
||||
li Each user will have access to:
|
||||
li
|
||||
li(ng-if="selected.plan_code == 'collaborator'")
|
||||
strong #{translate("collabs_per_proj", {collabcount:10})}
|
||||
li(ng-if="selected.plan_code == 'professional'")
|
||||
strong #{translate("unlimited_collabs")}
|
||||
+features_premium
|
||||
.col-md-6
|
||||
form.form
|
||||
.form-group
|
||||
label(for='plan_code')
|
||||
| Plan
|
||||
select.form-control(id="plan_code", ng-model="selected.plan_code")
|
||||
option(ng-repeat="plan_code in options.plan_codes", value="{{plan_code.code}}") {{ plan_code.display }}
|
||||
.form-group
|
||||
label(for='size')
|
||||
| Number of users
|
||||
select.form-control(id="size", ng-model="selected.size")
|
||||
option(ng-repeat="size in options.sizes", value="{{size}}") {{ size }}
|
||||
.form-group
|
||||
label(for='currency')
|
||||
| Currency
|
||||
select.form-control(disabled id="currency", ng-model="selected.currency")
|
||||
option(ng-repeat="currency in options.currencies", value="{{currency.code}}") {{ currency.display }}
|
||||
.form-group
|
||||
label(for='usage')
|
||||
| Usage
|
||||
select.form-control(id="usage", ng-model="selected.usage")
|
||||
option(ng-repeat="usage in options.usages", value="{{usage.code}}") {{ usage.display }}
|
||||
p.small.text-center.row-spaced-small(ng-show="selected.usage == 'educational'")
|
||||
| The 40% educational discount can be used by students or faculty using Overleaf for teaching
|
||||
p.small.text-center.row-spaced-small(ng-show="selected.usage == 'enterprise'")
|
||||
| Save an additional 40% on groups of 10 or more with our educational discount
|
||||
.modal-footer
|
||||
.text-center
|
||||
p
|
||||
strong Your new subscription will be billed immediately to your current payment method.
|
||||
hr.thin
|
||||
button.btn.btn-primary.btn-lg(ng-disabled='inflight' ng-click="upgrade()") Upgrade Now
|
||||
hr.thin
|
||||
a(
|
||||
href
|
||||
ng-controller="ContactGeneralModal"
|
||||
ng-click="openModal()"
|
||||
) Need more than 50 licenses? Please get in touch
|
||||
|
|
@ -12,6 +12,7 @@ block append meta
|
|||
meta(name="ol-recurlyApiKey" content=settings.apis.recurly.publicKey)
|
||||
meta(name="ol-subscription" data-type="json" content=personalSubscription)
|
||||
meta(name="ol-recomendedCurrency" content=personalSubscription.recurly.currency)
|
||||
meta(name="ol-groupPlans" data-type="json" content=groupPlans)
|
||||
|
||||
block content
|
||||
main.content.content-alt#main-content(ng-cloak)
|
||||
|
|
|
@ -21,6 +21,8 @@ div(ng-controller="RecurlySubscriptionController")
|
|||
a(href, ng-click="switchToChangePlanView()", ng-if="showChangePlanButton") !{translate("change_plan")}.
|
||||
if (personalSubscription.pendingPlan)
|
||||
p #{translate("want_change_to_apply_before_plan_end")}
|
||||
else if (personalSubscription.plan.groupPlan)
|
||||
p #{translate("contact_support_to_change_group_subscription")}
|
||||
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>
|
||||
p !{translate("next_payment_of_x_collectected_on_y", {paymentAmmount: personalSubscription.recurly.price, collectionDate: personalSubscription.recurly.nextPaymentDueAt}, ['strong', 'strong'])}
|
||||
|
@ -64,6 +66,19 @@ div(ng-controller="RecurlySubscriptionController")
|
|||
+printPlans(plans.individualMonthlyPlans)
|
||||
+printPlans(plans.individualAnnualPlans)
|
||||
|
||||
div(ng-controller="ChangePlanToGroupFormController")
|
||||
h2 #{translate('looking_multiple_licenses')}
|
||||
div(ng-show="isValidCurrencyForUpgrade")
|
||||
span #{translate('reduce_costs_group_licenses')}
|
||||
br
|
||||
br
|
||||
a.btn.btn-success(
|
||||
href="#groups"
|
||||
ng-click="openGroupPlanModal()"
|
||||
) #{translate('change_to_group_plan')}
|
||||
div(ng-hide="isValidCurrencyForUpgrade")
|
||||
span #{translate('contact_support_to_upgrade_to_group_subscription')}
|
||||
|
||||
|
||||
.div(ng-controller="RecurlyCancellationController", ng-show="showCancellation").text-center
|
||||
p
|
||||
|
@ -130,3 +145,6 @@ script(type='text/ng-template', id='cancelPendingPlanChangeModalTemplate')
|
|||
)
|
||||
span(ng-hide="inflight") #{translate("revert_pending_plan_change")}
|
||||
span(ng-show="inflight") #{translate("processing")}…
|
||||
|
||||
include ../_plans_page_mixins
|
||||
include ../_modal_group_upgrade
|
|
@ -91,6 +91,112 @@ App.factory('RecurlyPricing', function ($q, MultiCurrencyPricing) {
|
|||
}
|
||||
})
|
||||
|
||||
App.controller('ChangePlanToGroupFormController', function ($scope, $modal) {
|
||||
if (!ensureRecurlyIsSetup()) return
|
||||
|
||||
const subscription = getMeta('ol-subscription')
|
||||
const currency = subscription.recurly.currency
|
||||
|
||||
if (['USD', 'GBP', 'EUR'].includes(currency)) {
|
||||
$scope.isValidCurrencyForUpgrade = true
|
||||
}
|
||||
|
||||
$scope.openGroupPlanModal = function () {
|
||||
const planCode = subscription.plan.planCode
|
||||
$scope.defaultGroupPlan = planCode.includes('professional')
|
||||
? 'professional'
|
||||
: 'collaborator'
|
||||
$scope.currentPlanCurrency = currency
|
||||
$modal.open({
|
||||
templateUrl: 'groupPlanModalUpgradeTemplate',
|
||||
controller: 'GroupPlansModalUpgradeController',
|
||||
scope: $scope,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
App.controller(
|
||||
'GroupPlansModalUpgradeController',
|
||||
function ($scope, $modal, $location, $http) {
|
||||
$scope.options = {
|
||||
plan_codes: [
|
||||
{
|
||||
display: 'Collaborator',
|
||||
code: 'collaborator',
|
||||
},
|
||||
{
|
||||
display: 'Professional',
|
||||
code: 'professional',
|
||||
},
|
||||
],
|
||||
currencies: [
|
||||
{
|
||||
display: 'USD ($)',
|
||||
code: 'USD',
|
||||
},
|
||||
{
|
||||
display: 'GBP (£)',
|
||||
code: 'GBP',
|
||||
},
|
||||
{
|
||||
display: 'EUR (€)',
|
||||
code: 'EUR',
|
||||
},
|
||||
],
|
||||
currencySymbols: {
|
||||
USD: '$',
|
||||
EUR: '€',
|
||||
GBP: '£',
|
||||
},
|
||||
sizes: [2, 3, 4, 5, 10, 20, 50],
|
||||
usages: [
|
||||
{
|
||||
display: 'Enterprise',
|
||||
code: 'enterprise',
|
||||
},
|
||||
{
|
||||
display: 'Educational',
|
||||
code: 'educational',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
$scope.prices = getMeta('ol-groupPlans')
|
||||
|
||||
const currency = $scope.currentPlanCurrency
|
||||
|
||||
// default selected
|
||||
$scope.selected = {
|
||||
plan_code: $scope.defaultGroupPlan || 'collaborator',
|
||||
currency,
|
||||
size: '10',
|
||||
usage: 'enterprise',
|
||||
}
|
||||
|
||||
$scope.recalculatePrice = function () {
|
||||
const { usage, plan_code, currency, size } = $scope.selected
|
||||
const price = $scope.prices[usage][plan_code][currency][size]
|
||||
const currencySymbol = $scope.options.currencySymbols[currency]
|
||||
$scope.displayPrice = `${currencySymbol}${price}`
|
||||
}
|
||||
|
||||
$scope.$watch('selected', $scope.recalculatePrice, true)
|
||||
$scope.recalculatePrice()
|
||||
|
||||
$scope.upgrade = function () {
|
||||
const { plan_code, size, usage } = $scope.selected
|
||||
const body = {
|
||||
_csrf: window.csrfToken,
|
||||
plan_code: `group_${plan_code}_${size}_${usage}`,
|
||||
}
|
||||
$scope.inflight = true
|
||||
$http
|
||||
.post(`/user/subscription/update`, body)
|
||||
.then(() => location.reload())
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
App.controller(
|
||||
'ChangePlanFormController',
|
||||
function ($scope, $modal, RecurlyPricing) {
|
||||
|
|
|
@ -1045,7 +1045,10 @@
|
|||
"currently_subscribed_to_plan": "You are currently subscribed to the <0>__planName__</0> plan.",
|
||||
"your_plan_is_changing_at_term_end": "Your plan is changing to <0>__pendingPlanName__</0> at the end of the current billing period.",
|
||||
"want_change_to_apply_before_plan_end": "If you wish this change to apply before the end of your current billing period, please contact us.",
|
||||
"contact_support_to_change_group_subscription": "Please contact support if you wish to change your group subscription.",
|
||||
"contact_support_to_upgrade_to_group_subscription": "Please contact support if you wish to be upgraded to a group subscription.",
|
||||
"change_plan": "Change plan",
|
||||
"change_to_group_plan": "Change to a group plan",
|
||||
"next_payment_of_x_collectected_on_y": "The next payment of <0>__paymentAmmount__</0> will be collected on <1>__collectionDate__</1>.",
|
||||
"additional_licenses": "Your subscription includes <0>__additionalLicenses__</0> additional license(s) for a total of <1>__totalLicenses__</1> licenses.",
|
||||
"pending_additional_licenses": "Your subscription is changing to include <0>__pendingAdditionalLicenses__</0> additional license(s) for a total of <1>__pendingTotalLicenses__</1> licenses.",
|
||||
|
|
Loading…
Reference in a new issue