mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-13 21:53:43 +01:00
Merge pull request #22340 from overleaf/mf-clean-up-currency-format-test
[web] Clean up localized currency format test (`local-ccy-format-v2`) GitOrigin-RevId: 30d671479522b87ee9205994508b745d2b0ae4c3
This commit is contained in:
@@ -3,11 +3,8 @@ import _ from 'lodash'
|
||||
import { SplitTestContext } from '../../frontend/js/shared/context/split-test-context'
|
||||
|
||||
export const splitTestsArgTypes = {
|
||||
'local-ccy-format-v2': {
|
||||
description: 'Use local currency formatting',
|
||||
control: { type: 'radio' as const },
|
||||
options: ['default', 'enabled'],
|
||||
},
|
||||
// to be able to use this utility, you need to add the argTypes for each split test in this object
|
||||
// Check the original implementation for an example: https://github.com/overleaf/internal/pull/17809
|
||||
}
|
||||
|
||||
export const withSplitTests = (
|
||||
|
||||
@@ -23,8 +23,7 @@ const SubscriptionHelper = require('./SubscriptionHelper')
|
||||
const AuthorizationManager = require('../Authorization/AuthorizationManager')
|
||||
const Modules = require('../../infrastructure/Modules')
|
||||
const async = require('async')
|
||||
const { formatCurrencyLocalized } = require('../../util/currency')
|
||||
const SubscriptionFormatters = require('./SubscriptionFormatters')
|
||||
const { formatCurrency } = require('../../util/currency')
|
||||
const HttpErrorHandler = require('../Errors/HttpErrorHandler')
|
||||
const { URLSearchParams } = require('url')
|
||||
const RecurlyClient = require('./RecurlyClient')
|
||||
@@ -113,16 +112,6 @@ async function plansPage(req, res) {
|
||||
const { showLATAMBanner, showInrGeoBanner, showBrlGeoBanner } =
|
||||
_plansBanners(countryCode)
|
||||
|
||||
const localCcyAssignment = await SplitTestHandler.promises.getAssignment(
|
||||
req,
|
||||
res,
|
||||
'local-ccy-format-v2'
|
||||
)
|
||||
const formatCurrency =
|
||||
localCcyAssignment.variant === 'enabled'
|
||||
? formatCurrencyLocalized
|
||||
: SubscriptionHelper.formatCurrencyDefault
|
||||
|
||||
const shouldLoadHotjar = await getShouldLoadHotjar(req, res)
|
||||
|
||||
res.render('subscriptions/plans', {
|
||||
@@ -142,8 +131,7 @@ async function plansPage(req, res) {
|
||||
initialLocalizedGroupPrice:
|
||||
SubscriptionHelper.generateInitialLocalizedGroupPrice(
|
||||
currency ?? 'USD',
|
||||
language,
|
||||
formatCurrency
|
||||
language
|
||||
),
|
||||
showInrGeoBanner,
|
||||
showBrlGeoBanner,
|
||||
@@ -163,16 +151,6 @@ async function plansPageLightDesign(req, res) {
|
||||
const plans = SubscriptionViewModelBuilder.buildPlansList()
|
||||
const groupPlanModalDefaults = _getGroupPlanModalDefaults(req, currency)
|
||||
|
||||
const localCcyAssignment = await SplitTestHandler.promises.getAssignment(
|
||||
req,
|
||||
res,
|
||||
'local-ccy-format-v2'
|
||||
)
|
||||
const formatCurrency =
|
||||
localCcyAssignment.variant === 'enabled'
|
||||
? formatCurrencyLocalized
|
||||
: SubscriptionHelper.formatCurrencyDefault
|
||||
|
||||
const { showLATAMBanner, showInrGeoBanner, showBrlGeoBanner } =
|
||||
_plansBanners(countryCode)
|
||||
|
||||
@@ -197,8 +175,7 @@ async function plansPageLightDesign(req, res) {
|
||||
initialLocalizedGroupPrice:
|
||||
SubscriptionHelper.generateInitialLocalizedGroupPrice(
|
||||
currency ?? 'USD',
|
||||
language,
|
||||
formatCurrency
|
||||
language
|
||||
),
|
||||
showLATAMBanner,
|
||||
showInrGeoBanner,
|
||||
@@ -222,11 +199,6 @@ function formatGroupPlansDataForDash() {
|
||||
async function userSubscriptionPage(req, res) {
|
||||
const user = SessionManager.getSessionUser(req.session)
|
||||
|
||||
const localCcyAssignment = await SplitTestHandler.promises.getAssignment(
|
||||
req,
|
||||
res,
|
||||
'local-ccy-format-v2'
|
||||
)
|
||||
await SplitTestHandler.promises.getAssignment(req, res, 'ai-add-on')
|
||||
|
||||
// Populates splitTestVariants with a value for the split test name and allows
|
||||
@@ -241,10 +213,7 @@ async function userSubscriptionPage(req, res) {
|
||||
const results =
|
||||
await SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel(
|
||||
user,
|
||||
req.i18n.language,
|
||||
localCcyAssignment.variant === 'enabled'
|
||||
? SubscriptionFormatters.formatPriceLocalized
|
||||
: SubscriptionFormatters.formatPriceDefault
|
||||
req.i18n.language
|
||||
)
|
||||
const {
|
||||
personalSubscription,
|
||||
@@ -364,12 +333,6 @@ async function interstitialPaymentPage(req, res) {
|
||||
const { showLATAMBanner, showInrGeoBanner, showBrlGeoBanner } =
|
||||
_plansBanners(countryCode)
|
||||
|
||||
const localCcyAssignment = await SplitTestHandler.promises.getAssignment(
|
||||
req,
|
||||
res,
|
||||
'local-ccy-format-v2'
|
||||
)
|
||||
|
||||
const shouldLoadHotjar = await getShouldLoadHotjar(req, res)
|
||||
|
||||
res.render(template, {
|
||||
@@ -380,11 +343,8 @@ async function interstitialPaymentPage(req, res) {
|
||||
recommendedCurrency,
|
||||
interstitialPaymentConfig,
|
||||
showSkipLink,
|
||||
formatCurrency:
|
||||
localCcyAssignment.variant === 'enabled'
|
||||
? formatCurrencyLocalized
|
||||
: SubscriptionHelper.formatCurrencyDefault,
|
||||
showCurrencyAndPaymentMethods: localCcyAssignment.variant === 'enabled',
|
||||
formatCurrency,
|
||||
showCurrencyAndPaymentMethods: true, // TODO: remove hardcode
|
||||
showInrGeoBanner,
|
||||
showBrlGeoBanner,
|
||||
showLATAMBanner,
|
||||
@@ -399,18 +359,11 @@ async function interstitialPaymentPage(req, res) {
|
||||
|
||||
async function successfulSubscription(req, res) {
|
||||
const user = SessionManager.getSessionUser(req.session)
|
||||
const localCcyAssignment = await SplitTestHandler.promises.getAssignment(
|
||||
req,
|
||||
res,
|
||||
'local-ccy-format-v2'
|
||||
)
|
||||
|
||||
const { personalSubscription } =
|
||||
await SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel(
|
||||
user,
|
||||
req.i18n.language,
|
||||
localCcyAssignment.variant === 'enabled'
|
||||
? SubscriptionFormatters.formatPriceLocalized
|
||||
: SubscriptionFormatters.formatPriceDefault
|
||||
req.i18n.language
|
||||
)
|
||||
|
||||
const postCheckoutRedirect = req.session?.postCheckoutRedirect
|
||||
|
||||
@@ -1,56 +1,5 @@
|
||||
const dateformat = require('dateformat')
|
||||
const { formatCurrencyLocalized } = require('../../util/currency')
|
||||
|
||||
/**
|
||||
* @import { CurrencyCode } from '../../../../types/currency-code'
|
||||
*/
|
||||
|
||||
const currencySymbols = {
|
||||
EUR: '€',
|
||||
USD: '$',
|
||||
GBP: '£',
|
||||
SEK: 'kr',
|
||||
CAD: '$',
|
||||
NOK: 'kr',
|
||||
DKK: 'kr',
|
||||
AUD: '$',
|
||||
NZD: '$',
|
||||
CHF: 'Fr',
|
||||
SGD: '$',
|
||||
INR: '₹',
|
||||
BRL: 'R$',
|
||||
MXN: '$',
|
||||
COP: '$',
|
||||
CLP: '$',
|
||||
PEN: 'S/',
|
||||
}
|
||||
|
||||
function formatPriceDefault(priceInCents, currency) {
|
||||
if (!currency) {
|
||||
currency = 'USD'
|
||||
} else if (currency === 'CLP') {
|
||||
// CLP doesn't have minor units, recurly stores the whole major unit without cents
|
||||
return priceInCents.toLocaleString('es-CL', {
|
||||
style: 'currency',
|
||||
currency,
|
||||
minimumFractionDigits: 0,
|
||||
})
|
||||
}
|
||||
let string = String(Math.round(priceInCents))
|
||||
if (string.length === 2) {
|
||||
string = `0${string}`
|
||||
}
|
||||
if (string.length === 1) {
|
||||
string = `00${string}`
|
||||
}
|
||||
if (string.length === 0) {
|
||||
string = '000'
|
||||
}
|
||||
const cents = string.slice(-2)
|
||||
const dollars = string.slice(0, -2)
|
||||
const symbol = currencySymbols[currency]
|
||||
return `${symbol}${dollars}.${cents}`
|
||||
}
|
||||
const { formatCurrency } = require('../../util/currency')
|
||||
|
||||
/**
|
||||
* @param {number} priceInCents - price in the smallest currency unit (e.g. dollar cents, CLP units, ...)
|
||||
@@ -65,7 +14,7 @@ function formatPriceLocalized(priceInCents, currency = 'USD', locale) {
|
||||
? priceInCents
|
||||
: priceInCents / 100
|
||||
|
||||
return formatCurrencyLocalized(priceInCurrencyUnit, currency, locale)
|
||||
return formatCurrency(priceInCurrencyUnit, currency, locale)
|
||||
}
|
||||
|
||||
function formatDateTime(date) {
|
||||
@@ -83,7 +32,6 @@ function formatDate(date) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
formatPriceDefault,
|
||||
formatPriceLocalized,
|
||||
formatDateTime,
|
||||
formatDate,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
const { formatCurrency } = require('../../util/currency')
|
||||
const GroupPlansData = require('./GroupPlansData')
|
||||
|
||||
/**
|
||||
@@ -9,20 +10,15 @@ function shouldPlanChangeAtTermEnd(oldPlan, newPlan) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @import { CurrencyCode } from '../../../../types/currency-code'
|
||||
* @import { CurrencyCode } from '../../../../types/subscription/currency'
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {CurrencyCode} recommendedCurrency
|
||||
* @param {string} locale
|
||||
* @param {(amount: number, currency: CurrencyCode, locale: string, stripIfInteger: boolean) => string} formatCurrency
|
||||
* @returns {{ price: { collaborator: string, professional: string }, pricePerUser: { collaborator: string, professional: string } }} - localized group price
|
||||
*/
|
||||
function generateInitialLocalizedGroupPrice(
|
||||
recommendedCurrency,
|
||||
locale,
|
||||
formatCurrency
|
||||
) {
|
||||
function generateInitialLocalizedGroupPrice(recommendedCurrency, locale) {
|
||||
const INITIAL_LICENSE_SIZE = 2
|
||||
|
||||
// the price is in cents, so divide by 100 to get the value
|
||||
@@ -56,106 +52,7 @@ function generateInitialLocalizedGroupPrice(
|
||||
}
|
||||
}
|
||||
|
||||
const currencies = {
|
||||
USD: {
|
||||
symbol: '$',
|
||||
placement: 'before',
|
||||
},
|
||||
EUR: {
|
||||
symbol: '€',
|
||||
placement: 'before',
|
||||
},
|
||||
GBP: {
|
||||
symbol: '£',
|
||||
placement: 'before',
|
||||
},
|
||||
SEK: {
|
||||
symbol: ' kr',
|
||||
placement: 'after',
|
||||
},
|
||||
CAD: {
|
||||
symbol: '$',
|
||||
placement: 'before',
|
||||
},
|
||||
NOK: {
|
||||
symbol: ' kr',
|
||||
placement: 'after',
|
||||
},
|
||||
DKK: {
|
||||
symbol: ' kr',
|
||||
placement: 'after',
|
||||
},
|
||||
AUD: {
|
||||
symbol: '$',
|
||||
placement: 'before',
|
||||
},
|
||||
NZD: {
|
||||
symbol: '$',
|
||||
placement: 'before',
|
||||
},
|
||||
CHF: {
|
||||
symbol: 'Fr ',
|
||||
placement: 'before',
|
||||
},
|
||||
SGD: {
|
||||
symbol: '$',
|
||||
placement: 'before',
|
||||
},
|
||||
INR: {
|
||||
symbol: '₹',
|
||||
placement: 'before',
|
||||
},
|
||||
BRL: {
|
||||
code: 'BRL',
|
||||
locale: 'pt-BR',
|
||||
symbol: 'R$ ',
|
||||
placement: 'before',
|
||||
},
|
||||
MXN: {
|
||||
code: 'MXN',
|
||||
locale: 'es-MX',
|
||||
symbol: '$ ',
|
||||
placement: 'before',
|
||||
},
|
||||
COP: {
|
||||
code: 'COP',
|
||||
locale: 'es-CO',
|
||||
symbol: '$ ',
|
||||
placement: 'before',
|
||||
},
|
||||
CLP: {
|
||||
code: 'CLP',
|
||||
locale: 'es-CL',
|
||||
symbol: '$ ',
|
||||
placement: 'before',
|
||||
},
|
||||
PEN: {
|
||||
code: 'PEN',
|
||||
locale: 'es-PE',
|
||||
symbol: 'S/ ',
|
||||
placement: 'before',
|
||||
},
|
||||
}
|
||||
|
||||
function formatCurrencyDefault(amount, recommendedCurrency) {
|
||||
const currency = currencies[recommendedCurrency]
|
||||
|
||||
// Test using toLocaleString to format currencies for new LATAM regions
|
||||
if (currency.locale && currency.code) {
|
||||
return amount.toLocaleString(currency.locale, {
|
||||
style: 'currency',
|
||||
currency: currency.code,
|
||||
minimumFractionDigits: 0,
|
||||
})
|
||||
}
|
||||
|
||||
return currency.placement === 'before'
|
||||
? `${currency.symbol}${amount}`
|
||||
: `${amount}${currency.symbol}`
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
formatCurrencyDefault,
|
||||
shouldPlanChangeAtTermEnd,
|
||||
generateInitialLocalizedGroupPrice,
|
||||
}
|
||||
|
||||
@@ -69,11 +69,7 @@ async function getRedirectToHostedPage(userId, pageType) {
|
||||
].join('')
|
||||
}
|
||||
|
||||
async function buildUsersSubscriptionViewModel(
|
||||
user,
|
||||
locale = 'en',
|
||||
formatPrice = SubscriptionFormatters.formatPriceDefault
|
||||
) {
|
||||
async function buildUsersSubscriptionViewModel(user, locale = 'en') {
|
||||
let {
|
||||
personalSubscription,
|
||||
memberGroupSubscriptions,
|
||||
@@ -313,19 +309,21 @@ async function buildUsersSubscriptionViewModel(
|
||||
const pendingSubscriptionTax =
|
||||
personalSubscription.recurly.taxRate *
|
||||
recurlySubscription.pending_subscription.unit_amount_in_cents
|
||||
personalSubscription.recurly.displayPrice = formatPrice(
|
||||
recurlySubscription.pending_subscription.unit_amount_in_cents +
|
||||
pendingAddOnPrice +
|
||||
pendingAddOnTax +
|
||||
pendingSubscriptionTax,
|
||||
recurlySubscription.currency,
|
||||
locale
|
||||
)
|
||||
personalSubscription.recurly.currentPlanDisplayPrice = formatPrice(
|
||||
recurlySubscription.unit_amount_in_cents + addOnPrice + tax,
|
||||
recurlySubscription.currency,
|
||||
locale
|
||||
)
|
||||
personalSubscription.recurly.displayPrice =
|
||||
SubscriptionFormatters.formatPriceLocalized(
|
||||
recurlySubscription.pending_subscription.unit_amount_in_cents +
|
||||
pendingAddOnPrice +
|
||||
pendingAddOnTax +
|
||||
pendingSubscriptionTax,
|
||||
recurlySubscription.currency,
|
||||
locale
|
||||
)
|
||||
personalSubscription.recurly.currentPlanDisplayPrice =
|
||||
SubscriptionFormatters.formatPriceLocalized(
|
||||
recurlySubscription.unit_amount_in_cents + addOnPrice + tax,
|
||||
recurlySubscription.currency,
|
||||
locale
|
||||
)
|
||||
const pendingTotalLicenses =
|
||||
(pendingPlan.membersLimit || 0) + pendingAdditionalLicenses
|
||||
personalSubscription.recurly.pendingAdditionalLicenses =
|
||||
@@ -333,11 +331,12 @@ async function buildUsersSubscriptionViewModel(
|
||||
personalSubscription.recurly.pendingTotalLicenses = pendingTotalLicenses
|
||||
personalSubscription.pendingPlan = pendingPlan
|
||||
} else {
|
||||
personalSubscription.recurly.displayPrice = formatPrice(
|
||||
recurlySubscription.unit_amount_in_cents + addOnPrice + tax,
|
||||
recurlySubscription.currency,
|
||||
locale
|
||||
)
|
||||
personalSubscription.recurly.displayPrice =
|
||||
SubscriptionFormatters.formatPriceLocalized(
|
||||
recurlySubscription.unit_amount_in_cents + addOnPrice + tax,
|
||||
recurlySubscription.currency,
|
||||
locale
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @import { CurrencyCode } from '../../../types/currency-code'
|
||||
* @import { CurrencyCode } from '../../../types/subscription/currency'
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -13,7 +13,7 @@
|
||||
* @param {boolean} stripIfInteger
|
||||
* @returns {string}
|
||||
*/
|
||||
function formatCurrencyLocalized(amount, currency, locale, stripIfInteger) {
|
||||
function formatCurrency(amount, currency, locale, stripIfInteger) {
|
||||
const options = { style: 'currency', currency }
|
||||
if (stripIfInteger && Number.isInteger(amount)) {
|
||||
options.minimumFractionDigits = 0
|
||||
@@ -34,5 +34,5 @@ function formatCurrencyLocalized(amount, currency, locale, stripIfInteger) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
formatCurrencyLocalized,
|
||||
formatCurrency,
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ block vars
|
||||
block append meta
|
||||
meta(name="ol-recommendedCurrency" content=recommendedCurrency)
|
||||
meta(name="ol-groupPlans" data-type="json" content=groupPlans)
|
||||
meta(name="ol-currencySymbols" data-type="json" content=groupPlanModalOptions.currencySymbols)
|
||||
meta(name="ol-itm_content" content=itm_content)
|
||||
meta(name="ol-currentView" content=currentView)
|
||||
meta(name="ol-countryCode" content=countryCode)
|
||||
|
||||
@@ -6,7 +6,6 @@ block entrypointVar
|
||||
block append meta
|
||||
meta(name="ol-recommendedCurrency" content=recommendedCurrency)
|
||||
meta(name="ol-groupPlans" data-type="json" content=groupPlans)
|
||||
meta(name="ol-currencySymbols" data-type="json" content=groupPlanModalOptions.currencySymbols)
|
||||
meta(name="ol-itm_content" content=itm_content)
|
||||
meta(name="ol-currentView" content=currentView)
|
||||
meta(name="ol-countryCode" content=countryCode)
|
||||
|
||||
+5
-5
@@ -1,6 +1,6 @@
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import { Card, ListGroup } from 'react-bootstrap-5'
|
||||
import { formatCurrencyLocalized } from '@/shared/utils/currency'
|
||||
import { formatCurrency } from '@/shared/utils/currency'
|
||||
import { formatTime } from '@/features/utils/format-date'
|
||||
import {
|
||||
AddOnUpdate,
|
||||
@@ -67,7 +67,7 @@ function CostSummary({ subscriptionChange, totalLicenses }: CostSummaryProps) {
|
||||
{t('seats')}
|
||||
</span>
|
||||
<span data-testid="price">
|
||||
{formatCurrencyLocalized(
|
||||
{formatCurrency(
|
||||
subscriptionChange.immediateCharge.subtotal,
|
||||
subscriptionChange.currency
|
||||
)}
|
||||
@@ -82,7 +82,7 @@ function CostSummary({ subscriptionChange, totalLicenses }: CostSummaryProps) {
|
||||
{subscriptionChange.nextInvoice.tax.rate * 100}%
|
||||
</span>
|
||||
<span data-testid="price">
|
||||
{formatCurrencyLocalized(
|
||||
{formatCurrency(
|
||||
subscriptionChange.immediateCharge.tax,
|
||||
subscriptionChange.currency
|
||||
)}
|
||||
@@ -94,7 +94,7 @@ function CostSummary({ subscriptionChange, totalLicenses }: CostSummaryProps) {
|
||||
>
|
||||
<strong className="me-auto">{t('total_due_today')}</strong>
|
||||
<strong data-testid="price">
|
||||
{formatCurrencyLocalized(
|
||||
{formatCurrency(
|
||||
subscriptionChange.immediateCharge.total,
|
||||
subscriptionChange.currency
|
||||
)}
|
||||
@@ -112,7 +112,7 @@ function CostSummary({ subscriptionChange, totalLicenses }: CostSummaryProps) {
|
||||
{t(
|
||||
'after_that_well_bill_you_x_annually_on_date_unless_you_cancel',
|
||||
{
|
||||
subtotal: formatCurrencyLocalized(
|
||||
subtotal: formatCurrency(
|
||||
subscriptionChange.nextInvoice.total,
|
||||
subscriptionChange.currency
|
||||
),
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ import { useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Card, Row, Col } from 'react-bootstrap-5'
|
||||
import MaterialIcon from '@/shared/components/material-icon'
|
||||
import { formatCurrencyLocalized } from '@/shared/utils/currency'
|
||||
import { formatCurrency } from '@/shared/utils/currency'
|
||||
|
||||
const LICENSE_ADD_ON = 'additional-license'
|
||||
|
||||
@@ -30,7 +30,7 @@ function UpgradeSubscriptionPlanDetails() {
|
||||
<Col>
|
||||
<span className="per-user-price" data-testid="per-user-price">
|
||||
<b>
|
||||
{formatCurrencyLocalized(
|
||||
{formatCurrency(
|
||||
licenseUnitPrice,
|
||||
preview.currency,
|
||||
getMeta('ol-i18n')?.currentLangCode ?? 'en',
|
||||
|
||||
+5
-5
@@ -1,6 +1,6 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Card, ListGroup } from 'react-bootstrap-5'
|
||||
import { formatCurrencyLocalized } from '@/shared/utils/currency'
|
||||
import { formatCurrency } from '@/shared/utils/currency'
|
||||
import { formatTime } from '@/features/utils/format-date'
|
||||
import {
|
||||
GroupPlanUpgrade,
|
||||
@@ -39,7 +39,7 @@ function UpgradeSummary({ subscriptionChange }: UpgradeSummaryProps) {
|
||||
{t('users')}
|
||||
</span>
|
||||
<span data-testid="subtotal">
|
||||
{formatCurrencyLocalized(
|
||||
{formatCurrency(
|
||||
subscriptionChange.immediateCharge.subtotal,
|
||||
subscriptionChange.currency
|
||||
)}
|
||||
@@ -48,7 +48,7 @@ function UpgradeSummary({ subscriptionChange }: UpgradeSummaryProps) {
|
||||
<ListGroup.Item className="bg-transparent border-0 px-0 gap-3 card-description-secondary">
|
||||
<span className="me-auto">{t('sales_tax')}</span>
|
||||
<span data-testid="tax">
|
||||
{formatCurrencyLocalized(
|
||||
{formatCurrency(
|
||||
subscriptionChange.immediateCharge.tax,
|
||||
subscriptionChange.currency
|
||||
)}
|
||||
@@ -57,7 +57,7 @@ function UpgradeSummary({ subscriptionChange }: UpgradeSummaryProps) {
|
||||
<ListGroup.Item className="bg-transparent border-0 px-0 gap-3 card-description-secondary">
|
||||
<strong className="me-auto">{t('total_due_today')}</strong>
|
||||
<strong data-testid="total">
|
||||
{formatCurrencyLocalized(
|
||||
{formatCurrency(
|
||||
subscriptionChange.immediateCharge.total,
|
||||
subscriptionChange.currency
|
||||
)}
|
||||
@@ -73,7 +73,7 @@ function UpgradeSummary({ subscriptionChange }: UpgradeSummaryProps) {
|
||||
</div>
|
||||
<div>
|
||||
{t('after_that_well_bill_you_x_annually_on_date_unless_you_cancel', {
|
||||
subtotal: formatCurrencyLocalized(
|
||||
subtotal: formatCurrency(
|
||||
subscriptionChange.nextInvoice.subtotal,
|
||||
subscriptionChange.currency
|
||||
),
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
import getMeta from '../../../utils/meta'
|
||||
import { swapModal } from '../../utils/swapModal'
|
||||
import * as eventTracking from '../../../infrastructure/event-tracking'
|
||||
import {
|
||||
createLocalizedGroupPlanPrice,
|
||||
formatCurrencyDefault,
|
||||
} from '../utils/group-plan-pricing'
|
||||
import { getSplitTestVariant } from '@/utils/splitTestUtils'
|
||||
import { formatCurrencyLocalized } from '@/shared/utils/currency'
|
||||
import { createLocalizedGroupPlanPrice } from '../utils/group-plan-pricing'
|
||||
|
||||
export const GROUP_PLAN_MODAL_HASH = '#groups'
|
||||
|
||||
@@ -27,18 +22,12 @@ export function updateGroupModalPlanPricing() {
|
||||
const modalEl = document.querySelector('[data-ol-group-plan-modal]')
|
||||
const { planCode, size, currency, usage } = getFormValues()
|
||||
|
||||
const localCcyVariant = getSplitTestVariant('local-ccy-format-v2')
|
||||
|
||||
const { localizedPrice, localizedPerUserPrice } =
|
||||
createLocalizedGroupPlanPrice({
|
||||
plan: planCode,
|
||||
licenseSize: size,
|
||||
currency,
|
||||
usage,
|
||||
formatCurrency:
|
||||
localCcyVariant === 'enabled'
|
||||
? formatCurrencyLocalized
|
||||
: formatCurrencyDefault,
|
||||
})
|
||||
|
||||
modalEl.querySelectorAll('[data-ol-group-plan-plan-code]').forEach(el => {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { formatCurrency } from '@/shared/utils/currency'
|
||||
import getMeta from '../../../utils/meta'
|
||||
|
||||
/**
|
||||
* @import { CurrencyCode } from '../../../../../types/currency-code'
|
||||
* @import { CurrencyCode } from '../../../../../types/subscription/currency'
|
||||
*/
|
||||
|
||||
// plan: 'collaborator' or 'professional'
|
||||
@@ -13,7 +14,6 @@ import getMeta from '../../../utils/meta'
|
||||
* @param {CurrencyCode} opts.currency
|
||||
* @param {'enterprise' | 'educational'} opts.usage
|
||||
* @param {string} [opts.locale]
|
||||
* @param {(amount: number, currency: CurrencyCode, locale: string, includeSymbol: boolean) => string} opts.formatCurrency
|
||||
* @returns {{localizedPrice: string, localizedPerUserPrice: string}}
|
||||
*/
|
||||
export function createLocalizedGroupPlanPrice({
|
||||
@@ -22,7 +22,6 @@ export function createLocalizedGroupPlanPrice({
|
||||
currency,
|
||||
usage,
|
||||
locale = getMeta('ol-i18n').currentLangCode || 'en',
|
||||
formatCurrency,
|
||||
}) {
|
||||
const groupPlans = getMeta('ol-groupPlans')
|
||||
const priceInCents =
|
||||
@@ -42,44 +41,3 @@ export function createLocalizedGroupPlanPrice({
|
||||
localizedPerUserPrice: formatPrice(perUserPrice),
|
||||
}
|
||||
}
|
||||
|
||||
const LOCALES = {
|
||||
BRL: 'pt-BR',
|
||||
MXN: 'es-MX',
|
||||
COP: 'es-CO',
|
||||
CLP: 'es-CL',
|
||||
PEN: 'es-PE',
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} amount
|
||||
* @param {string} currency
|
||||
*/
|
||||
export function formatCurrencyDefault(amount, currency) {
|
||||
const currencySymbols = getMeta('ol-currencySymbols')
|
||||
|
||||
const currencySymbol = currencySymbols[currency]
|
||||
|
||||
switch (currency) {
|
||||
case 'BRL':
|
||||
case 'MXN':
|
||||
case 'COP':
|
||||
case 'CLP':
|
||||
case 'PEN':
|
||||
// Test using toLocaleString to format currencies for new LATAM regions
|
||||
return amount.toLocaleString(LOCALES[currency], {
|
||||
style: 'currency',
|
||||
currency,
|
||||
minimumFractionDigits: Number.isInteger(amount) ? 0 : null,
|
||||
})
|
||||
case 'CHF':
|
||||
return `${currencySymbol} ${amount}`
|
||||
case 'DKK':
|
||||
case 'SEK':
|
||||
case 'NOK':
|
||||
return `${amount} ${currencySymbol}`
|
||||
default: {
|
||||
return `${currencySymbol}${amount}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-11
@@ -8,7 +8,7 @@ import {
|
||||
PremiumSubscriptionChange,
|
||||
} from '../../../../../../types/subscription/subscription-change-preview'
|
||||
import getMeta from '@/utils/meta'
|
||||
import { formatCurrencyLocalized } from '@/shared/utils/currency'
|
||||
import { formatCurrency } from '@/shared/utils/currency'
|
||||
import useAsync from '@/shared/hooks/use-async'
|
||||
import { useLocation } from '@/shared/hooks/use-location'
|
||||
import { debugConsole } from '@/utils/debugging'
|
||||
@@ -101,7 +101,7 @@ function PreviewSubscriptionChange() {
|
||||
<Col xs={9}>{changeName}</Col>
|
||||
<Col xs={3} className="text-right">
|
||||
<strong>
|
||||
{formatCurrencyLocalized(
|
||||
{formatCurrency(
|
||||
preview.immediateCharge.subtotal,
|
||||
preview.currency
|
||||
)}
|
||||
@@ -115,7 +115,7 @@ function PreviewSubscriptionChange() {
|
||||
{t('vat')} {preview.nextInvoice.tax.rate * 100}%
|
||||
</Col>
|
||||
<Col xs={3} className="text-right">
|
||||
{formatCurrencyLocalized(
|
||||
{formatCurrency(
|
||||
preview.immediateCharge.tax,
|
||||
preview.currency
|
||||
)}
|
||||
@@ -127,7 +127,7 @@ function PreviewSubscriptionChange() {
|
||||
<Col xs={9}>{t('total_today')}</Col>
|
||||
<Col xs={3} className="text-right">
|
||||
<strong>
|
||||
{formatCurrencyLocalized(
|
||||
{formatCurrency(
|
||||
preview.immediateCharge.total,
|
||||
preview.currency
|
||||
)}
|
||||
@@ -169,7 +169,7 @@ function PreviewSubscriptionChange() {
|
||||
<Row className="mt-1">
|
||||
<Col xs={9}>{preview.nextInvoice.plan.name}</Col>
|
||||
<Col xs={3} className="text-right">
|
||||
{formatCurrencyLocalized(
|
||||
{formatCurrency(
|
||||
preview.nextInvoice.plan.amount,
|
||||
preview.currency
|
||||
)}
|
||||
@@ -183,7 +183,7 @@ function PreviewSubscriptionChange() {
|
||||
{addOn.quantity > 1 ? ` ×${addOn.quantity}` : ''}
|
||||
</Col>
|
||||
<Col xs={3} className="text-right">
|
||||
{formatCurrencyLocalized(addOn.amount, preview.currency)}
|
||||
{formatCurrency(addOn.amount, preview.currency)}
|
||||
</Col>
|
||||
</Row>
|
||||
))}
|
||||
@@ -194,7 +194,7 @@ function PreviewSubscriptionChange() {
|
||||
{t('vat')} {preview.nextInvoice.tax.rate * 100}%
|
||||
</Col>
|
||||
<Col xs={3} className="text-right">
|
||||
{formatCurrencyLocalized(
|
||||
{formatCurrency(
|
||||
preview.nextInvoice.tax.amount,
|
||||
preview.currency
|
||||
)}
|
||||
@@ -209,10 +209,7 @@ function PreviewSubscriptionChange() {
|
||||
: t('total_per_month')}
|
||||
</Col>
|
||||
<Col xs={3} className="text-right">
|
||||
{formatCurrencyLocalized(
|
||||
preview.nextInvoice.total,
|
||||
preview.currency
|
||||
)}
|
||||
{formatCurrency(preview.nextInvoice.total, preview.currency)}
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
|
||||
+4
-18
@@ -21,15 +21,13 @@ import {
|
||||
import { Institution } from '../../../../../types/institution'
|
||||
import getMeta from '../../../utils/meta'
|
||||
import {
|
||||
formatCurrencyDefault,
|
||||
loadDisplayPriceWithTaxPromise,
|
||||
loadGroupDisplayPriceWithTaxPromise,
|
||||
} from '../util/recurly-pricing'
|
||||
import { isRecurlyLoaded } from '../util/is-recurly-loaded'
|
||||
import { SubscriptionDashModalIds } from '../../../../../types/subscription/dashboard/modal-ids'
|
||||
import { debugConsole } from '@/utils/debugging'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
import { formatCurrencyLocalized } from '@/shared/utils/currency'
|
||||
import { formatCurrency } from '@/shared/utils/currency'
|
||||
import { ManagedInstitution } from '../../../../../types/subscription/dashboard/managed-institution'
|
||||
import { Publisher } from '../../../../../types/subscription/dashboard/publisher'
|
||||
|
||||
@@ -141,10 +139,6 @@ export function SubscriptionDashboardProvider({
|
||||
memberGroupSubscriptions?.length > 0
|
||||
)
|
||||
|
||||
const formatCurrency = useFeatureFlag('local-ccy-format-v2')
|
||||
? formatCurrencyLocalized
|
||||
: formatCurrencyDefault
|
||||
|
||||
useEffect(() => {
|
||||
if (!isRecurlyLoaded()) {
|
||||
setRecurlyLoadError(true)
|
||||
@@ -167,8 +161,7 @@ export function SubscriptionDashboardProvider({
|
||||
plan.planCode,
|
||||
currency,
|
||||
taxRate,
|
||||
i18n.language,
|
||||
formatCurrency
|
||||
i18n.language
|
||||
)
|
||||
if (priceData?.totalAsNumber !== undefined) {
|
||||
plan.displayPrice = formatCurrency(
|
||||
@@ -186,12 +179,7 @@ export function SubscriptionDashboardProvider({
|
||||
}
|
||||
fetchPlansDisplayPrices().catch(debugConsole.error)
|
||||
}
|
||||
}, [
|
||||
personalSubscription,
|
||||
plansWithoutDisplayPrice,
|
||||
i18n.language,
|
||||
formatCurrency,
|
||||
])
|
||||
}, [personalSubscription, plansWithoutDisplayPrice, i18n.language])
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
@@ -214,8 +202,7 @@ export function SubscriptionDashboardProvider({
|
||||
taxRate,
|
||||
groupPlanToChangeToSize,
|
||||
groupPlanToChangeToUsage,
|
||||
i18n.language,
|
||||
formatCurrency
|
||||
i18n.language
|
||||
)
|
||||
} catch (e) {
|
||||
debugConsole.error(e)
|
||||
@@ -231,7 +218,6 @@ export function SubscriptionDashboardProvider({
|
||||
groupPlanToChangeToSize,
|
||||
personalSubscription,
|
||||
groupPlanToChangeToCode,
|
||||
formatCurrency,
|
||||
i18n.language,
|
||||
])
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { SubscriptionPricingState } from '@recurly/recurly-js'
|
||||
import { PriceForDisplayData } from '../../../../../types/subscription/plan'
|
||||
import {
|
||||
currencies,
|
||||
CurrencyCode,
|
||||
} from '../../../../../types/subscription/currency'
|
||||
import { CurrencyCode } from '../../../../../types/subscription/currency'
|
||||
import { getRecurlyGroupPlanCode } from './recurly-group-plan-code'
|
||||
import { debugConsole } from '@/utils/debugging'
|
||||
import { formatCurrency } from '@/shared/utils/currency'
|
||||
|
||||
function queryRecurlyPlanPrice(planCode: string, currency: CurrencyCode) {
|
||||
return new Promise(resolve => {
|
||||
@@ -23,31 +21,11 @@ function queryRecurlyPlanPrice(planCode: string, currency: CurrencyCode) {
|
||||
})
|
||||
}
|
||||
|
||||
type FormatCurrency = (
|
||||
price: number,
|
||||
currency: CurrencyCode,
|
||||
locale: string,
|
||||
stripIfInteger?: boolean
|
||||
) => string
|
||||
|
||||
export const formatCurrencyDefault: FormatCurrency = (
|
||||
price: number,
|
||||
currency: CurrencyCode,
|
||||
_locale: string,
|
||||
stripIfInteger = false
|
||||
) => {
|
||||
const currencySymbol = currencies[currency]
|
||||
const number =
|
||||
stripIfInteger && price % 1 === 0 ? Number(price) : price.toFixed(2)
|
||||
return `${currencySymbol}${number}`
|
||||
}
|
||||
|
||||
export function formatPriceForDisplayData(
|
||||
price: string,
|
||||
taxRate: number,
|
||||
currencyCode: CurrencyCode,
|
||||
locale: string,
|
||||
formatCurrency: FormatCurrency
|
||||
locale: string
|
||||
): PriceForDisplayData {
|
||||
const totalPriceExTax = parseFloat(price)
|
||||
let taxAmount = totalPriceExTax * taxRate
|
||||
@@ -69,8 +47,7 @@ function getPerUserDisplayPrice(
|
||||
totalPrice: number,
|
||||
currency: CurrencyCode,
|
||||
size: string,
|
||||
locale: string,
|
||||
formatCurrency: FormatCurrency
|
||||
locale: string
|
||||
): string {
|
||||
return formatCurrency(totalPrice / parseInt(size), currency, locale, true)
|
||||
}
|
||||
@@ -79,8 +56,7 @@ export async function loadDisplayPriceWithTaxPromise(
|
||||
planCode: string,
|
||||
currencyCode: CurrencyCode,
|
||||
taxRate: number,
|
||||
locale: string,
|
||||
formatCurrency: FormatCurrency
|
||||
locale: string
|
||||
) {
|
||||
if (!recurly) return
|
||||
|
||||
@@ -93,8 +69,7 @@ export async function loadDisplayPriceWithTaxPromise(
|
||||
price.next.total,
|
||||
taxRate,
|
||||
currencyCode,
|
||||
locale,
|
||||
formatCurrency
|
||||
locale
|
||||
)
|
||||
}
|
||||
|
||||
@@ -104,8 +79,7 @@ export async function loadGroupDisplayPriceWithTaxPromise(
|
||||
taxRate: number,
|
||||
size: string,
|
||||
usage: string,
|
||||
locale: string,
|
||||
formatCurrency: FormatCurrency
|
||||
locale: string
|
||||
) {
|
||||
if (!recurly) return
|
||||
|
||||
@@ -114,8 +88,7 @@ export async function loadGroupDisplayPriceWithTaxPromise(
|
||||
planCode,
|
||||
currencyCode,
|
||||
taxRate,
|
||||
locale,
|
||||
formatCurrency
|
||||
locale
|
||||
)
|
||||
|
||||
if (price) {
|
||||
@@ -123,8 +96,7 @@ export async function loadGroupDisplayPriceWithTaxPromise(
|
||||
price.totalAsNumber,
|
||||
currencyCode,
|
||||
size,
|
||||
locale,
|
||||
formatCurrency
|
||||
locale
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
import { updateGroupModalPlanPricing } from '../../../../features/plans/group-plan-modal'
|
||||
import '../../../../features/plans/plans-v2-group-plan-modal'
|
||||
import {
|
||||
createLocalizedGroupPlanPrice,
|
||||
formatCurrencyDefault,
|
||||
} from '../../../../features/plans/utils/group-plan-pricing'
|
||||
|
||||
import getMeta from '../../../../utils/meta'
|
||||
import { getSplitTestVariant } from '@/utils/splitTestUtils'
|
||||
import { formatCurrencyLocalized } from '@/shared/utils/currency'
|
||||
import { updateGroupModalPlanPricing } from '../../../../features/plans/group-plan-modal'
|
||||
import { createLocalizedGroupPlanPrice } from '../../../../features/plans/utils/group-plan-pricing'
|
||||
|
||||
const MINIMUM_LICENSE_SIZE_EDUCATIONAL_DISCOUNT = 10
|
||||
|
||||
@@ -26,11 +22,6 @@ export function updateMainGroupPlanPricing() {
|
||||
? 'educational'
|
||||
: 'enterprise'
|
||||
|
||||
const localCcyVariant = getSplitTestVariant('local-ccy-format-v2')
|
||||
const formatCurrency =
|
||||
localCcyVariant === 'enabled'
|
||||
? formatCurrencyLocalized
|
||||
: formatCurrencyDefault
|
||||
const {
|
||||
localizedPrice: localizedPriceProfessional,
|
||||
localizedPerUserPrice: localizedPerUserPriceProfessional,
|
||||
@@ -39,7 +30,6 @@ export function updateMainGroupPlanPricing() {
|
||||
licenseSize,
|
||||
currency,
|
||||
usage,
|
||||
formatCurrency,
|
||||
})
|
||||
|
||||
const {
|
||||
@@ -50,7 +40,6 @@ export function updateMainGroupPlanPricing() {
|
||||
licenseSize,
|
||||
currency,
|
||||
usage,
|
||||
formatCurrency,
|
||||
})
|
||||
|
||||
document.querySelector(
|
||||
|
||||
@@ -13,10 +13,6 @@ export function sendPlansViewEvent() {
|
||||
'group-tab-improvements'
|
||||
)
|
||||
|
||||
const websiteRedesignPlansTestVariant = getMeta(
|
||||
'ol-websiteRedesignPlansVariant'
|
||||
)
|
||||
|
||||
const periodToggleTestVariant = getSplitTestVariant(
|
||||
'period-toggle-improvements'
|
||||
)
|
||||
@@ -32,7 +28,6 @@ export function sendPlansViewEvent() {
|
||||
currency,
|
||||
countryCode,
|
||||
device,
|
||||
'website-redesign-plans': websiteRedesignPlansTestVariant,
|
||||
'group-tab-improvements': groupTabImprovementsVariant,
|
||||
plan: planTabParam,
|
||||
'period-toggle-improvements': periodToggleTestVariant,
|
||||
|
||||
@@ -2,7 +2,7 @@ import getMeta from '@/utils/meta'
|
||||
|
||||
const DEFAULT_LOCALE = getMeta('ol-i18n')?.currentLangCode ?? 'en'
|
||||
|
||||
export function formatCurrencyLocalized(
|
||||
export function formatCurrency(
|
||||
amount: number,
|
||||
currency: string,
|
||||
locale: string = DEFAULT_LOCALE,
|
||||
|
||||
+8
-8
@@ -344,7 +344,7 @@ describe('<ChangePlanModal />', function () {
|
||||
within(modal).getByText('Customize your group subscription')
|
||||
within(modal).getByText('Save 30% or more')
|
||||
|
||||
within(modal).getByText('$1290 per year')
|
||||
within(modal).getByText('$1,290 per year')
|
||||
expect(within(modal).getAllByText('$129 per user').length).to.equal(2)
|
||||
|
||||
within(modal).getByText('Each user will have access to:')
|
||||
@@ -432,9 +432,9 @@ describe('<ChangePlanModal />', function () {
|
||||
|
||||
within(modal).getByText('Total:', { exact: false })
|
||||
expect(
|
||||
within(modal).getAllByText('€1438.40', { exact: false }).length
|
||||
within(modal).getAllByText('€1,438.40', { exact: false }).length
|
||||
).to.equal(3)
|
||||
within(modal).getByText('(€1160.00 + €278.40 tax) per year', {
|
||||
within(modal).getByText('(€1,160.00 + €278.40 tax) per year', {
|
||||
exact: false,
|
||||
})
|
||||
})
|
||||
@@ -444,7 +444,7 @@ describe('<ChangePlanModal />', function () {
|
||||
|
||||
await openModal()
|
||||
|
||||
within(modal).getByText('$1290 per year')
|
||||
within(modal).getByText('$1,290 per year')
|
||||
within(modal).getAllByText('$129 per user')
|
||||
|
||||
// plan type (pro collab)
|
||||
@@ -468,7 +468,7 @@ describe('<ChangePlanModal />', function () {
|
||||
) as HTMLInputElement
|
||||
expect(professionalPlanRadioInput.checked).to.be.true
|
||||
|
||||
await within(modal).findByText('$2590 per year')
|
||||
await within(modal).findByText('$2,590 per year')
|
||||
await within(modal).findAllByText('$259 per user')
|
||||
|
||||
// user count
|
||||
@@ -478,7 +478,7 @@ describe('<ChangePlanModal />', function () {
|
||||
sizeSelect = within(modal).getByRole('combobox') as HTMLInputElement
|
||||
expect(sizeSelect.value).to.equal('5')
|
||||
|
||||
await within(modal).findByText('$1395 per year')
|
||||
await within(modal).findByText('$1,395 per year')
|
||||
await within(modal).findAllByText('$279 per user')
|
||||
|
||||
// usage (enterprise or educational)
|
||||
@@ -493,12 +493,12 @@ describe('<ChangePlanModal />', function () {
|
||||
expect(educationInput.checked).to.be.true
|
||||
|
||||
// make sure doesn't change price until back at min user to qualify
|
||||
await within(modal).findByText('$1395 per year')
|
||||
await within(modal).findByText('$1,395 per year')
|
||||
await within(modal).findAllByText('$279 per user')
|
||||
|
||||
await userEvent.selectOptions(sizeSelect, [screen.getByText('10')])
|
||||
|
||||
await within(modal).findByText('$1550 per year')
|
||||
await within(modal).findByText('$1,550 per year')
|
||||
await within(modal).findAllByText('$155 per user')
|
||||
})
|
||||
|
||||
|
||||
@@ -1,16 +1,9 @@
|
||||
import { expect } from 'chai'
|
||||
import { formatPriceForDisplayData } from '../../../../../frontend/js/features/subscription/util/recurly-pricing'
|
||||
import { formatCurrencyLocalized } from '@/shared/utils/currency'
|
||||
|
||||
describe('formatPriceForDisplayData', function () {
|
||||
it('should handle no tax rate', function () {
|
||||
const data = formatPriceForDisplayData(
|
||||
'1000',
|
||||
0,
|
||||
'USD',
|
||||
'en',
|
||||
formatCurrencyLocalized
|
||||
)
|
||||
const data = formatPriceForDisplayData('1000', 0, 'USD', 'en')
|
||||
expect(data).to.deep.equal({
|
||||
totalForDisplay: '$1,000',
|
||||
totalAsNumber: 1000,
|
||||
@@ -21,13 +14,7 @@ describe('formatPriceForDisplayData', function () {
|
||||
})
|
||||
|
||||
it('should handle a tax rate', function () {
|
||||
const data = formatPriceForDisplayData(
|
||||
'380',
|
||||
0.2,
|
||||
'EUR',
|
||||
'en',
|
||||
formatCurrencyLocalized
|
||||
)
|
||||
const data = formatPriceForDisplayData('380', 0.2, 'EUR', 'en')
|
||||
expect(data).to.deep.equal({
|
||||
totalForDisplay: '€456',
|
||||
totalAsNumber: 456,
|
||||
@@ -38,13 +25,7 @@ describe('formatPriceForDisplayData', function () {
|
||||
})
|
||||
|
||||
it('should handle total with cents', function () {
|
||||
const data = formatPriceForDisplayData(
|
||||
'8',
|
||||
0.2,
|
||||
'EUR',
|
||||
'en',
|
||||
formatCurrencyLocalized
|
||||
)
|
||||
const data = formatPriceForDisplayData('8', 0.2, 'EUR', 'en')
|
||||
expect(data).to.deep.equal({
|
||||
totalForDisplay: '€9.60',
|
||||
totalAsNumber: 9.6,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { expect } from 'chai'
|
||||
import { createLocalizedGroupPlanPrice } from '../../../../frontend/js/features/plans/utils/group-plan-pricing'
|
||||
import { formatCurrencyLocalized } from '@/shared/utils/currency'
|
||||
|
||||
describe('group-plan-pricing', function () {
|
||||
beforeEach(function () {
|
||||
@@ -25,11 +24,6 @@ describe('group-plan-pricing', function () {
|
||||
},
|
||||
},
|
||||
})
|
||||
window.metaAttributesCache.set('ol-currencySymbols', {
|
||||
CHF: 'Fr',
|
||||
DKK: 'kr',
|
||||
USD: '$',
|
||||
})
|
||||
window.metaAttributesCache.set('ol-i18n', { currentLangCode: 'en' })
|
||||
})
|
||||
|
||||
@@ -41,7 +35,6 @@ describe('group-plan-pricing', function () {
|
||||
currency: 'CHF',
|
||||
licenseSize: '2',
|
||||
usage: 'enterprise',
|
||||
formatCurrency: formatCurrencyLocalized,
|
||||
})
|
||||
|
||||
expect(localizedGroupPlanPrice).to.deep.equal({
|
||||
@@ -57,7 +50,6 @@ describe('group-plan-pricing', function () {
|
||||
currency: 'DKK',
|
||||
licenseSize: '2',
|
||||
usage: 'enterprise',
|
||||
formatCurrency: formatCurrencyLocalized,
|
||||
})
|
||||
|
||||
expect(localizedGroupPlanPrice).to.deep.equal({
|
||||
@@ -73,7 +65,6 @@ describe('group-plan-pricing', function () {
|
||||
currency: 'USD',
|
||||
licenseSize: '2',
|
||||
usage: 'enterprise',
|
||||
formatCurrency: formatCurrencyLocalized,
|
||||
})
|
||||
|
||||
expect(localizedGroupPlanPrice).to.deep.equal({
|
||||
|
||||
@@ -176,7 +176,7 @@ describe('SubscriptionController', function () {
|
||||
},
|
||||
'../../infrastructure/Features': this.Features,
|
||||
'../../util/currency': (this.currency = {
|
||||
formatCurrencyLocalized: sinon.stub(),
|
||||
formatCurrency: sinon.stub(),
|
||||
}),
|
||||
},
|
||||
})
|
||||
@@ -380,26 +380,10 @@ describe('SubscriptionController', function () {
|
||||
})
|
||||
})
|
||||
|
||||
describe('localCcyAssignment', function () {
|
||||
it('uses formatCurrencyLocalized when variant is enabled', function (done) {
|
||||
this.SplitTestV2Hander.promises.getAssignment
|
||||
.withArgs(this.req, this.res, 'local-ccy-format-v2')
|
||||
.resolves({
|
||||
variant: 'enabled',
|
||||
})
|
||||
describe('formatCurrency data', function () {
|
||||
it('return correct formatCurrency function', function (done) {
|
||||
this.res.render = (page, opts) => {
|
||||
expect(opts.formatCurrency).to.equal(
|
||||
this.currency.formatCurrencyLocalized
|
||||
)
|
||||
done()
|
||||
}
|
||||
this.SubscriptionController.plansPage(this.req, this.res)
|
||||
})
|
||||
it('uses formatCurrencyDefault when variant is default', function (done) {
|
||||
this.res.render = (page, opts) => {
|
||||
expect(opts.formatCurrency).to.equal(
|
||||
this.SubscriptionHelper.formatCurrencyDefault
|
||||
)
|
||||
expect(opts.formatCurrency).to.equal(this.currency.formatCurrency)
|
||||
done()
|
||||
}
|
||||
this.SubscriptionController.plansPage(this.req, this.res)
|
||||
@@ -698,26 +682,10 @@ describe('SubscriptionController', function () {
|
||||
})
|
||||
})
|
||||
|
||||
describe('localCcyAssignment', function () {
|
||||
it('uses formatCurrencyLocalized when variant is enabled', function (done) {
|
||||
this.SplitTestV2Hander.promises.getAssignment
|
||||
.withArgs(this.req, this.res, 'local-ccy-format-v2')
|
||||
.resolves({
|
||||
variant: 'enabled',
|
||||
})
|
||||
describe('formatCurrency data', function () {
|
||||
it('return correct formatCurrency function', function (done) {
|
||||
this.res.render = (page, opts) => {
|
||||
expect(opts.formatCurrency).to.equal(
|
||||
this.currency.formatCurrencyLocalized
|
||||
)
|
||||
done()
|
||||
}
|
||||
this.SubscriptionController.plansPageLightDesign(this.req, this.res)
|
||||
})
|
||||
it('uses formatCurrencyDefault when variant is default', function (done) {
|
||||
this.res.render = (page, opts) => {
|
||||
expect(opts.formatCurrency).to.equal(
|
||||
this.SubscriptionHelper.formatCurrencyDefault
|
||||
)
|
||||
expect(opts.formatCurrency).to.equal(this.currency.formatCurrency)
|
||||
done()
|
||||
}
|
||||
this.SubscriptionController.plansPageLightDesign(this.req, this.res)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
const SandboxedModule = require('sandboxed-module')
|
||||
const { expect } = require('chai')
|
||||
const { formatCurrencyLocalized } = require('../../../../app/src/util/currency')
|
||||
const modulePath =
|
||||
'../../../../app/src/Features/Subscription/SubscriptionHelper'
|
||||
|
||||
@@ -34,15 +33,7 @@ describe('SubscriptionHelper', function () {
|
||||
beforeEach(function () {
|
||||
this.INITIAL_LICENSE_SIZE = 2
|
||||
this.settings = {
|
||||
groupPlanModalOptions: {
|
||||
currencySymbols: {
|
||||
USD: '$',
|
||||
CHF: 'Fr',
|
||||
DKK: 'kr',
|
||||
NOK: 'kr',
|
||||
SEK: 'kr',
|
||||
},
|
||||
},
|
||||
groupPlanModalOptions: {},
|
||||
}
|
||||
this.GroupPlansData = {
|
||||
enterprise: {
|
||||
@@ -154,8 +145,7 @@ describe('SubscriptionHelper', function () {
|
||||
const localizedPrice =
|
||||
this.SubscriptionHelper.generateInitialLocalizedGroupPrice(
|
||||
'CHF',
|
||||
'fr',
|
||||
formatCurrencyLocalized
|
||||
'fr'
|
||||
)
|
||||
|
||||
expect(localizedPrice).to.deep.equal({
|
||||
@@ -176,8 +166,7 @@ describe('SubscriptionHelper', function () {
|
||||
const localizedPrice =
|
||||
this.SubscriptionHelper.generateInitialLocalizedGroupPrice(
|
||||
'DKK',
|
||||
'da',
|
||||
formatCurrencyLocalized
|
||||
'da'
|
||||
)
|
||||
|
||||
expect(localizedPrice).to.deep.equal({
|
||||
@@ -198,8 +187,7 @@ describe('SubscriptionHelper', function () {
|
||||
const localizedPrice =
|
||||
this.SubscriptionHelper.generateInitialLocalizedGroupPrice(
|
||||
'SEK',
|
||||
'sv',
|
||||
formatCurrencyLocalized
|
||||
'sv'
|
||||
)
|
||||
|
||||
expect(localizedPrice).to.deep.equal({
|
||||
@@ -222,8 +210,7 @@ describe('SubscriptionHelper', function () {
|
||||
'NOK',
|
||||
// there seem to be possible inconsistencies with the CI
|
||||
// maybe it depends on what languages are installed on the server?
|
||||
'en',
|
||||
formatCurrencyLocalized
|
||||
'en'
|
||||
)
|
||||
|
||||
expect(localizedPrice).to.deep.equal({
|
||||
@@ -244,8 +231,7 @@ describe('SubscriptionHelper', function () {
|
||||
const localizedPrice =
|
||||
this.SubscriptionHelper.generateInitialLocalizedGroupPrice(
|
||||
'USD',
|
||||
'en',
|
||||
formatCurrencyLocalized
|
||||
'en'
|
||||
)
|
||||
|
||||
expect(localizedPrice).to.deep.equal({
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export type { CurrencyCode } from './subscription/currency'
|
||||
@@ -20,4 +20,3 @@ export const currencies = <const>{
|
||||
|
||||
type Currency = typeof currencies
|
||||
export type CurrencyCode = keyof Currency
|
||||
export type CurrencySymbol = Currency[CurrencyCode]
|
||||
|
||||
@@ -2,7 +2,7 @@ import countries from '@/features/subscription/data/countries'
|
||||
import { Plan } from './plan'
|
||||
import { SubscriptionPricingStateTax } from 'recurly__recurly-js'
|
||||
import { SubscriptionPricingInstanceCustom } from '../recurly/pricing/subscription'
|
||||
import { currencies, CurrencyCode, CurrencySymbol } from './currency'
|
||||
import { currencies, CurrencyCode } from './currency'
|
||||
|
||||
export type PricingFormState = {
|
||||
first_name: string
|
||||
@@ -23,7 +23,6 @@ export type PaymentContextValue = {
|
||||
setCurrencyCode: React.Dispatch<
|
||||
React.SetStateAction<PaymentContextValue['currencyCode']>
|
||||
>
|
||||
currencySymbol: CurrencySymbol
|
||||
limitedCurrencies: Partial<typeof currencies>
|
||||
pricingFormState: PricingFormState
|
||||
setPricingFormState: React.Dispatch<
|
||||
|
||||
Reference in New Issue
Block a user