From ccde2519a8b8e2c0345cb45256bf7bac3ca713b9 Mon Sep 17 00:00:00 2001 From: Fabien 'egg' O'Carroll Date: Thu, 25 Feb 2021 09:58:19 +0000 Subject: [PATCH] Used `Intl.NumberFormat` to determine currency symbol (#128) refs https://github.com/TryGhost/Team/issues/473 refs https://github.com/TryGhost/Ghost/pull/12700/commits/006cf434 Ghost no longer sends back currency symbols from the API, so we calculate the currency symbol using `Intl.NumberFormat`. We've also renamed the `currency` property to `currency_symbol` - as it does not store a currency. Depending on currency and locale, currency symbols can be the currency ISO code (e.g. AED). In order to style these differently we add a different class to the element. --- .../portal/src/components/common/PlansSection.js | 10 ++++++---- .../src/components/common/PlansSection.test.js | 6 +++--- .../src/components/pages/AccountHomePage.js | 4 ++-- ghost/portal/src/components/pages/SignupPage.js | 6 +++--- ghost/portal/src/utils/fixtures.js | 12 ++++-------- ghost/portal/src/utils/helpers.js | 16 ++++------------ 6 files changed, 22 insertions(+), 32 deletions(-) diff --git a/ghost/portal/src/components/common/PlansSection.js b/ghost/portal/src/components/common/PlansSection.js index b606750f08..50038f123c 100644 --- a/ghost/portal/src/components/common/PlansSection.js +++ b/ghost/portal/src/components/common/PlansSection.js @@ -241,10 +241,12 @@ function Checkbox({name, onPlanSelect, isChecked, disabled}) { ); } -function PriceLabel({currency, price}) { +function PriceLabel({currencySymbol, price}) { + const isSymbol = currencySymbol.length !== 3; + const currencyClass = isSymbol ? 'gh-portal-plan-currency gh-portal-plan-currency-symbol' : 'gh-portal-plan-currency gh-portal-plan-currency-code'; return (
- {currency} + {currencySymbol} {price}
); @@ -254,7 +256,7 @@ function PlanOptions({plans, selectedPlan, onPlanSelect, changePlan}) { const hasMonthlyPlan = plans.some(({name}) => { return name === 'Monthly'; }); - return plans.map(({name, currency, price, discount}, i) => { + return plans.map(({name, currency_symbol: currencySymbol, price, discount}, i) => { const isChecked = selectedPlan === name; const classes = (isChecked ? 'gh-portal-plan-section checked' : 'gh-portal-plan-section'); const planDetails = {}; @@ -279,7 +281,7 @@ function PlanOptions({plans, selectedPlan, onPlanSelect, changePlan}) {
onPlanSelect(e, name)}>

{displayName || name}

- +
{planDetails.feature} diff --git a/ghost/portal/src/components/common/PlansSection.test.js b/ghost/portal/src/components/common/PlansSection.test.js index 6f2e535996..e291f4a651 100644 --- a/ghost/portal/src/components/common/PlansSection.test.js +++ b/ghost/portal/src/components/common/PlansSection.test.js @@ -6,9 +6,9 @@ const setup = (overrides = {}) => { const mockOnPlanSelectFn = jest.fn(); const props = { plans: [ - {type: 'free', price: 'Decide later', name: 'Free'}, - {type: 'month', price: 12, currency: '$', name: 'Monthly'}, - {type: 'year', price: 110, currency: '$', name: 'Yearly'} + {type: 'free', price: 'Decide later', currency_symbol: '$', name: 'Free'}, + {type: 'month', price: 12, currency_symbol: '$', name: 'Monthly'}, + {type: 'year', price: 110, currency_symbol: '$', name: 'Yearly'} ], selectedPlan: 'Monthly', onPlanSelect: mockOnPlanSelectFn diff --git a/ghost/portal/src/components/pages/AccountHomePage.js b/ghost/portal/src/components/pages/AccountHomePage.js index 5ef5df14ef..7964ab4b29 100644 --- a/ghost/portal/src/components/pages/AccountHomePage.js +++ b/ghost/portal/src/components/pages/AccountHomePage.js @@ -132,8 +132,8 @@ const UserHeader = ({member, brandColor}) => { const PaidAccountActions = ({member, site, openUpdatePlan, onEditBilling}) => { const PlanLabel = ({plan, isComplimentary}) => { - const {amount = 0, currency_symbol: currencySymbol = '$', interval} = plan; - let label = `${currencySymbol}${amount / 100}/${interval}`; + const {amount = 0, currency, interval} = plan; + let label = `${Intl.NumberFormat('en', {currency, style: 'currency'}).format(amount / 100)}/${interval}`; if (isComplimentary) { label = `Complimentary (${label})`; } diff --git a/ghost/portal/src/components/pages/SignupPage.js b/ghost/portal/src/components/pages/SignupPage.js index 168b37113c..078d968de2 100644 --- a/ghost/portal/src/components/pages/SignupPage.js +++ b/ghost/portal/src/components/pages/SignupPage.js @@ -266,20 +266,20 @@ class SignupPage extends React.Component { { type: 'month', price: plans.monthly, - currency: plans.currency_symbol, + currency_symbol: plans.currency_symbol, name: 'Monthly' }, { type: 'year', price: plans.yearly, - currency: plans.currency_symbol, + currency_symbol: plans.currency_symbol, name: 'Yearly', discount } ]; if (allowSelfSignup && (portalPlans === undefined || portalPlans.includes('free'))) { - plansData.push({type: 'free', price: 0, currency: plans.currency_symbol, name: 'Free'}); + plansData.push({type: 'free', price: 0, currency_symbol: plans.currency_symbol, name: 'Free'}); } if (isStripeConfigured && pageQuery !== 'free') { diff --git a/ghost/portal/src/utils/fixtures.js b/ghost/portal/src/utils/fixtures.js index 1746a3998f..4331f2888d 100644 --- a/ghost/portal/src/utils/fixtures.js +++ b/ghost/portal/src/utils/fixtures.js @@ -8,8 +8,7 @@ export const site = { plans: { monthly: 5, yearly: 15, - currency: 'USD', - currency_symbol: '$' + currency: 'USD' }, allow_self_signup: true, is_stripe_configured: true, @@ -52,8 +51,7 @@ export const member = { nickname: 'Yearly', interval: 'year', amount: 1500, - currency: 'USD', - currency_symbol: '$' + currency: 'USD' }, status: 'active', start_date: '2019-05-01T11:42:40.000Z', @@ -82,8 +80,7 @@ export const member = { nickname: 'Complimentary', amount: 0, interval: 'year', - currency: 'USD', - currency_symbol: '$' + currency: 'USD' }, status: 'active', start_date: '2020-09-03T11:12:37.000Z', @@ -112,8 +109,7 @@ export const member = { nickname: 'Yearly', interval: 'year', amount: 500, - currency: 'USD', - currency_symbol: '$' + currency: 'USD' }, status: 'active', start_date: '2019-05-01T11:42:40.000Z', diff --git a/ghost/portal/src/utils/helpers.js b/ghost/portal/src/utils/helpers.js index 1bbaa25c7f..fc14ba36f6 100644 --- a/ghost/portal/src/utils/helpers.js +++ b/ghost/portal/src/utils/helpers.js @@ -124,13 +124,13 @@ export function getSitePlans({site = {}, includeFree = true, pageQuery} = {}) { { type: 'month', price: plans.monthly, - currency: plans.currency_symbol, + currency_symbol: getCurrencySymbol(plans.currency), name: 'Monthly' }, { type: 'year', price: plans.yearly, - currency: plans.currency_symbol, + currency_symbol: getCurrencySymbol(plans.currency), name: 'Yearly', discount } @@ -140,7 +140,7 @@ export function getSitePlans({site = {}, includeFree = true, pageQuery} = {}) { plansData.push({ type: 'free', price: 0, - currency: plans.currency_symbol, + currency_symbol: getCurrencySymbol(plans.currency), name: 'Free' }); } @@ -188,15 +188,7 @@ export const getSiteDomain = ({site}) => { }; export const getCurrencySymbol = (currency) => { - const CURRENCY_SYMBOLS = { - USD: '$', - AUD: '$', - CAD: '$', - GBP: '£', - EUR: '€', - INR: '₹' - }; - return CURRENCY_SYMBOLS[currency] || ''; + return Intl.NumberFormat('en', {currency, style: 'currency'}).format(0).replace(/[\d\s.]/g, ''); }; export const createPopupNotification = ({type, status, autoHide, duration, closeable, state, message, meta = {}}) => {