mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-17 23:44:39 -05:00
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.
This commit is contained in:
parent
b751c1c41e
commit
ccde2519a8
6 changed files with 22 additions and 32 deletions
|
@ -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 (
|
return (
|
||||||
<div className='gh-portal-plan-pricelabel'>
|
<div className='gh-portal-plan-pricelabel'>
|
||||||
<span className='gh-portal-plan-currency'>{currency}</span>
|
<span className={currencyClass}>{currencySymbol}</span>
|
||||||
<span className='gh-portal-plan-price'>{price}</span>
|
<span className='gh-portal-plan-price'>{price}</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -254,7 +256,7 @@ function PlanOptions({plans, selectedPlan, onPlanSelect, changePlan}) {
|
||||||
const hasMonthlyPlan = plans.some(({name}) => {
|
const hasMonthlyPlan = plans.some(({name}) => {
|
||||||
return name === 'Monthly';
|
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 isChecked = selectedPlan === name;
|
||||||
const classes = (isChecked ? 'gh-portal-plan-section checked' : 'gh-portal-plan-section');
|
const classes = (isChecked ? 'gh-portal-plan-section checked' : 'gh-portal-plan-section');
|
||||||
const planDetails = {};
|
const planDetails = {};
|
||||||
|
@ -279,7 +281,7 @@ function PlanOptions({plans, selectedPlan, onPlanSelect, changePlan}) {
|
||||||
<div className={classes} key={name} onClick={e => onPlanSelect(e, name)}>
|
<div className={classes} key={name} onClick={e => onPlanSelect(e, name)}>
|
||||||
<Checkbox name={name} isChecked={isChecked} onPlanSelect={onPlanSelect} />
|
<Checkbox name={name} isChecked={isChecked} onPlanSelect={onPlanSelect} />
|
||||||
<h4 className='gh-portal-plan-name'>{displayName || name}</h4>
|
<h4 className='gh-portal-plan-name'>{displayName || name}</h4>
|
||||||
<PriceLabel name={name} currency={currency} price={price} />
|
<PriceLabel name={name} currencySymbol={currencySymbol} price={price} />
|
||||||
<div className='gh-portal-plan-featurewrapper'>
|
<div className='gh-portal-plan-featurewrapper'>
|
||||||
<div className='gh-portal-plan-feature'>
|
<div className='gh-portal-plan-feature'>
|
||||||
{planDetails.feature}
|
{planDetails.feature}
|
||||||
|
|
|
@ -6,9 +6,9 @@ const setup = (overrides = {}) => {
|
||||||
const mockOnPlanSelectFn = jest.fn();
|
const mockOnPlanSelectFn = jest.fn();
|
||||||
const props = {
|
const props = {
|
||||||
plans: [
|
plans: [
|
||||||
{type: 'free', price: 'Decide later', name: 'Free'},
|
{type: 'free', price: 'Decide later', currency_symbol: '$', name: 'Free'},
|
||||||
{type: 'month', price: 12, currency: '$', name: 'Monthly'},
|
{type: 'month', price: 12, currency_symbol: '$', name: 'Monthly'},
|
||||||
{type: 'year', price: 110, currency: '$', name: 'Yearly'}
|
{type: 'year', price: 110, currency_symbol: '$', name: 'Yearly'}
|
||||||
],
|
],
|
||||||
selectedPlan: 'Monthly',
|
selectedPlan: 'Monthly',
|
||||||
onPlanSelect: mockOnPlanSelectFn
|
onPlanSelect: mockOnPlanSelectFn
|
||||||
|
|
|
@ -132,8 +132,8 @@ const UserHeader = ({member, brandColor}) => {
|
||||||
|
|
||||||
const PaidAccountActions = ({member, site, openUpdatePlan, onEditBilling}) => {
|
const PaidAccountActions = ({member, site, openUpdatePlan, onEditBilling}) => {
|
||||||
const PlanLabel = ({plan, isComplimentary}) => {
|
const PlanLabel = ({plan, isComplimentary}) => {
|
||||||
const {amount = 0, currency_symbol: currencySymbol = '$', interval} = plan;
|
const {amount = 0, currency, interval} = plan;
|
||||||
let label = `${currencySymbol}${amount / 100}/${interval}`;
|
let label = `${Intl.NumberFormat('en', {currency, style: 'currency'}).format(amount / 100)}/${interval}`;
|
||||||
if (isComplimentary) {
|
if (isComplimentary) {
|
||||||
label = `Complimentary (${label})`;
|
label = `Complimentary (${label})`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -266,20 +266,20 @@ class SignupPage extends React.Component {
|
||||||
{
|
{
|
||||||
type: 'month',
|
type: 'month',
|
||||||
price: plans.monthly,
|
price: plans.monthly,
|
||||||
currency: plans.currency_symbol,
|
currency_symbol: plans.currency_symbol,
|
||||||
name: 'Monthly'
|
name: 'Monthly'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'year',
|
type: 'year',
|
||||||
price: plans.yearly,
|
price: plans.yearly,
|
||||||
currency: plans.currency_symbol,
|
currency_symbol: plans.currency_symbol,
|
||||||
name: 'Yearly',
|
name: 'Yearly',
|
||||||
discount
|
discount
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
if (allowSelfSignup && (portalPlans === undefined || portalPlans.includes('free'))) {
|
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') {
|
if (isStripeConfigured && pageQuery !== 'free') {
|
||||||
|
|
|
@ -8,8 +8,7 @@ export const site = {
|
||||||
plans: {
|
plans: {
|
||||||
monthly: 5,
|
monthly: 5,
|
||||||
yearly: 15,
|
yearly: 15,
|
||||||
currency: 'USD',
|
currency: 'USD'
|
||||||
currency_symbol: '$'
|
|
||||||
},
|
},
|
||||||
allow_self_signup: true,
|
allow_self_signup: true,
|
||||||
is_stripe_configured: true,
|
is_stripe_configured: true,
|
||||||
|
@ -52,8 +51,7 @@ export const member = {
|
||||||
nickname: 'Yearly',
|
nickname: 'Yearly',
|
||||||
interval: 'year',
|
interval: 'year',
|
||||||
amount: 1500,
|
amount: 1500,
|
||||||
currency: 'USD',
|
currency: 'USD'
|
||||||
currency_symbol: '$'
|
|
||||||
},
|
},
|
||||||
status: 'active',
|
status: 'active',
|
||||||
start_date: '2019-05-01T11:42:40.000Z',
|
start_date: '2019-05-01T11:42:40.000Z',
|
||||||
|
@ -82,8 +80,7 @@ export const member = {
|
||||||
nickname: 'Complimentary',
|
nickname: 'Complimentary',
|
||||||
amount: 0,
|
amount: 0,
|
||||||
interval: 'year',
|
interval: 'year',
|
||||||
currency: 'USD',
|
currency: 'USD'
|
||||||
currency_symbol: '$'
|
|
||||||
},
|
},
|
||||||
status: 'active',
|
status: 'active',
|
||||||
start_date: '2020-09-03T11:12:37.000Z',
|
start_date: '2020-09-03T11:12:37.000Z',
|
||||||
|
@ -112,8 +109,7 @@ export const member = {
|
||||||
nickname: 'Yearly',
|
nickname: 'Yearly',
|
||||||
interval: 'year',
|
interval: 'year',
|
||||||
amount: 500,
|
amount: 500,
|
||||||
currency: 'USD',
|
currency: 'USD'
|
||||||
currency_symbol: '$'
|
|
||||||
},
|
},
|
||||||
status: 'active',
|
status: 'active',
|
||||||
start_date: '2019-05-01T11:42:40.000Z',
|
start_date: '2019-05-01T11:42:40.000Z',
|
||||||
|
|
|
@ -124,13 +124,13 @@ export function getSitePlans({site = {}, includeFree = true, pageQuery} = {}) {
|
||||||
{
|
{
|
||||||
type: 'month',
|
type: 'month',
|
||||||
price: plans.monthly,
|
price: plans.monthly,
|
||||||
currency: plans.currency_symbol,
|
currency_symbol: getCurrencySymbol(plans.currency),
|
||||||
name: 'Monthly'
|
name: 'Monthly'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'year',
|
type: 'year',
|
||||||
price: plans.yearly,
|
price: plans.yearly,
|
||||||
currency: plans.currency_symbol,
|
currency_symbol: getCurrencySymbol(plans.currency),
|
||||||
name: 'Yearly',
|
name: 'Yearly',
|
||||||
discount
|
discount
|
||||||
}
|
}
|
||||||
|
@ -140,7 +140,7 @@ export function getSitePlans({site = {}, includeFree = true, pageQuery} = {}) {
|
||||||
plansData.push({
|
plansData.push({
|
||||||
type: 'free',
|
type: 'free',
|
||||||
price: 0,
|
price: 0,
|
||||||
currency: plans.currency_symbol,
|
currency_symbol: getCurrencySymbol(plans.currency),
|
||||||
name: 'Free'
|
name: 'Free'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -188,15 +188,7 @@ export const getSiteDomain = ({site}) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getCurrencySymbol = (currency) => {
|
export const getCurrencySymbol = (currency) => {
|
||||||
const CURRENCY_SYMBOLS = {
|
return Intl.NumberFormat('en', {currency, style: 'currency'}).format(0).replace(/[\d\s.]/g, '');
|
||||||
USD: '$',
|
|
||||||
AUD: '$',
|
|
||||||
CAD: '$',
|
|
||||||
GBP: '£',
|
|
||||||
EUR: '€',
|
|
||||||
INR: '₹'
|
|
||||||
};
|
|
||||||
return CURRENCY_SYMBOLS[currency] || '';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createPopupNotification = ({type, status, autoHide, duration, closeable, state, message, meta = {}}) => {
|
export const createPopupNotification = ({type, status, autoHide, duration, closeable, state, message, meta = {}}) => {
|
||||||
|
|
Loading…
Add table
Reference in a new issue