Files
overleaf-cep/services/web/app/src/Features/Subscription/SubscriptionFormatters.js
T
Antoine Clausse 7ed5000e29 [web] Use localized number formatting for currencies (#17622)
* Add a unit test on `SubscriptionFormatters.formatPrice`

* Add JSDoc to `formatPrice`

Also: Name the functions before exporting:
This fixes my IDE (WebStorm) navigation

* Make `'USD'` the default param instead of reassigning

* Create `formatCurrency` function

* Use `formatCurrency` in SubscriptionFormatters

* Use an `isNoCentsCurrency` logic for `CLP` `JPY` `KRW` `VND`

And remove custom `CLP` logic and locale

* Add `locale` param to `formatPrice`

* Generate `groups.json` and `localizedPlanPricing.json`

```
bin/exec web node ./scripts/recurly/recurly_prices.js --download -o prices.json
bin/exec web node ./scripts/plan-prices/plans.js -f ../../prices.json -o dir
```

* Update scripts/plan-prices/plans.js to generate numbers instead of localized amounts

* Generate `groups.json` and `localizedPlanPricing.json`

```
bin/exec web node ./scripts/recurly/recurly_prices.js --download -o prices.json
bin/exec web node ./scripts/plan-prices/plans.js -f ../../prices.json -o dir
```

* Remove generation of `plans.json`

As /services/web/frontend/js/main/plans.js was removed in https://github.com/overleaf/internal/pull/12593

* Sort currencies in alphabetical order in scripts/plan-prices/plans.js

* Generate `groups.json` and `localizedPlanPricing.json`

```
bin/exec web node ./scripts/recurly/recurly_prices.js --download -o prices.json
bin/exec web node ./scripts/plan-prices/plans.js -f ../../prices.json -o dir
```

* Use `formatCurrency` in price-summary.tsx

* Use `formatCurrency` in Subscription Pug files

* Fix unit tests SubscriptionHelperTests.js

* Remove unused `currencySymbol`

* Change to `formatCurrency` in other React components

* Add `CurrencyCode` JSDoc types

* Duplicate `formatCurrency` into services/web/app/src/util

* Wrap tests in a top-level describe block

* Use `narrowSymbol`

* Fix tests with `narrowSymbol` expects

* Revert deletion of old `formatPrice` in SubscriptionFormatters.js

* Rename `formatCurrency` -> `formatCurrencyLocalized`

* Revert deletion of `CurrencySymbol`

* Add split-test in SubscriptionController.js

* Add split-test in SubscriptionViewModelBuilder.js

* Add split-test in plans

* Add split-test in subscription-dashboard-context.tsx

* Add split-test in 4 more components

* Update tests

* Show currency and payment methods in interstitial page

* Fix `–` being printed. Use `–` instead

* Fix test with NOK

* Storybook: Fix missing `SplitTestProvider`

* Storybook: Revert "Remove unused `currencySymbol`"

This reverts commit e55387d4753f97bbf8e39e0fdc3ad17312122aaa.

* Replace `getSplitTestVariant` by `useSplitTestContext`

* Use parameterize currencyFormat in `generateInitialLocalizedGroupPrice`

* Fixup import paths of `formatCurrencyLocalized`

* Replace `% 1 === 0` by `Number.isInteger`

* Add comment explaining that any combinations of languages/currencies could happen

* Fixup after rebase: import `useSplitTestContext`

* Revert "Remove SplitTestProvider from subscription root"

This reverts commit be9f378fda715b86589ab0759737581c72321d87.

* Revert "Remove split test provider from some tests"

This reverts commit 985522932b550cfd38fa6a4f4c3d2ebaee6ff7df.

GitOrigin-RevId: 59a83cbbe0f7cc7e45f189c654e23fcf9bfa37af
2024-04-19 08:03:54 +00:00

83 lines
1.9 KiB
JavaScript

const dateformat = require('dateformat')
const { formatCurrencyLocalized } = require('../../util/currency')
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}`
}
/**
* @typedef {import('@/shared/utils/currency').CurrencyCode} CurrencyCode
*/
/**
* @param {number} priceInCents - price in the smallest currency unit (e.g. dollar cents, CLP units, ...)
* @param {CurrencyCode?} currency - currency code (default to USD)
* @param {string} [locale] - locale string
* @returns {string} - formatted price
*/
function formatPriceLocalized(priceInCents, currency = 'USD', locale) {
const isNoCentsCurrency = ['CLP', 'JPY', 'KRW', 'VND'].includes(currency)
const priceInCurrencyUnit = isNoCentsCurrency
? priceInCents
: priceInCents / 100
return formatCurrencyLocalized(priceInCurrencyUnit, currency, locale)
}
function formatDate(date) {
if (!date) {
return null
}
return dateformat(date, 'mmmm dS, yyyy h:MM TT Z', true)
}
module.exports = {
formatPriceDefault,
formatPriceLocalized,
formatDate,
}