Merge pull request #3203 from overleaf/hb-new-personal-plan

New personal plan

GitOrigin-RevId: bd96e86bef35b618f492625c3a9ea41328390374
This commit is contained in:
Hugh O'Brien 2020-10-13 13:32:57 +01:00 committed by Copybot
parent acd51e88c8
commit 8eab5a5f6f
8 changed files with 253 additions and 68 deletions

View file

@ -6,6 +6,7 @@ module.exports = [
value: 'str',
plans: {
free: '1',
personal: '1',
coll: '10',
prof: 'unlimited'
},
@ -17,6 +18,7 @@ module.exports = [
info: 'unlimited_private_info',
plans: {
free: true,
personal: true,
coll: true,
prof: true
},
@ -28,6 +30,7 @@ module.exports = [
info: 'realtime_collab_info',
plans: {
free: true,
personal: true,
coll: true,
prof: true
},
@ -39,6 +42,7 @@ module.exports = [
info: 'hundreds_templates_info',
plans: {
free: true,
personal: true,
coll: true,
prof: true
},
@ -50,39 +54,30 @@ module.exports = [
info: 'latex_editor_info',
plans: {
free: true,
personal: true,
coll: true,
prof: true
},
student: true
},
{
feature: 'compile_timeout',
value: 'str',
plans: {
free: '1 min',
personal: '4 mins',
coll: '4 mins',
prof: '4 mins'
},
student: '4 mins'
},
{
feature: 'realtime_track_changes',
value: 'bool',
info: 'realtime_track_changes_info',
plans: {
free: false,
coll: true,
prof: true
},
student: true
},
{
feature: 'reference_search',
value: 'bool',
info: 'reference_search_info',
plans: {
free: false,
coll: true,
prof: true
},
student: true
},
{
feature: 'reference_sync',
info: 'reference_sync_info',
value: 'bool',
plans: {
free: false,
personal: false,
coll: true,
prof: true
},
@ -94,6 +89,31 @@ module.exports = [
info: 'full_doc_history_info',
plans: {
free: false,
personal: true,
coll: true,
prof: true
},
student: true
},
{
feature: 'reference_search',
value: 'bool',
info: 'reference_search_info',
plans: {
free: false,
personal: true,
coll: true,
prof: true
},
student: true
},
{
feature: 'reference_sync',
info: 'reference_sync_info',
value: 'bool',
plans: {
free: false,
personal: true,
coll: true,
prof: true
},
@ -105,6 +125,7 @@ module.exports = [
info: 'dropbox_integration_info',
plans: {
free: false,
personal: true,
coll: true,
prof: true
},
@ -116,6 +137,7 @@ module.exports = [
info: 'github_integration_info',
plans: {
free: false,
personal: true,
coll: true,
prof: true
},
@ -126,6 +148,7 @@ module.exports = [
value: 'bool',
plans: {
free: false,
personal: true,
coll: true,
prof: true
},

View file

@ -6,6 +6,13 @@ mixin btn_buy_collaborator(location)
)
span(ng-show="ui.view != 'annual'") #{translate("start_free_trial")}
span(ng-show="ui.view == 'annual'") #{translate("buy_now")}
mixin btn_buy_personal(location)
a.btn.btn-primary(
ng-href="/user/subscription/new?planCode={{ getPersonalPlanCode() }}&currency={{currencyCode}}&itm_campaign=plans&itm_content=" + location,
ng-click="signUpNowClicked('personal','" + location + "')"
)
span(ng-show="ui.view != 'annual'") #{translate("start_free_trial")}
span(ng-show="ui.view == 'annual'") #{translate("buy_now")}
mixin btn_buy_free(location)
a.btn.btn-primary(
href="/register"
@ -74,6 +81,19 @@ mixin features_free(location)
li
br
+btn_buy_free(location)
mixin features_personal(location)
ul.list-unstyled
li #{translate("one_collaborator")}
li  
li
strong #{translate('premium_features')}
li #{translate('sync_dropbox_github')}
li #{translate('full_doc_history')}
li + #{translate('more').toLowerCase()}
li(class="hidden-xs hidden-sm")  
li
br
+btn_buy_personal(location)
mixin features_premium
li  
li
@ -100,6 +120,13 @@ mixin features_student(location, plan)
+btn_buy_student(location, plan)
//- Prices
mixin price_personal
span(ng-if="ui.view == 'monthly'")
| {{plans[currencyCode]['personal']['monthly']}}
span.small /mo
span(ng-if="ui.view == 'annual'")
| {{plans[currencyCode]['personal']['annual']}}
span.small /yr
mixin price_collaborator
span(ng-if="ui.view == 'monthly'")
| {{plans[currencyCode]['collaborator']['monthly']}}
@ -154,7 +181,7 @@ mixin plan_switch(location)
a.btn.btn-default-outline(
href="#"
ng-click="switchToStudent($event,'" + location + "')"
) #{translate("half_price_student")}
) #{translate("special_price_student")}
mixin allCardsAndControls(controlsRowSpaced, listLocation)
- var location = listLocation ? 'card_' + listLocation : 'card'
@ -173,8 +200,9 @@ mixin allCardsAndControls(controlsRowSpaced, listLocation)
.card-header
h2 #{translate("personal")}
h5.tagline #{translate("tagline_personal")}
.circle #{translate("free")}
+features_free(location)
.circle
+price_personal
+features_personal(location)
.col-md-4
.card.card-highlighted
.best-value
@ -198,8 +226,8 @@ mixin allCardsAndControls(controlsRowSpaced, listLocation)
.col-md-4
.card.card-first
.card-header
h2 #{translate("personal")}
h5.tagline #{translate("tagline_personal")}
h2 #{translate("free")}
h5.tagline #{translate("tagline_free")}
.circle #{translate("free")}
+features_free(location)
@ -209,4 +237,4 @@ mixin allCardsAndControls(controlsRowSpaced, listLocation)
.col-md-4
.card.card-last
+card_student_monthly(location)
+card_student_monthly(location)

View file

@ -1,9 +1,10 @@
//- Features Tables
mixin table_premium
table.card.plans-table
table.card.plans-table.plans-table-main
tr
th
th #{translate("free")}
th #{translate("personal")}
th #{translate("collaborator")}
.outer.outer-top
@ -15,6 +16,8 @@ mixin table_premium
tr
td #{translate("price")}
td #{translate("free")}
td
+price_personal
td
+price_collaborator
td
@ -42,6 +45,8 @@ mixin table_premium
td
td
+btn_buy_free('table')
td
+btn_buy_personal('table')
td
+btn_buy_collaborator('table')
.outer.outer-btm
@ -60,10 +65,10 @@ mixin table_cell_student(feature)
span.sr-only Feature not included
mixin table_student
table.card.plans-table
table.card.plans-table.plans-table-student
tr
th
th #{translate("personal")}
th #{translate("free")}
th #{translate("student")} (#{translate("annual")})
.outer.outer-top
.outer-content

View file

@ -18,4 +18,4 @@ mixin printPlan(plan)
mixin printPlans(plans)
each plan in plans
+printPlan(plan)
+printPlan(plan)

View file

@ -47,7 +47,7 @@ block content
div(ng-if="trialLength")
span !{translate("first_few_days_free", {trialLen:'{{trialLength}}'})}
span(ng-if="coupon.discountMonths && coupon.discountRate")   - {{coupon.discountMonths}} #{translate("month")}s {{coupon.discountRate}}% Off
div(ng-if="price")
- var priceAngularExp = "<strong>{{ availableCurrencies[currencyCode]['symbol'] }}{{ price.total }}</strong>";
span(ng-if="!coupon.singleUse && monthlyBilling")
@ -235,7 +235,7 @@ block content
- priceBreakdownAngularExp += " + " ;
- priceBreakdownAngularExp += "{{availableCurrencies[currencyCode]['symbol']}}{{ price.tax }} tax)";
hr.thin
span
span
| Total:
|
span(ng-if="!coupon.singleUse && monthlyBilling")
@ -283,7 +283,7 @@ block content
a.btn-primary.btn.plansPageStudentLink(
href,
ng-click="switchToStudent()"
) #{translate("half_price_student")}
) #{translate("special_price_student")}
.card.card-first
.paymentPageFeatures
@ -295,7 +295,10 @@ block content
- var collaboratorCount = 'Unlimited'
else
- var collaboratorCount = plan.features.collaborators
| #{translate("collabs_per_proj", {collabcount:collaboratorCount})}
if plan.features.collaborators == 1
| #{translate("collabs_per_proj_single", {collabcount:collaboratorCount})}
else
| #{translate("collabs_per_proj", {collabcount:collaboratorCount})}
p #{translate("work_on_single_version")}. #{translate("view_collab_edits")} in real time.
h3 #{translate("full_doc_history")}

View file

@ -38,6 +38,7 @@ block content
.row.row-spaced-large.text-centered
.col-xs-12
p.text-centered !{translate('also_provides_free_plan', { appName:'{{settings.appName}}', registerLinkOpen: '<a href="/register">', registerLinkClose: '</a>' })}
i.fa.fa-cc-mastercard.fa-2x(aria-hidden="true") &nbsp;
span.sr-only Mastercard accepted
i.fa.fa-cc-visa.fa-2x(aria-hidden="true") &nbsp;

View file

@ -16,6 +16,10 @@ App.factory('MultiCurrencyPricing', function() {
monthly: '$8',
annual: '$80'
},
personal: {
monthly: '$10',
annual: '$120'
},
collaborator: {
monthly: '$15',
annual: '$180'
@ -32,6 +36,10 @@ App.factory('MultiCurrencyPricing', function() {
monthly: '€7',
annual: '€70'
},
personal: {
monthly: '€9',
annual: '€108'
},
collaborator: {
monthly: '€14',
annual: '€168'
@ -48,6 +56,10 @@ App.factory('MultiCurrencyPricing', function() {
monthly: '£6',
annual: '£60'
},
personal: {
monthly: '£8',
annual: '£96'
},
collaborator: {
monthly: '£12',
annual: '£144'
@ -64,6 +76,10 @@ App.factory('MultiCurrencyPricing', function() {
monthly: '60 kr',
annual: '600 kr'
},
personal: {
monthly: '73 kr',
annual: '876 kr'
},
collaborator: {
monthly: '110 kr',
annual: '1320 kr'
@ -79,6 +95,10 @@ App.factory('MultiCurrencyPricing', function() {
monthly: '$9',
annual: '$90'
},
personal: {
monthly: '$11',
annual: '$132'
},
collaborator: {
monthly: '$17',
annual: '$204'
@ -95,6 +115,10 @@ App.factory('MultiCurrencyPricing', function() {
monthly: '60 kr',
annual: '600 kr'
},
personal: {
monthly: '73 kr',
annual: '876 kr'
},
collaborator: {
monthly: '110 kr',
annual: '1320 kr'
@ -111,6 +135,10 @@ App.factory('MultiCurrencyPricing', function() {
monthly: '50 kr',
annual: '500 kr'
},
personal: {
monthly: '60 kr',
annual: '720 kr'
},
collaborator: {
monthly: '90 kr',
annual: '1080 kr'
@ -127,6 +155,10 @@ App.factory('MultiCurrencyPricing', function() {
monthly: '$10',
annual: '$100'
},
personal: {
monthly: '$12',
annual: '$144'
},
collaborator: {
monthly: '$18',
annual: '$216'
@ -143,6 +175,10 @@ App.factory('MultiCurrencyPricing', function() {
monthly: '$10',
annual: '$100'
},
personal: {
monthly: '$12',
annual: '$144'
},
collaborator: {
monthly: '$18',
annual: '$216'
@ -159,6 +195,10 @@ App.factory('MultiCurrencyPricing', function() {
monthly: 'Fr 8',
annual: 'Fr 80'
},
personal: {
monthly: 'Fr 10',
annual: 'Fr 120'
},
collaborator: {
monthly: 'Fr 15',
annual: 'Fr 180'
@ -175,6 +215,10 @@ App.factory('MultiCurrencyPricing', function() {
monthly: '$12',
annual: '$120'
},
personal: {
monthly: '$13',
annual: '$156'
},
collaborator: {
monthly: '$20',
annual: '$240'
@ -224,6 +268,15 @@ App.controller('PlansController', function(
}
}
$scope.getPersonalPlanCode = function() {
const { view } = $scope.ui
if (view === 'annual') {
return 'paid-personal-annual'
} else {
return `paid-personal${$scope.planQueryString}`
}
}
$scope.signUpNowClicked = function(plan, location) {
if ($scope.ui.view === 'annual') {
plan = `${plan}_annual`

View file

@ -288,20 +288,6 @@
border-bottom: 0;
padding: 18px;
}
/* highlighted column */
td:nth-child(3) {
position: relative;
/* keep here position here, otherwise messes up border on safari when there is a bg color */
&:before {
/* needed for safafi */
border-top: 1px solid @border-color-base;
content: '';
left: 0;
position: absolute;
top: -1px;
width: 100%;
}
}
td:first-child {
border: 0;
}
@ -316,13 +302,6 @@
color: @gray-med;
}
/* highlighted column */
td:nth-child(3),
th:nth-child(3) {
background-color: white;
border-left: @border-width-base solid @border-color-base;
border-right: @border-width-base solid @border-color-base;
}
.outer {
left: -@border-width-base;
right: -@border-width-base;
@ -357,20 +336,22 @@
}
}
/* highlight rows on hover */
tr:hover {
td {
background-color: @table-hover-bg;
@media (min-width: @screen-sm-min) {
/* highlight rows on hover */
tr:hover {
td {
background-color: @table-hover-bg;
}
}
}
tr:first-child:hover {
background-color: transparent;
}
tr:last-child:hover {
background-color: transparent;
td {
tr:first-child:hover {
background-color: transparent;
}
tr:last-child:hover {
background-color: transparent;
td {
background-color: transparent;
}
}
}
/* tooltip */
@ -411,4 +392,95 @@
font-size: @font-size-small;
}
}
@media screen and (max-width: @screen-xs-max) {
tbody,
thead {
display: block;
}
tr {
display: flex;
flex-flow: row wrap;
justify-content: space-around;
}
th {
font-size: 12px;
}
/* hide the first column header */
tr:first-child {
th:first-child {
display: none;
}
}
/* make the first column into a row */
td:first-child {
text-align: center;
background: @gray-lightest;
width: 100%;
}
}
}
.plans-table-main {
td:nth-child(4),
th:nth-child(4) {
background-color: white;
border-left: @border-width-base solid @border-color-base;
border-right: @border-width-base solid @border-color-base;
}
tr:last-child {
/* highlighted column */
td:nth-child(4) {
position: relative;
/* keep here position here, otherwise messes up border on safari when there is a bg color */
&:before {
/* needed for safafi */
border-top: 1px solid @border-color-base;
content: '';
left: 0;
position: absolute;
top: -1px;
width: 100%;
}
}
}
@media screen and (max-width: @screen-xs-max) {
td,
th {
display: block;
width: 25%;
}
}
}
.plans-table-student {
td:nth-child(3),
th:nth-child(3) {
background-color: white;
border-left: @border-width-base solid @border-color-base;
border-right: @border-width-base solid @border-color-base;
}
tr:last-child {
/* highlighted column */
td:nth-child(3) {
position: relative;
/* keep here position here, otherwise messes up border on safari when there is a bg color */
&:before {
/* needed for safafi */
border-top: 1px solid @border-color-base;
content: '';
left: 0;
position: absolute;
top: -1px;
width: 100%;
}
}
}
@media screen and (max-width: @screen-xs-max) {
td,
th {
display: block;
width: 33.3%;
}
}
}