Merge pull request #22742 from overleaf/mf-remove-frontend-plans-page-dead-code

[web] Remove frontend plans page dead code

GitOrigin-RevId: 6db07b909f99a7afd17880698787a2c3527e879f
This commit is contained in:
M Fahru
2025-01-15 10:05:44 -07:00
committed by Copybot
parent 4340e24431
commit db64829f63
11 changed files with 0 additions and 1049 deletions

View File

@@ -1,162 +0,0 @@
import getMeta from '../../../utils/meta'
import { swapModal } from '../../utils/swapModal'
import * as eventTracking from '../../../infrastructure/event-tracking'
import { createLocalizedGroupPlanPrice } from '../utils/group-plan-pricing'
export const GROUP_PLAN_MODAL_HASH = '#groups'
function getFormValues() {
const modalEl = document.querySelector('[data-ol-group-plan-modal]')
const planCode = modalEl.querySelector(
'input[name="plan_code"]:checked'
).value
const size = modalEl.querySelector('#size').value
const currency = modalEl.querySelector('#currency').value
const usage = modalEl.querySelector('#usage').checked
? 'educational'
: 'enterprise'
return { planCode, size, currency, usage }
}
export function updateGroupModalPlanPricing() {
const modalEl = document.querySelector('[data-ol-group-plan-modal]')
const { planCode, size, currency, usage } = getFormValues()
const { localizedPrice, localizedPerUserPrice } =
createLocalizedGroupPlanPrice({
plan: planCode,
licenseSize: size,
currency,
usage,
})
modalEl.querySelectorAll('[data-ol-group-plan-plan-code]').forEach(el => {
el.hidden = el.getAttribute('data-ol-group-plan-plan-code') !== planCode
})
modalEl.querySelectorAll('[data-ol-group-plan-usage]').forEach(el => {
el.hidden = el.getAttribute('data-ol-group-plan-usage') !== usage
})
modalEl.querySelector('[data-ol-group-plan-display-price]').innerText =
localizedPrice
modalEl
.querySelectorAll('[data-ol-group-plan-price-per-user]')
.forEach(el => {
el.innerText = `${localizedPerUserPrice} ${el.getAttribute(
'data-ol-group-plan-price-per-user'
)}`
})
modalEl.querySelector('[data-ol-group-plan-educational-discount]').hidden =
usage !== 'educational'
modalEl.querySelector(
'[data-ol-group-plan-educational-discount-applied]'
).hidden = size < 10
modalEl.querySelector(
'[data-ol-group-plan-educational-discount-ineligible]'
).hidden = size >= 10
}
const modalEl = $('[data-ol-group-plan-modal]')
modalEl
.on('shown.bs.modal', function () {
const path = `${window.location.pathname}${window.location.search}`
history.replaceState(null, document.title, path + GROUP_PLAN_MODAL_HASH)
eventTracking.sendMB('form-submitted-groups-modal-open')
})
.on('hidden.bs.modal', function () {
const path = `${window.location.pathname}${window.location.search}${window.location.hash}`
history.replaceState(null, document.title, path)
})
function showGroupPlanModal() {
modalEl.modal()
eventTracking.send(
'subscription-funnel',
'plans-page',
'group-inquiry-potential'
) // deprecated by plans-page-click
}
document
.querySelectorAll('[data-ol-group-plan-form] select')
.forEach(el => el.addEventListener('change', updateGroupModalPlanPricing))
document
.querySelectorAll('[data-ol-group-plan-form] input')
.forEach(el => el.addEventListener('change', updateGroupModalPlanPricing))
document.querySelectorAll('[data-ol-purchase-group-plan]').forEach(el =>
el.addEventListener('click', e => {
e.preventDefault()
const { planCode, size, currency, usage } = getFormValues()
const queryParams = new URLSearchParams(
Object.entries({
planCode: `group_${planCode}_${size}_${usage}`,
currency,
itm_campaign: 'groups',
})
)
const itmContent = getMeta('ol-itm_content')
if (itmContent) {
queryParams.set('itm_content', itmContent)
}
eventTracking.sendMB('groups-modal-click', {
plan: planCode,
users: size,
currency,
type: usage,
})
const url = new URL('/user/subscription/new', window.origin)
url.search = queryParams.toString()
window.location = url.toString()
})
)
document.querySelectorAll('[data-ol-open-group-plan-modal]').forEach(el => {
const location = el.getAttribute('data-ol-location')
el.addEventListener('click', function (e) {
e.preventDefault()
eventTracking.sendMB('plans-page-click', {
button: 'group',
location,
'billing-period': 'annual',
})
showGroupPlanModal()
})
})
document
.querySelectorAll('[data-ol-open-contact-form-for-more-than-50-licenses]')
.forEach(el => {
el.addEventListener('click', function (e) {
e.preventDefault()
swapModal(
'[data-ol-group-plan-modal]',
'[data-ol-contact-form-modal="general"]'
)
})
})
function updateGroupModalPlanPricingIfAvailable() {
const isGroupPlanModalAvailable = document.querySelector(
'[data-ol-group-plan-modal]'
)
if (isGroupPlanModalAvailable) {
updateGroupModalPlanPricing()
}
}
updateGroupModalPlanPricingIfAvailable()
// When using browser back buttons, we need to update the pricing plan
// after the page has fully loaded as we need to wait for the previously
// selected values to load for e.g. size.
window.addEventListener('load', () => {
updateGroupModalPlanPricingIfAvailable()
})
if (window.location.hash === GROUP_PLAN_MODAL_HASH) {
showGroupPlanModal()
}

View File

@@ -1,74 +0,0 @@
import './group-plan-modal'
import { updateMainGroupPlanPricing } from '../../pages/user/subscription/plans-v2/plans-v2-group-plan'
export function changePlansV2MainPageGroupData() {
const mainPlansPageFormEl = document.querySelector(
'[data-ol-plans-v2-license-picker-form]'
)
const mainPlansPageLicensePickerEl = mainPlansPageFormEl.querySelector(
'[data-ol-plans-v2-license-picker-select]'
)
const mainPlansPageEducationalDiscountEl = mainPlansPageFormEl.querySelector(
'[data-ol-plans-v2-license-picker-educational-discount-input]'
)
const groupPlanModalNumberOfLicenses = document.querySelector(
'[data-ol-group-plan-modal] #size'
).value
const educationalDiscountChecked = document.querySelector(
'[data-ol-group-plan-modal] #usage'
).checked
const educationalDiscountEnabled =
educationalDiscountChecked && groupPlanModalNumberOfLicenses >= 10
// update license picker on the main plans page
mainPlansPageLicensePickerEl.value = groupPlanModalNumberOfLicenses
// update educational discount checkbox on the main plans page
//
// extra note
// for number of users < 10, there is a difference on the checkbox behaviour
// between the group plan modal and the main plan page
//
// On the group plan modal, the checkbox button is not visually disabled for number of users < 10 (checkbox can still be clicked)
// but the logic is disabled and there will be an extra text whether or not the discount is applied
//
// However, on the main group plan page, the checkbox button is visually disabled for number of users < 10 (checkbox can not be clicked)
// Hence, there's a possibility that the checkbox on the group plan modal is checked, but the discount is not applied.
// i.e user can still click the checkbox with number of users < 10. The price won't be discounted, but the checkbox is checked.
if (groupPlanModalNumberOfLicenses >= 10) {
mainPlansPageEducationalDiscountEl.checked = educationalDiscountEnabled
} else {
// The code below is for disabling the checkbox button on the main plan page for number of users <10
// while still checking the educational discount
if (educationalDiscountChecked) {
mainPlansPageEducationalDiscountEl.checked = false
}
}
updateMainGroupPlanPricing()
}
function hideCurrencyPicker() {
document.querySelector('[data-ol-group-plan-form-currency]').hidden = true
}
document.querySelectorAll('[data-ol-group-plan-form] select').forEach(el =>
el.addEventListener('change', () => {
changePlansV2MainPageGroupData()
})
)
document
.querySelectorAll('[data-ol-group-plan-form] input')
.forEach(el => el.addEventListener('change', changePlansV2MainPageGroupData))
const isGroupPlanModalAvailable = document.querySelector(
'[data-ol-group-plan-modal]'
)
if (isGroupPlanModalAvailable) {
hideCurrencyPicker()
}

View File

@@ -1,43 +0,0 @@
import { formatCurrency } from '@/shared/utils/currency'
import getMeta from '../../../utils/meta'
/**
* @import { CurrencyCode } from '../../../../../types/subscription/currency'
*/
// plan: 'collaborator' or 'professional'
// the rest of available arguments can be seen in the groupPlans value
/**
* @param {Object} opts
* @param {'collaborator' | 'professional'} opts.plan
* @param {string} opts.licenseSize
* @param {CurrencyCode} opts.currency
* @param {'enterprise' | 'educational'} opts.usage
* @param {string} [opts.locale]
* @returns {{localizedPrice: string, localizedPerUserPrice: string}}
*/
export function createLocalizedGroupPlanPrice({
plan,
licenseSize,
currency,
usage,
locale = getMeta('ol-i18n').currentLangCode || 'en',
}) {
const groupPlans = getMeta('ol-groupPlans')
const priceInCents =
groupPlans[usage][plan][currency][licenseSize].price_in_cents
const price = priceInCents / 100
const perUserPrice = price / parseInt(licenseSize)
/**
* @param {number} price
* @returns {string}
*/
const formatPrice = price => formatCurrency(price, currency, locale, true)
return {
localizedPrice: formatPrice(price),
localizedPerUserPrice: formatPrice(perUserPrice),
}
}

View File

@@ -1,142 +0,0 @@
import '../../../../features/plans/plans-v2-group-plan-modal'
import getMeta from '../../../../utils/meta'
import { updateGroupModalPlanPricing } from '../../../../features/plans/group-plan-modal'
import { createLocalizedGroupPlanPrice } from '../../../../features/plans/utils/group-plan-pricing'
const MINIMUM_LICENSE_SIZE_EDUCATIONAL_DISCOUNT = 10
export function updateMainGroupPlanPricing() {
const currency = getMeta('ol-recommendedCurrency')
const formEl = document.querySelector(
'[data-ol-plans-v2-license-picker-form]'
)
const licenseSize = formEl.querySelector(
'[data-ol-plans-v2-license-picker-select]'
).value
const usage = formEl.querySelector(
'[data-ol-plans-v2-license-picker-educational-discount-input]'
).checked
? 'educational'
: 'enterprise'
const {
localizedPrice: localizedPriceProfessional,
localizedPerUserPrice: localizedPerUserPriceProfessional,
} = createLocalizedGroupPlanPrice({
plan: 'professional',
licenseSize,
currency,
usage,
})
const {
localizedPrice: localizedPriceCollaborator,
localizedPerUserPrice: localizedPerUserPriceCollaborator,
} = createLocalizedGroupPlanPrice({
plan: 'collaborator',
licenseSize,
currency,
usage,
})
document.querySelector(
'[data-ol-plans-v2-group-total-price="professional"]'
).innerText = localizedPriceProfessional
document.querySelector(
'[data-ol-plans-v2-group-price-per-user="professional"]'
).innerText = localizedPerUserPriceProfessional
document.querySelector(
'[data-ol-plans-v2-group-total-price="collaborator"]'
).innerText = localizedPriceCollaborator
document.querySelector(
'[data-ol-plans-v2-group-price-per-user="collaborator"]'
).innerText = localizedPerUserPriceCollaborator
const notEligibleForEducationalDiscount =
licenseSize < MINIMUM_LICENSE_SIZE_EDUCATIONAL_DISCOUNT
formEl
.querySelector(
'[data-ol-plans-v2-license-picker-educational-discount-label]'
)
.classList.toggle('disabled', notEligibleForEducationalDiscount)
formEl
.querySelector('.plans-v2-license-picker-educational-discount')
.classList.toggle(
'total-licenses-not-eligible-for-discount',
notEligibleForEducationalDiscount
)
formEl.querySelector(
'[data-ol-plans-v2-license-picker-educational-discount-input]'
).disabled = notEligibleForEducationalDiscount
if (notEligibleForEducationalDiscount) {
// force disable educational discount checkbox
formEl.querySelector(
'[data-ol-plans-v2-license-picker-educational-discount-input]'
).checked = false
}
changeNumberOfUsersInTableHead()
changeNumberOfUsersInFeatureTable()
}
export function changeGroupPlanModalNumberOfLicenses() {
const modalEl = document.querySelector('[data-ol-group-plan-modal]')
const numberOfLicenses = document.querySelector(
'[data-ol-plans-v2-license-picker-select]'
).value
const groupPlanModalLicensePickerEl = modalEl.querySelector('#size')
groupPlanModalLicensePickerEl.value = numberOfLicenses
updateGroupModalPlanPricing()
}
export function changeGroupPlanModalEducationalDiscount() {
const modalEl = document.querySelector('[data-ol-group-plan-modal]')
const groupPlanModalEducationalDiscountEl = modalEl.querySelector('#usage')
const educationalDiscountChecked = document.querySelector(
'[data-ol-plans-v2-license-picker-educational-discount-input]'
).checked
groupPlanModalEducationalDiscountEl.checked = educationalDiscountChecked
updateGroupModalPlanPricing()
}
export function changeNumberOfUsersInFeatureTable() {
document
.querySelectorAll(
'[data-ol-plans-v2-table-cell-plan^="group"][data-ol-plans-v2-table-cell-feature="number_of_users"]'
)
.forEach(el => {
const licenseSize = document.querySelector(
'[data-ol-plans-v2-license-picker-select]'
).value
el.textContent = el.textContent.replace(/\d+/, licenseSize)
})
}
export function changeNumberOfUsersInTableHead() {
document
.querySelectorAll('[data-ol-plans-v2-table-th-group-license-size]')
.forEach(el => {
const licenseSize = el.getAttribute(
'data-ol-plans-v2-table-th-group-license-size'
)
const currentLicenseSize = document.querySelector(
'[data-ol-plans-v2-license-picker-select]'
).value
el.hidden = licenseSize !== currentLicenseSize
})
}

View File

@@ -1,52 +0,0 @@
import { GROUP_PLAN_MODAL_HASH } from '@/features/plans/group-plan-modal'
export function getViewInfoFromHash() {
const hashValue = window.location.hash.replace('#', '')
const groupPlanModalHashValue = GROUP_PLAN_MODAL_HASH.replace('#', '')
switch (hashValue) {
case 'individual-monthly':
return ['individual', 'monthly']
case 'individual-annual':
return ['individual', 'annual']
case groupPlanModalHashValue:
case 'group':
return ['group', 'annual']
case 'student-monthly':
return ['student', 'monthly']
case 'student-annual':
return ['student', 'annual']
default:
return ['individual', 'monthly']
}
}
/**
*
* @param {individual | group | student} viewTab
* @param {monthly | annual} period
*/
export function setHashFromViewTab(viewTab, period) {
const newHash = viewTab === 'group' ? 'group' : `${viewTab}-${period}`
if (window.location.hash.replace('#', '') !== newHash) {
window.location.hash = newHash
}
}
// this is only for the students link in footer
export function handleForStudentsLinkInFooter() {
const links = document.querySelectorAll('[data-ol-for-students-link]')
links.forEach(function (link) {
link.addEventListener('click', function () {
if (window.location.pathname === '/user/subscription/plans') {
// reload location with the correct hash
const newURL =
'/user/subscription/plans?itm_referrer=footer-for-students#student-annual'
history.replaceState(null, '', newURL)
location.reload()
}
})
})
}

View File

@@ -1,63 +0,0 @@
// m-a stands for monthly-annual
export function toggleMonthlyAnnualSwitching(
view,
currentMonthlyAnnualSwitchValue
) {
const containerEl = document.querySelector(
'[data-ol-plans-v2-m-a-switch-container]'
)
if (containerEl) {
const checkbox = containerEl.querySelector('input[type="checkbox"]')
containerEl.classList.toggle('disabled', view === 'group')
checkbox.disabled = view === 'group'
checkbox.checked = currentMonthlyAnnualSwitchValue === 'monthly'
switchMonthlyAnnual(currentMonthlyAnnualSwitchValue)
}
}
export function switchMonthlyAnnual(currentMonthlyAnnualSwitchValue) {
const el = document.querySelector('[data-ol-plans-v2-m-a-tooltip]')
el.classList.toggle(
'plans-v2-m-a-tooltip-monthly-selected',
currentMonthlyAnnualSwitchValue === 'monthly'
)
document.querySelectorAll('[data-ol-tooltip-period]').forEach(el => {
const period = el.getAttribute('data-ol-tooltip-period')
el.hidden = period !== currentMonthlyAnnualSwitchValue
})
document.querySelectorAll('[data-ol-plans-v2-period').forEach(el => {
const period = el.getAttribute('data-ol-plans-v2-period')
el.hidden = currentMonthlyAnnualSwitchValue !== period
})
document
.querySelectorAll('[data-ol-plans-v2-m-a-switch-text]')
.forEach(el => {
el.classList.toggle(
'underline',
el.getAttribute('data-ol-plans-v2-m-a-switch-text') ===
currentMonthlyAnnualSwitchValue
)
})
}
function changeMonthlyAnnualTooltipPosition() {
const smallScreen = window.matchMedia('(max-width: 767px)').matches
const el = document.querySelector('[data-ol-plans-v2-m-a-tooltip]')
el.classList.toggle('bottom', smallScreen)
el.classList.toggle('left', !smallScreen)
}
// click event listener for monthly-annual switch
export function setUpMonthlyAnnualSwitching() {
changeMonthlyAnnualTooltipPosition()
window.addEventListener('resize', changeMonthlyAnnualTooltipPosition)
}

View File

@@ -1,336 +0,0 @@
import '../../../../marketing'
import '../../../../infrastructure/hotjar'
import * as eventTracking from '../../../../infrastructure/event-tracking'
import { setUpStickyHeaderObserver } from './plans-v2-sticky-header'
import {
setUpMonthlyAnnualSwitching,
switchMonthlyAnnual,
toggleMonthlyAnnualSwitching,
} from './plans-v2-m-a-switch'
import {
changeGroupPlanModalEducationalDiscount,
changeGroupPlanModalNumberOfLicenses,
updateMainGroupPlanPricing,
} from './plans-v2-group-plan'
import { setUpGroupSubscriptionButtonAction } from './plans-v2-subscription-button'
import {
getViewInfoFromHash,
handleForStudentsLinkInFooter,
setHashFromViewTab,
} from './plans-v2-hash'
import { sendPlansViewEvent } from './plans-v2-tracking'
import getMeta from '../../../../utils/meta'
const currentCurrencyCode = getMeta('ol-recommendedCurrency')
function showQuoteForTab(viewTab) {
// hide/display quote rows
document.querySelectorAll('.plans-page-quote-row').forEach(quoteRow => {
const showForPlanTypes = quoteRow.getAttribute('data-ol-show-for-plan-type')
if (showForPlanTypes?.includes(viewTab)) {
quoteRow.classList.remove('plans-page-quote-row-hidden')
} else {
quoteRow.classList.add('plans-page-quote-row-hidden')
}
})
}
function setUpSubscriptionTracking(linkEl) {
linkEl.addEventListener('click', function () {
const plan =
linkEl.getAttribute('data-ol-tracking-plan') ||
linkEl.getAttribute('data-ol-start-new-subscription')
const location = linkEl.getAttribute('data-ol-location')
const period = linkEl.getAttribute('data-ol-item-view')
const DEFAULT_EVENT_TRACKING_KEY = 'plans-page-click'
const eventTrackingKey =
linkEl.getAttribute('data-ol-event-tracking-key') ||
DEFAULT_EVENT_TRACKING_KEY
const eventTrackingSegmentation = {
button: plan,
location,
'billing-period': period,
currency: currentCurrencyCode,
}
eventTracking.sendMB(eventTrackingKey, eventTrackingSegmentation)
})
}
const searchParams = new URLSearchParams(window.location.search)
export function updateLinkTargets() {
document.querySelectorAll('[data-ol-start-new-subscription]').forEach(el => {
if (el.hasAttribute('data-ol-has-custom-href')) return
const plan = el.getAttribute('data-ol-start-new-subscription')
const view = el.getAttribute('data-ol-item-view')
const suffix = view === 'annual' ? '-annual' : '_free_trial_7_days'
const planCode = `${plan}${suffix}`
const location = el.getAttribute('data-ol-location')
const itmCampaign = searchParams.get('itm_campaign') || 'plans'
const itmContent =
itmCampaign === 'plans' ? location : searchParams.get('itm_content')
const queryString = new URLSearchParams({
planCode,
currency: currentCurrencyCode,
itm_campaign: itmCampaign,
})
if (itmContent) {
queryString.set('itm_content', itmContent)
}
if (searchParams.get('itm_referrer')) {
queryString.set('itm_referrer', searchParams.get('itm_referrer'))
}
el.href = `/user/subscription/new?${queryString.toString()}`
})
}
// We need this mutable variable because the group tab only have annual.
// There's some difference between the monthly and annual UI
// and since monthly-annual switch is disabled for the group tab,
// we need to introduce a new variable to store the information
let currentMonthlyAnnualSwitchValue = 'annual'
function selectTab(viewTab) {
document.querySelectorAll('[data-ol-plans-v2-view-tab]').forEach(el => {
const tab = el.querySelector('[data-ol-plans-v2-view-tab] button')
if (tab) {
const isActive =
tab.parentElement.getAttribute('data-ol-plans-v2-view-tab') === viewTab
tab.parentElement.classList.toggle('active', isActive)
tab.setAttribute('aria-selected', isActive)
}
})
document.querySelectorAll('[data-ol-plans-v2-view]').forEach(el => {
el.hidden = el.getAttribute('data-ol-plans-v2-view') !== viewTab
})
const tooltipEl = document.querySelector('[data-ol-plans-v2-m-a-tooltip]')
if (tooltipEl) {
tooltipEl.hidden = viewTab === 'group'
}
const licensePickerEl = document.querySelector(
'[data-ol-plans-v2-license-picker-container]'
)
if (licensePickerEl) {
licensePickerEl.hidden = viewTab !== 'group'
}
const monthlyAnnualSwitch = document.querySelector(
'[data-ol-plans-v2-m-a-switch-container]'
)
if (monthlyAnnualSwitch) {
monthlyAnnualSwitch.setAttribute('data-ol-current-view', viewTab)
}
if (viewTab === 'group') {
updateMainGroupPlanPricing()
}
updateMonthlyAnnualSwitchValue(viewTab)
toggleUniversityInfo(viewTab)
// update the hash to reflect the current view when switching individual, group, or student tabs
setHashFromViewTab(viewTab, currentMonthlyAnnualSwitchValue)
showQuoteForTab(viewTab)
}
function updateMonthlyAnnualSwitchValue(viewTab) {
// group tab is special because group plan only has annual value
// so we need to perform some UI changes whenever user click the group tab
if (viewTab === 'group') {
toggleMonthlyAnnualSwitching(viewTab, 'annual')
} else {
toggleMonthlyAnnualSwitching(viewTab, currentMonthlyAnnualSwitchValue)
}
}
function setUpTabSwitching() {
document.querySelectorAll('[data-ol-plans-v2-view-tab]').forEach(el => {
const viewTab = el.getAttribute('data-ol-plans-v2-view-tab')
el.querySelector('button').addEventListener('click', function (e) {
e.preventDefault()
eventTracking.send(
'subscription-funnel',
'plans-page',
`${viewTab}-prices`
)
selectTab(viewTab)
})
})
const tabs = document.querySelectorAll(
'[data-ol-plans-v2-view-tab] [role="tab"]'
)
if (tabs) {
tabs.forEach(tab => {
tab.addEventListener('keydown', event => {
if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
const currentIndex = Array.from(tabs).indexOf(tab)
const nextIndex =
event.key === 'ArrowLeft' ? currentIndex - 1 : currentIndex + 1
const newIndex = (nextIndex + tabs.length) % tabs.length
tabs[newIndex].focus()
}
})
})
}
}
function setUpGroupPlanPricingChange() {
document
.querySelectorAll('[data-ol-plans-v2-license-picker-select]')
.forEach(el => {
el.addEventListener('change', () => {
updateMainGroupPlanPricing()
changeGroupPlanModalNumberOfLicenses()
})
})
document
.querySelectorAll(
'[data-ol-plans-v2-license-picker-educational-discount-input]'
)
.forEach(el =>
el.addEventListener('change', () => {
updateMainGroupPlanPricing()
changeGroupPlanModalEducationalDiscount()
})
)
}
function toggleUniversityInfo(viewTab) {
const el = document.querySelector('[data-ol-plans-university-info-container]')
if (el) {
el.hidden = viewTab !== 'student'
}
}
// This is the old scheme for hashing redirection
// This is deprecated and should be removed in the future
// This is only used for backward compatibility
function selectViewFromHashDeprecated() {
try {
const params = new URLSearchParams(window.location.hash.substring(1))
const view = params.get('view')
if (view) {
// View params are expected to be of the format e.g. individual or individual-monthly
const [tab, period] = view.split('-')
// make sure the selected view is valid
if (document.querySelector(`[data-ol-plans-v2-view-tab="${tab}"]`)) {
selectTab(tab)
if (['monthly', 'annual'].includes(period)) {
currentMonthlyAnnualSwitchValue = period
} else {
// set annual as the default
currentMonthlyAnnualSwitchValue = 'annual'
}
updateMonthlyAnnualSwitchValue(tab)
// change the hash with the new scheme
setHashFromViewTab(tab, currentMonthlyAnnualSwitchValue)
}
}
} catch {
// do nothing
}
}
function selectViewAndPeriodFromHash() {
const [viewTab, period] = getViewInfoFromHash()
// the sequence of these three lines is important
// because `currentMonthlyAnnualSwitchValue` is mutable.
// `selectTab` and `updateMonthlyAnnualSwitchValue` depend on the value of `currentMonthlyAnnualSwitchValue`
// to determine the UI state
currentMonthlyAnnualSwitchValue = period
selectTab(viewTab)
updateMonthlyAnnualSwitchValue(viewTab)
// handle the case where user access plans page while still on the plans page
// current example would the the "For students" link on the footer
const SCROLL_TO_TOP_DELAY = 50
window.setTimeout(() => {
window.scrollTo({ top: 0, behavior: 'smooth' })
}, SCROLL_TO_TOP_DELAY)
}
// call the function to select the view and period from the hash value
// this is called once when the page is loaded
if (window.location.hash) {
if (window.location.hash.includes('view')) {
selectViewFromHashDeprecated()
} else {
selectViewAndPeriodFromHash()
}
}
document
.querySelector('[data-ol-plans-v2-m-a-switch]')
.addEventListener('click', () => {
const isMonthlyPricing = document.querySelector(
'[data-ol-plans-v2-m-a-switch] input[type="checkbox"]'
).checked
if (isMonthlyPricing) {
currentMonthlyAnnualSwitchValue = 'monthly'
} else {
currentMonthlyAnnualSwitchValue = 'annual'
}
switchMonthlyAnnual(currentMonthlyAnnualSwitchValue)
// update the hash to reflect the current view when pressing the monthly-annual switch
const DEFAULT_VIEW_TAB = 'individual'
const viewTab =
document
.querySelector('[data-ol-plans-v2-m-a-switch-container]')
.getAttribute('data-ol-current-view') ?? DEFAULT_VIEW_TAB
setHashFromViewTab(viewTab, currentMonthlyAnnualSwitchValue)
})
document
.querySelectorAll('[data-ol-start-new-subscription]')
.forEach(setUpSubscriptionTracking)
setUpTabSwitching()
setUpGroupPlanPricingChange()
setUpMonthlyAnnualSwitching()
setUpGroupSubscriptionButtonAction()
setUpStickyHeaderObserver()
updateLinkTargets()
handleForStudentsLinkInFooter()
window.addEventListener('hashchange', () => {
if (window.location.hash) {
if (window.location.hash.includes('view')) {
selectViewFromHashDeprecated()
} else {
selectViewAndPeriodFromHash()
}
}
})
sendPlansViewEvent()

View File

@@ -1,17 +0,0 @@
function stickyHeaderObserverCallback(entry) {
document
.querySelectorAll('[data-ol-plans-v2-table-sticky-header]')
.forEach(el =>
el.classList.toggle('sticky', entry[0].boundingClientRect.bottom > 0)
)
}
export function setUpStickyHeaderObserver() {
const stickyHeaderStopEl = document.querySelector(
'[data-ol-plans-v2-table-sticky-header-stop]'
)
const observer = new IntersectionObserver(stickyHeaderObserverCallback)
observer.observe(stickyHeaderStopEl)
}

View File

@@ -1,32 +0,0 @@
import { updateGroupModalPlanPricing } from '../../../../features/plans/group-plan-modal'
function showGroupPlanModal(el) {
const plan = el.getAttribute('data-ol-start-new-subscription')
// plan is either `group_collaborator` or `group_professional`
// we want to get the suffix (collaborator or professional)
const groupPlan = plan.split('_')[1]
const groupModalRadioInputEl = document.querySelector(
`[data-ol-group-plan-code="${groupPlan}"]`
)
groupModalRadioInputEl.checked = true
updateGroupModalPlanPricing()
const modalEl = $('[data-ol-group-plan-modal]')
modalEl.modal()
}
export function setUpGroupSubscriptionButtonAction() {
document.querySelectorAll('[data-ol-start-new-subscription]').forEach(el => {
const plan = el.getAttribute('data-ol-start-new-subscription')
if (plan === 'group_collaborator' || plan === 'group_professional') {
el.addEventListener('click', e => {
e.preventDefault()
showGroupPlanModal(el)
})
}
})
}

View File

@@ -1,51 +0,0 @@
import { sendMB } from '@/infrastructure/event-tracking'
import { getSplitTestVariant } from '@/utils/splitTestUtils'
import getMeta from '@/utils/meta'
export function sendPlansViewEvent() {
document.addEventListener(
'DOMContentLoaded',
function () {
const currency = getMeta('ol-recommendedCurrency')
const countryCode = getMeta('ol-countryCode')
const groupTabImprovementsVariant = getSplitTestVariant(
'group-tab-improvements'
)
const periodToggleTestVariant = getSplitTestVariant(
'period-toggle-improvements'
)
const device = window.matchMedia('(max-width: 767px)').matches
? 'mobile'
: 'desktop'
const queryParams = new URLSearchParams(window.location.search)
const planTabParam = queryParams.get('plan')
const plansPageViewSegmentation = {
currency,
countryCode,
device,
'group-tab-improvements': groupTabImprovementsVariant,
plan: planTabParam,
'period-toggle-improvements': periodToggleTestVariant,
}
const isPlansPage = window.location.href.includes(
'user/subscription/plans'
)
const isInterstitialPaymentPage = window.location.href.includes(
'user/subscription/choose-your-plan'
)
if (isPlansPage) {
sendMB('plans-page-view', plansPageViewSegmentation)
} else if (isInterstitialPaymentPage) {
sendMB('paywall-plans-page-view', plansPageViewSegmentation)
}
},
{ once: true }
)
}

View File

@@ -1,77 +0,0 @@
import { expect } from 'chai'
import { createLocalizedGroupPlanPrice } from '../../../../frontend/js/features/plans/utils/group-plan-pricing'
describe('group-plan-pricing', function () {
beforeEach(function () {
window.metaAttributesCache.set('ol-groupPlans', {
enterprise: {
professional: {
CHF: {
2: {
price_in_cents: 10000,
},
},
DKK: {
2: {
price_in_cents: 20000,
},
},
USD: {
2: {
price_in_cents: 30000,
},
},
},
},
})
window.metaAttributesCache.set('ol-i18n', { currentLangCode: 'en' })
})
describe('createLocalizedGroupPlanPrice', function () {
describe('CHF currency', function () {
it('should return the correct localized price', function () {
const localizedGroupPlanPrice = createLocalizedGroupPlanPrice({
plan: 'professional',
currency: 'CHF',
licenseSize: '2',
usage: 'enterprise',
})
expect(localizedGroupPlanPrice).to.deep.equal({
localizedPrice: 'CHF 100',
localizedPerUserPrice: 'CHF 50',
})
})
})
describe('DKK currency', function () {
it('should return the correct localized price', function () {
const localizedGroupPlanPrice = createLocalizedGroupPlanPrice({
plan: 'professional',
currency: 'DKK',
licenseSize: '2',
usage: 'enterprise',
})
expect(localizedGroupPlanPrice).to.deep.equal({
localizedPrice: 'kr 200',
localizedPerUserPrice: 'kr 100',
})
})
})
describe('other supported currencies', function () {
it('should return the correct localized price', function () {
const localizedGroupPlanPrice = createLocalizedGroupPlanPrice({
plan: 'professional',
currency: 'USD',
licenseSize: '2',
usage: 'enterprise',
})
expect(localizedGroupPlanPrice).to.deep.equal({
localizedPrice: '$300',
localizedPerUserPrice: '$150',
})
})
})
})
})