[web] Extract reusable table mixin on plans page v2 tables (#8262)

GitOrigin-RevId: 7d8dcff5fd3f0c450de6cca57b428759d44dec7d
This commit is contained in:
M Fahru 2022-06-03 04:06:43 -04:00 committed by Copybot
parent 4f127f8408
commit b12c108522
5 changed files with 284 additions and 324 deletions

View file

@ -9,7 +9,7 @@ const logger = require('@overleaf/logger')
const GeoIpLookup = require('../../infrastructure/GeoIpLookup')
const FeaturesUpdater = require('./FeaturesUpdater')
const planFeatures = require('./planFeatures')
const planFeaturesV2 = require('./planFeaturesV2')
const plansV2Config = require('./plansV2Config')
const GroupPlansData = require('./GroupPlansData')
const V1SubscriptionManager = require('./V1SubscriptionManager')
const Errors = require('../Errors/Errors')
@ -89,7 +89,8 @@ async function plansPage(req, res) {
plans,
itm_content: req.query && req.query.itm_content,
recommendedCurrency,
planFeatures: newPlansPageVariantV2 ? planFeaturesV2 : planFeatures,
planFeatures,
plansV2Config,
groupPlans: GroupPlansData,
groupPlanModalOptions,
groupPlanModalDefaults,

View file

@ -0,0 +1,47 @@
const plansV2Features = require('./plansV2Features')
const config = {
individual: {
tableHead: [
'individual_free',
'individual_personal',
'individual_collaborator',
'individual_professional',
],
features: plansV2Features.individual,
highlightedColumn: {
index: 2,
text: {
monthly: 'MOST POPULAR',
annual: 'MOST POPULAR',
},
},
},
group: {
tableHead: [
'group_collaborator',
'group_professional',
'group_organization',
],
features: plansV2Features.group,
highlightedColumn: {
index: 1,
text: {
annual: 'RECOMMENDED',
},
},
},
student: {
tableHead: ['student_free', 'student_student', 'student_university'],
features: plansV2Features.student,
highlightedColumn: {
index: 1,
text: {
monthly: 'SAVE 20% ON ANNUAL PLAN',
annual: 'SAVING 20%',
},
},
},
}
module.exports = config

View file

@ -1,63 +1,44 @@
mixin table_individual(period)
table.card.plans-v2-table.plans-v2-table-individual
mixin plans_v2_table(period, config)
tr
th
th
div.plans-v2-table-th-content
p.plans-v2-table-th-content-title #{translate("free")}
+table_head_price('free', period)
.plans-v2-table-btn-buy-container-mobile
+btn_buy_individual_free()
ul.plans-v2-table-th-content-benefit
li #{translate("one_collaborator")}
.plans-v2-table-btn-buy-container-desktop
+btn_buy_individual_free()
th.plans-v2-table-cell-before-highlighted-column
div.plans-v2-table-th-content
p.plans-v2-table-th-content-title #{translate("personal")}
+table_head_price('personal', period)
.plans-v2-table-btn-buy-container-mobile
+btn_buy_individual_personal(period)
ul.plans-v2-table-th-content-benefit
li #{translate("one_collaborator")}
li #{translate("most_premium_features")}
.plans-v2-table-btn-buy-container-desktop
+btn_buy_individual_personal(period)
th.plans-v2-table-green-highlighted
div.plans-v2-table-th-content
p.plans-v2-table-green-highlighted-text MOST POPULAR
p.plans-v2-table-th-content-title #{translate("standard")}
+table_head_price('collaborator', period)
.plans-v2-table-btn-buy-container-mobile
+btn_buy_individual_collaborator(period)
ul.plans-v2-table-th-content-benefit
li !{translate("x_collaborators_per_project", {collaboratorsCount: '10'})}
li #{translate("all_premium_features")}
.plans-v2-table-btn-buy-container-desktop
+btn_buy_individual_collaborator(period)
- for (var i = 0; i < 4; i++)
th(
class=(i === config.highlightedColumn.index ? 'plans-v2-table-green-highlighted' : (i === config.highlightedColumn.index - 1 ? 'plans-v2-table-cell-before-highlighted-column' : ''))
)
if (i === config.highlightedColumn.index)
p.plans-v2-table-green-highlighted-text !{config.highlightedColumn.text[period]}
case config.tableHead[i]
when 'individual_free'
+table_head_individual_free(period)
when 'individual_personal'
+table_head_individual_personal(period)
when 'individual_collaborator'
+table_head_individual_collaborator(period)
when 'individual_professional'
+table_head_individual_professional(period)
when 'group_collaborator'
+table_head_group_collaborator()
when 'group_professional'
+table_head_group_professional()
when 'group_organization'
+table_head_group_organization()
when 'student_free'
+table_head_student_free(period)
when 'student_student'
+table_head_student_student(period)
when 'student_university'
+table_head_student_university(period)
th
div.plans-v2-table-th-content
p.plans-v2-table-th-content-title #{translate("professional")}
+table_head_price('professional', period)
.plans-v2-table-btn-buy-container-mobile
+btn_buy_individual_professional(period)
ul.plans-v2-table-th-content-benefit
li #{translate("unlimited_collabs")}
li #{translate("all_premium_features")}
.plans-v2-table-btn-buy-container-desktop
+btn_buy_individual_professional(period)
for planFeaturesPerSection in planFeatures.individual
if planFeaturesPerSection.divider
for featuresPerSection in config.features
if featuresPerSection.divider
tr.plans-v2-table-divider
td(colspan="5")
td(colspan=config.tableHead.length + 1)
div
b.plans-v2-table-divider-label #{translate(planFeaturesPerSection.dividerLabel)}
b.plans-v2-table-divider-label #{translate(featuresPerSection.dividerLabel)}
//- will only appear on screen width >= 768px (using CSS)
i.fa.fa-question-circle.plans-v2-table-divider-question-icon(
data-toggle="tooltip"
title=translate(planFeaturesPerSection.dividerInfo),
title=translate(featuresPerSection.dividerInfo),
data-placement="top"
)
//- will only appear on screen width < 768px (using CSS)
@ -65,13 +46,13 @@ mixin table_individual(period)
span (
span.plans-v2-table-divider-learn-more-text(
data-toggle="tooltip"
title=translate(planFeaturesPerSection.dividerInfo),
title=translate(featuresPerSection.dividerInfo),
data-placement="top"
) #{translate("learn_more_lowercase")}
span )
for feature, featureIndex in planFeaturesPerSection.items
for feature, featureIndex in featuresPerSection.items
tr(
class=(featureIndex === (planFeaturesPerSection.items.length - 1) ? 'plans-v2-table-row-last-row-per-section' : '')
class=(featureIndex === (featuresPerSection.items.length - 1) ? 'plans-v2-table-row-last-row-per-section' : '')
)
td(event-tracking="plans-page-table" event-tracking-trigger="hover" event-tracking-ga="subscription-funnel" event-tracking-label=`${feature.feature}`)
.plans-v2-table-feature-name
@ -94,23 +75,75 @@ mixin table_individual(period)
span )
else
| #{translate(feature.feature)}
td(ng-non-bindable)
+table_cell(feature, 'free')
td.plans-v2-table-cell-before-highlighted-column(ng-non-bindable)
+table_cell(feature, 'personal')
td.plans-v2-table-green-highlighted(ng-non-bindable)
+table_cell(feature, 'collaborator')
td(ng-non-bindable)
+table_cell(feature, 'professional')
for plan, planIndex in Object.keys(feature.plans)
td(
class=(planIndex === config.highlightedColumn.index ? 'plans-v2-table-green-highlighted' : (planIndex === config.highlightedColumn.index - 1 ? 'plans-v2-table-cell-before-highlighted-column' : ''))
)
+table_cell(feature, plan)
mixin table_individual(period)
table.card.plans-v2-table.plans-v2-table-individual
+plans_v2_table(period, plansV2Config.individual)
mixin table_group
table.card.plans-v2-table.plans-v2-table-group
tr
th
th.plans-v2-table-cell-before-highlighted-column
div.plans-v2-table-th-content
+plans_v2_table('annual', plansV2Config.group)
mixin table_student(period)
table.card.plans-v2-table.plans-v2-table-student
+plans_v2_table(period, plansV2Config.student)
mixin table_head_individual_free(period)
.plans-v2-table-th-content
p.plans-v2-table-th-content-title #{translate("free")}
+table_head_price('free', period)
.plans-v2-table-btn-buy-container-mobile
+btn_buy_individual_free()
ul.plans-v2-table-th-content-benefit
li #{translate("one_collaborator")}
.plans-v2-table-btn-buy-container-desktop
+btn_buy_individual_free()
mixin table_head_individual_personal(period)
.plans-v2-table-th-content
p.plans-v2-table-th-content-title #{translate("personal")}
+table_head_price('personal', period)
.plans-v2-table-btn-buy-container-mobile
+btn_buy_individual_personal(period)
ul.plans-v2-table-th-content-benefit
li #{translate("one_collaborator")}
li #{translate("most_premium_features")}
.plans-v2-table-btn-buy-container-desktop
+btn_buy_individual_personal(period)
mixin table_head_individual_collaborator(period)
.plans-v2-table-th-content
p.plans-v2-table-th-content-title #{translate("standard")}
+table_head_price('collaborator', period)
.plans-v2-table-btn-buy-container-mobile
+btn_buy_individual_collaborator(period)
ul.plans-v2-table-th-content-benefit
li !{translate("x_collaborators_per_project", {collaboratorsCount: '10'})}
li #{translate("all_premium_features")}
.plans-v2-table-btn-buy-container-desktop
+btn_buy_individual_collaborator(period)
mixin table_head_individual_professional(period)
.plans-v2-table-th-content
p.plans-v2-table-th-content-title #{translate("professional")}
+table_head_price('professional', period)
.plans-v2-table-btn-buy-container-mobile
+btn_buy_individual_professional(period)
ul.plans-v2-table-th-content-benefit
li #{translate("unlimited_collabs")}
li #{translate("all_premium_features")}
.plans-v2-table-btn-buy-container-desktop
+btn_buy_individual_professional(period)
mixin table_head_group_collaborator()
.plans-v2-table-th-content
p.plans-v2-table-th-content-title #{translate("group_standard")}
div.plans-v2-table-price-container
.plans-v2-table-price-container
strike.plans-v2-table-annual-price-before-discount(data-ol-plans-v2-table-annual-price-before-discount)
+gen_localized_price_for_plan_view('collaborator', 'annual')
p.plans-v2-table-price
@ -129,11 +162,10 @@ mixin table_group
+btn_buy_group_collaborator()
+additional_link_group('group_collaborator')
th.plans-v2-table-green-highlighted
div.plans-v2-table-th-content
p.plans-v2-table-green-highlighted-text RECOMMENDED
mixin table_head_group_professional()
.plans-v2-table-th-content
p.plans-v2-table-th-content-title #{translate("group_professional")}
div.plans-v2-table-price-container
.plans-v2-table-price-container
strike.plans-v2-table-annual-price-before-discount(data-ol-plans-v2-table-annual-price-before-discount)
+gen_localized_price_for_plan_view('professional', 'annual')
p.plans-v2-table-price
@ -152,10 +184,11 @@ mixin table_group
+btn_buy_group_professional()
+additional_link_group('group_professional')
th
div.plans-v2-table-th-content
mixin table_head_group_organization()
.plans-v2-table-th-content
p.plans-v2-table-th-content-title #{translate("organization")}
div.plans-v2-table-comments-icon
.plans-v2-table-comments-icon
i.fa.fa-comments-o
.plans-v2-table-btn-buy-container-mobile
+btn_buy_group_organization()
@ -175,68 +208,8 @@ mixin table_group
.plans-v2-table-btn-buy-container-desktop
+btn_buy_group_organization()
small.plans-v2-table-th-content-additional-link.invisible(aria-hidden="true")
th
for planFeaturesPerSection in planFeatures.group
if planFeaturesPerSection.divider
tr.plans-v2-table-divider
td(colspan="4")
div
b.plans-v2-table-divider-label #{translate(planFeaturesPerSection.dividerLabel)}
//- will only appear on screen width >= 768px (using CSS)
i.fa.fa-question-circle.plans-v2-table-divider-question-icon(
data-toggle="tooltip"
title=translate(planFeaturesPerSection.dividerInfo),
data-placement="top"
)
//- will only appear on screen width < 768px (using CSS)
span.plans-v2-table-divider-learn-more-container
span (
span.plans-v2-table-divider-learn-more-text(
data-toggle="tooltip"
title=translate(planFeaturesPerSection.dividerInfo),
data-placement="top"
) #{translate("learn_more_lowercase")}
span )
td
for feature, featureIndex in planFeaturesPerSection.items
tr(
class=(featureIndex === (planFeaturesPerSection.items.length - 1) ? 'plans-v2-table-row-last-row-per-section' : '')
)
td(event-tracking="plans-page-table" event-tracking-trigger="hover" event-tracking-ga="subscription-funnel" event-tracking-label=`${feature.feature}`)
.plans-v2-table-feature-name
if feature.info
span #{translate(feature.feature)}
//- will only appear on screen width >= 768px (using CSS)
i.fa.fa-question-circle.plans-v2-table-feature-name-question-icon(
data-toggle="tooltip"
title=translate(feature.info),
data-placement="right"
)
//- will only appear on screen width < 768px (using CSS)
span.plans-v2-table-feature-name-learn-more-container
span (
span.plans-v2-table-feature-name-learn-more-text(
data-toggle="tooltip"
title=translate(feature.info),
data-placement="top"
) #{translate("learn_more_lowercase")}
span )
else
| #{translate(feature.feature)}
td.plans-v2-table-cell-before-highlighted-column(ng-non-bindable)
+table_cell(feature, 'group_standard')
td.plans-v2-table-green-highlighted(ng-non-bindable)
+table_cell(feature, 'group_professional')
td(ng-non-bindable)
+table_cell(feature, 'organization')
td
mixin table_student(period)
table.card.plans-v2-table.plans-v2-table-student
tr
th
th.plans-v2-table-cell-before-highlighted-column
mixin table_head_student_free(period)
div.plans-v2-table-th-content
p.plans-v2-table-th-content-title #{translate("free")}
+table_head_price('free', period)
@ -246,13 +219,9 @@ mixin table_student(period)
li #{translate("one_collaborator")}
.plans-v2-table-btn-buy-container-desktop
+btn_buy_student_free()
th.plans-v2-table-green-highlighted
mixin table_head_student_student(period)
div.plans-v2-table-th-content
p.plans-v2-table-green-highlighted-text
if (period === 'monthly')
| SAVE 20% ON ANNUAL PLAN
else
| SAVING 20%
p.plans-v2-table-th-content-title #{translate("student")}
+table_head_price('student', period)
.plans-v2-table-btn-buy-container-mobile
@ -262,7 +231,8 @@ mixin table_student(period)
li #{translate("all_premium_features")}
.plans-v2-table-btn-buy-container-desktop
+btn_buy_student_student(period)
th
mixin table_head_student_university(period)
div.plans-v2-table-th-content
p.plans-v2-table-th-content-title #{translate("university")}
div.plans-v2-table-comments-icon
@ -272,62 +242,6 @@ mixin table_student(period)
p.plans-v2-table-th-content-benefit !{translate("all_our_group_plans_offer_educational_discount", {}, [{name: 'b'}, {name: 'b'}])}
.plans-v2-table-btn-buy-container-desktop
+btn_buy_student_university(period)
th
for planFeaturesPerSection in planFeatures.student
if (planFeaturesPerSection.divider)
tr.plans-v2-table-divider
td(colspan="4")
div
b.plans-v2-table-divider-label #{translate(planFeaturesPerSection.dividerLabel)}
//- will only appear on screen width >= 768px (using CSS)
i.fa.fa-question-circle.plans-v2-table-divider-question-icon(
data-toggle="tooltip"
title=translate(planFeaturesPerSection.dividerInfo),
data-placement="top"
)
//- will only appear on screen width < 768px (using CSS)
span.plans-v2-table-divider-learn-more-container
span (
span.plans-v2-table-divider-learn-more-text(
data-toggle="tooltip"
title=translate(planFeaturesPerSection.dividerInfo),
data-placement="top"
) #{translate("learn_more_lowercase")}
span )
td
for feature, featureIndex in planFeaturesPerSection.items
tr(
class=(featureIndex === (planFeaturesPerSection.items.length - 1) ? 'plans-v2-table-row-last-row-per-section' : '')
)
td(event-tracking="plans-page-table" event-tracking-trigger="hover" event-tracking-ga="subscription-funnel" event-tracking-label=`${feature.feature}`)
.plans-v2-table-feature-name
if (feature.info)
span #{translate(feature.feature)}
//- will only appear on screen width >= 768px (using CSS)
i.fa.fa-question-circle.plans-v2-table-feature-name-question-icon(
data-toggle="tooltip"
title=translate(feature.info),
data-placement="right"
)
//- will only appear on screen width < 768px (using CSS)
span.plans-v2-table-feature-name-learn-more-container
span (
span.plans-v2-table-feature-name-learn-more-text(
data-toggle="tooltip"
title=translate(feature.info),
data-placement="top"
) #{translate("learn_more_lowercase")}
span )
else
| #{translate(feature.feature)}
td.plans-v2-table-cell-before-highlighted-column(ng-non-bindable)
+table_cell(feature, 'free')
td.plans-v2-table-green-highlighted(ng-non-bindable)
+table_cell(feature, 'student')
td(ng-non-bindable)
+table_cell(feature, 'university')
td
mixin table_head_price(plan, period)
div.plans-v2-table-price-container

View file

@ -379,8 +379,7 @@ span.plans-v2-license-picker-educational-discount-learn-more-container {
.plans-v2-table-student {
tr {
// "hide" the last column on desktop by making the background-color as the default background color
th:last-of-type,
td:last-of-type {
th:last-of-type {
background-color: @ol-blue-gray-0;
}
@ -419,8 +418,7 @@ span.plans-v2-license-picker-educational-discount-learn-more-container {
@media (max-width: @screen-md-max) {
tr {
th:last-of-type,
td:last-of-type {
th:last-of-type {
// Last column is only a UI placeholder for desktop view.
// We need to hide it for mobile to have the full table fully visible on mobile
// without any empty horizontal space.