diff --git a/ghost/admin/app/components/gh-members-payments-setting.hbs b/ghost/admin/app/components/gh-members-payments-setting.hbs index 16e86af61a..3f262c9ecd 100644 --- a/ghost/admin/app/components/gh-members-payments-setting.hbs +++ b/ghost/admin/app/components/gh-members-payments-setting.hbs @@ -56,7 +56,7 @@ {{else}} - +
diff --git a/ghost/admin/app/components/gh-members-payments-setting.js b/ghost/admin/app/components/gh-members-payments-setting.js index c41a97205f..9cb55fb990 100644 --- a/ghost/admin/app/components/gh-members-payments-setting.js +++ b/ghost/admin/app/components/gh-members-payments-setting.js @@ -1,30 +1,10 @@ import Component from '@ember/component'; import {computed} from '@ember/object'; +import {currencies} from 'ghost-admin/utils/currency'; import {reads} from '@ember/object/computed'; import {inject as service} from '@ember/service'; import {task} from 'ember-concurrency'; -export const CURRENCIES = [ - { - label: 'USD - US Dollar', value: 'usd', symbol: '$' - }, - { - label: 'AUD - Australian Dollar', value: 'aud', symbol: '$' - }, - { - label: 'CAD - Canadian Dollar', value: 'cad', symbol: '$' - }, - { - label: 'EUR - Euro', value: 'eur', symbol: '€' - }, - { - label: 'GBP - British Pound', value: 'gbp', symbol: '£' - }, - { - label: 'INR - Indian Rupee', value: 'inr', symbol: '₹' - } -]; - export default Component.extend({ feature: service(), config: service(), @@ -47,7 +27,7 @@ export default Component.extend({ stripeDirect: reads('config.stripeDirect'), allowSelfSignup: reads('settings.membersAllowFreeSignup'), - + /** OLD **/ stripeDirectPublicKey: reads('settings.stripePublishableKey'), stripeDirectSecretKey: reads('settings.stripeSecretKey'), @@ -59,7 +39,7 @@ export default Component.extend({ portalSettingsBorderColor: reads('settings.accentColor'), selectedCurrency: computed('stripePlans.monthly.currency', function () { - return CURRENCIES.findBy('value', this.get('stripePlans.monthly.currency')); + return this.get('currencies').findBy('value', this.get('stripePlans.monthly.currency')); }), blogDomain: computed('config.blogDomain', function () { @@ -87,7 +67,13 @@ export default Component.extend({ init() { this._super(...arguments); - this.set('currencies', CURRENCIES); + this.set('currencies', currencies.map((currency) => { + return { + value: currency.isoCode.toLowerCase(), + label: `${currency.isoCode} - ${currency.name}`, + isoCode: currency.isoCode + }; + })); if (this.get('stripeConnectAccountId')) { this.set('membersStripeOpen', false); } else { @@ -124,45 +110,7 @@ export default Component.extend({ }, validateStripePlans() { - this.get('settings.errors').remove('stripePlans'); - this.get('settings.hasValidated').removeObject('stripePlans'); - - if (this._scratchStripeYearlyAmount === null) { - this._scratchStripeYearlyAmount = this.get('stripePlans').yearly.amount; - } - if (this._scratchStripeMonthlyAmount === null) { - this._scratchStripeMonthlyAmount = this.get('stripePlans').monthly.amount; - } - - try { - const selectedCurrency = this.selectedCurrency; - const yearlyAmount = parseInt(this._scratchStripeYearlyAmount); - const monthlyAmount = parseInt(this._scratchStripeMonthlyAmount); - if (!yearlyAmount || yearlyAmount < 1 || !monthlyAmount || monthlyAmount < 1) { - throw new TypeError(`Subscription amount must be at least ${selectedCurrency.symbol}1.00`); - } - - const updatedPlans = this.get('settings.stripePlans').map((plan) => { - if (plan.name !== 'Complimentary') { - let newAmount; - if (plan.interval === 'year') { - newAmount = yearlyAmount * 100; - } else if (plan.interval === 'month') { - newAmount = monthlyAmount * 100; - } - return Object.assign({}, plan, { - amount: newAmount - }); - } - return plan; - }); - - this.set('settings.stripePlans', updatedPlans); - } catch (err) { - this.get('settings.errors').add('stripePlans', err.message); - } finally { - this.get('settings.hasValidated').pushObject('stripePlans'); - } + this.validateStripePlans(); }, setStripePlansCurrency(event) { @@ -190,6 +138,9 @@ export default Component.extend({ } this.set('settings.stripePlans', updatedPlans); + this.set('_scratchStripeYearlyAmount', null); + this.set('_scratchStripeMonthlyAmount', null); + this.validateStripePlans(); }, setStripeConnectIntegrationToken(event) { @@ -224,6 +175,53 @@ export default Component.extend({ } }, + validateStripePlans() { + this.get('settings.errors').remove('stripePlans'); + this.get('settings.hasValidated').removeObject('stripePlans'); + + if (this._scratchStripeYearlyAmount === null) { + this._scratchStripeYearlyAmount = this.get('stripePlans').yearly.amount; + } + if (this._scratchStripeMonthlyAmount === null) { + this._scratchStripeMonthlyAmount = this.get('stripePlans').monthly.amount; + } + + try { + const selectedCurrency = this.selectedCurrency; + const yearlyAmount = parseInt(this._scratchStripeYearlyAmount); + const monthlyAmount = parseInt(this._scratchStripeMonthlyAmount); + if (!yearlyAmount || yearlyAmount < 1 || !monthlyAmount || monthlyAmount < 1) { + const minimum = Intl.NumberFormat(this.settings.get('lang'), { + currency: selectedCurrency.isoCode, + style: 'currency' + }).format(1); + + throw new TypeError(`Subscription amount must be at least ${minimum}`); + } + + const updatedPlans = this.get('settings.stripePlans').map((plan) => { + if (plan.name !== 'Complimentary') { + let newAmount; + if (plan.interval === 'year') { + newAmount = yearlyAmount * 100; + } else if (plan.interval === 'month') { + newAmount = monthlyAmount * 100; + } + return Object.assign({}, plan, { + amount: newAmount + }); + } + return plan; + }); + + this.set('settings.stripePlans', updatedPlans); + } catch (err) { + this.get('settings.errors').add('stripePlans', err.message); + } finally { + this.get('settings.hasValidated').pushObject('stripePlans'); + } + }, + openDisconnectStripeConnectModal: task(function* () { this.set('hasActiveStripeSubscriptions', false); if (!this.get('stripeConnectAccountId')) { diff --git a/ghost/admin/app/utils/currency.js b/ghost/admin/app/utils/currency.js index 083517e70b..8ae33d4755 100644 --- a/ghost/admin/app/utils/currency.js +++ b/ghost/admin/app/utils/currency.js @@ -1,28 +1,130 @@ +export const currencies = [ + {isoCode: 'AED', name: 'United Arab Emirates dirham'}, + {isoCode: 'AFN', name: 'Afghan afghani'}, + {isoCode: 'ALL', name: 'Albanian lek'}, + {isoCode: 'AMD', name: 'Armenian dram'}, + {isoCode: 'ANG', name: 'Netherlands Antillean guilder'}, + {isoCode: 'AOA', name: 'Angolan kwanza'}, + {isoCode: 'ARS', name: 'Argentine peso'}, + {isoCode: 'AUD', name: 'Austrialian dollar'}, + {isoCode: 'AWG', name: 'Aruban florin'}, + {isoCode: 'AZN', name: 'Azerbaijani manat'}, + {isoCode: 'BAM', name: 'Bosnia and Herzegovina convertible mark'}, + {isoCode: 'BBD', name: 'Barbados dollar'}, + {isoCode: 'BDT', name: 'Bangladeshi taka'}, + {isoCode: 'BGN', name: 'Bulgarian lev'}, + {isoCode: 'BMD', name: 'Bermudian dollar'}, + {isoCode: 'BND', name: 'Brunei dollar'}, + {isoCode: 'BOB', name: 'Boliviano'}, + {isoCode: 'BRL', name: 'Brazilian real'}, + {isoCode: 'BSD', name: 'Bahamian dollar'}, + {isoCode: 'BWP', name: 'Botswana pula'}, + {isoCode: 'BZD', name: 'Belize dollar'}, + {isoCode: 'CAD', name: 'Canadian dollar'}, + {isoCode: 'CDF', name: 'Congolese franc'}, + {isoCode: 'CHF', name: 'Swiss franc'}, + {isoCode: 'CNY', name: 'Chinese yuan'}, + {isoCode: 'COP', name: 'Colombian peso'}, + {isoCode: 'CRC', name: 'Costa Rican colon'}, + {isoCode: 'CVE', name: 'Cape Verdean escudo'}, + {isoCode: 'CZK', name: 'Czech koruna'}, + {isoCode: 'DKK', name: 'Danish krone'}, + {isoCode: 'DOP', name: 'Dominican peso'}, + {isoCode: 'DZD', name: 'Algerian dinar'}, + {isoCode: 'EGP', name: 'Egyptian pound'}, + {isoCode: 'ETB', name: 'Ethiopian birr'}, + {isoCode: 'EUR', name: 'Euro'}, + {isoCode: 'FJD', name: 'Fiji dollar'}, + {isoCode: 'FKP', name: 'Falkland Islands pound'}, + {isoCode: 'GBP', name: 'Pound sterling'}, + {isoCode: 'GEL', name: 'Georgian lari'}, + {isoCode: 'GIP', name: 'Gibraltar pound'}, + {isoCode: 'GMD', name: 'Gambian dalasi'}, + {isoCode: 'GTQ', name: 'Guatemalan queztal'}, + {isoCode: 'GYD', name: 'Guyanese dollar'}, + {isoCode: 'HKD', name: 'Hong Kong dollar'}, + {isoCode: 'HNL', name: 'Honduran lempira'}, + {isoCode: 'HRK', name: 'Croation kuna'}, + {isoCode: 'HTG', name: 'Haitian gourde'}, + {isoCode: 'HUF', name: 'Hungarian forint'}, + {isoCode: 'IDR', name: 'Indonesian rupiah'}, + {isoCode: 'ILS', name: 'Israeli new shekel'}, + {isoCode: 'INR', name: 'Indian rupee'}, + {isoCode: 'ISK', name: 'Icelandic króna'}, + {isoCode: 'JMD', name: 'Jamaican dollar'}, + {isoCode: 'KES', name: 'Kenyan shilling'}, + {isoCode: 'KGS', name: 'Kyrgyzstani som'}, + {isoCode: 'KHR', name: 'Cambodian riel'}, + {isoCode: 'KYD', name: 'Cayman Islands dollar'}, + {isoCode: 'KZT', name: 'Kazakhstani tenge'}, + {isoCode: 'LAK', name: 'Lao kip'}, + {isoCode: 'LBP', name: 'Lebanese pound'}, + {isoCode: 'LKR', name: 'Sri Lankan rupee'}, + {isoCode: 'LRD', name: 'Liberian dollar'}, + {isoCode: 'LSL', name: 'Lesotho loti'}, + {isoCode: 'MAD', name: 'Moroccan dirham'}, + {isoCode: 'MDL', name: 'Moldovan leu'}, + {isoCode: 'MKD', name: 'Macedonian denar'}, + {isoCode: 'MMK', name: 'Myanmar kyat'}, + {isoCode: 'MNT', name: 'Mongolian tögrög'}, + {isoCode: 'MOP', name: 'Macanese pataca'}, + {isoCode: 'MRO', name: 'Mauritanian ouguiya'}, + {isoCode: 'MUR', name: 'Mauritian rupee'}, + {isoCode: 'MVR', name: 'Maldivian rufiyaa'}, + {isoCode: 'MWK', name: 'Malawian kwacha'}, + {isoCode: 'MXN', name: 'Mexican peso'}, + {isoCode: 'MYR', name: 'Malaysian ringgit'}, + {isoCode: 'MZN', name: 'Mozambican metical'}, + {isoCode: 'NAD', name: 'Namibian dollar'}, + {isoCode: 'NGN', name: 'Nigerian naira'}, + {isoCode: 'NIO', name: 'Nicaraguan córdoba'}, + {isoCode: 'NOK', name: 'Norwegian krone'}, + {isoCode: 'NPR', name: 'Nepalese rupee'}, + {isoCode: 'NZD', name: 'New Zealand dollar'}, + {isoCode: 'PAB', name: 'Panamanian balboa'}, + {isoCode: 'PEN', name: 'Peruvian sol'}, + {isoCode: 'PGK', name: 'Papua New Guinean kina'}, + {isoCode: 'PHP', name: 'Philippine peso'}, + {isoCode: 'PKR', name: 'Pakistani rupee'}, + {isoCode: 'PLN', name: 'Polish złoty'}, + {isoCode: 'QAR', name: 'Qatari riyal'}, + {isoCode: 'RON', name: 'Romanian leu'}, + {isoCode: 'RSD', name: 'Serbian dinar'}, + {isoCode: 'RUB', name: 'Russian ruble'}, + {isoCode: 'SAR', name: 'Saudi riyal'}, + {isoCode: 'SBD', name: 'Solomon Islands dollar'}, + {isoCode: 'SCR', name: 'Seychelles rupee'}, + {isoCode: 'SEK', name: 'Swedish krona'}, + {isoCode: 'SGD', name: 'Singapore dollar'}, + {isoCode: 'SHP', name: 'Saint Helena pound'}, + {isoCode: 'SLL', name: 'Sierra Leonean leone'}, + {isoCode: 'SOS', name: 'Somali shilling'}, + {isoCode: 'SRD', name: 'Surinamese dollar'}, + {isoCode: 'STD', name: 'São Tomé and Príncipe dobra'}, + {isoCode: 'SZL', name: 'Salvadoran colón'}, + {isoCode: 'THB', name: 'Thai baht'}, + {isoCode: 'TJS', name: 'Tajikistani somoni'}, + {isoCode: 'TOP', name: 'Tongan paʻanga'}, + {isoCode: 'TRY', name: 'Turkish lira'}, + {isoCode: 'TTD', name: 'Trinidad and Tobago dollar'}, + {isoCode: 'TWD', name: 'New Taiwan dollar'}, + {isoCode: 'TZS', name: 'Tanzanian shilling'}, + {isoCode: 'UAH', name: 'Ukrainian hryvnia'}, + {isoCode: 'USD', name: 'United States dollar'}, + {isoCode: 'UYU', name: 'Uruauayan peso'}, + {isoCode: 'UZS', name: 'Uzbekistan som'}, + {isoCode: 'WST', name: 'Samoan tala'}, + {isoCode: 'XCD', name: 'East Caribbean dollar'}, + {isoCode: 'YER', name: 'Yemeni rial'}, + {isoCode: 'ZAR', name: 'South African rand'}, + {isoCode: 'ZMW', name: 'Zambian kwacha'} +]; + export function getSymbol(currency) { - switch (currency) { - case 'usd': - case 'aud': - case 'cad': - return '$'; - case 'eur': - return '€'; - case 'gbp': - return '£'; - case 'inr': - return '₹'; - } - return null; + return Intl.NumberFormat('en', {currency, style: 'currency'}).format(0).replace(/[\d\s.]/g, ''); } -export function getNonDecimal(amount, currency) { - switch (currency) { - case 'usd': - case 'aud': - case 'cad': - case 'eur': - case 'gbp': - case 'inr': - return amount / 100; - } - return null; +// We currently only support decimal currencies +export function getNonDecimal(amount/*, currency*/) { + return amount / 100; }