UNPKG

@eastsideco/escshopify

Version:

WIP JS library for Shopify, containing a variety of useful functionality.

300 lines (249 loc) 8.94 kB
import Evee from 'evee'; import Money from 'js-money'; import config from './config'; import state from './state'; import log from 'log'; import MoneySpanSet from './MoneySpanSet'; import MoneySpan from './MoneySpan'; import GeoserviceResolver from './resolvers/GeoserviceResolver'; import DefaultFormatter from './formatters/DefaultFormatter'; import Formatter from './formatters/Formatter'; import CurrencyResolver from './resolvers/CurrencyResolver'; import SelectHelper from './helpers/SelectHelper'; import Session from './Session'; import GeoService from '~/plugins/geoservice/GeoService'; /** @ignore */ const TAG = 'EasyCurrency'; /** @ignore */ var instanceCount = 0; /** * Plugin for automatic currency conversion, tax handling, etc. * @extends {evee} * @private */ class EasyCurrency extends Evee { /** * Creates a new instance of EasyCurrency. * This class is intended to be used as a singleton, and has global * side-effects - do not create multiple instances. */ constructor() { super(); instanceCount++; var styles = []; if (instanceCount > 1) { log.warn(TAG, 'More than one instance of EasyCurrency has been created. This may cause unexpected behavior.'); } /** @type {src/plugins/easycurrency/config.js~Config} */ this._config = config; /** @type {src/plugins/easycurrency/resolvers/CurrencyResolver.js~CurrencyResolver} */ this._resolver = null; /** @type {src/plugins/easycurrency/state.js~State} */ this._state = state; /** @type {src/plugins/easycurrency/MoneySpanSet.js~MoneySpanSet} */ this._moneySpanSet = new MoneySpanSet; /** @type {src/plugins/easycurrency/formatters/Formatter.js~Formatter} */ this._formatter = new DefaultFormatter; /** @type {src/plugins/easycurrency/Session.js~Session} */ this._session = new Session; /** @type {src/plugins/easycurrency/helpers/SelectHelper.js~SelectHelper} */ this.selectHelper = new SelectHelper(this); } /** * Uses a default {@link GeoserviceResolver} as the currency resolver. */ useGeoserviceResolver() { this.setCurrencyResolver(new GeoserviceResolver); } /** * Start running EasyCurrency on the current page. * @param {Object|src/plugins/easycurrency/config.js~Config} config * @emits {Object|src/plugins/easycurrency/config.js~Config} beforeInitialize(config) * @emits {Object|src/plugins/easycurrency/config.js~Config} initialize(config) */ initialize(config) { this.emit('beforeInitialize', config); log.debug(TAG, 'Initialized with config', config); if (config) { this._config = Object.assign({}, this._config, config); } var currency = this._session.getCurrency(); var fromSession = currency; currency = currency || this._config.defaultCurrency; this.setActiveCurrency(this._session.getCurrency() || this._config.defaultCurrency); this.emit('initialize', config); if (!fromSession && this._config.useGeoForCurrency) { var geoService = new GeoService; geoService.lookupGeo().then((result) => { log.debug(TAG, 'Got currency from geoservice: ' + result.currency); this.setActiveCurrency(result.currency); }); } } /** * Sets the active currency, and refreshs any money spans. * @param {String} currency Currency code * @emits {String} beforeCurrencyChanged(currency) * @emits {String} currencyChanged(currency) */ setActiveCurrency(currency) { this.emit('beforeCurrencyChanged', currency); log.debug(TAG, 'Set active currency', currency); if (!currency || (this._config.allowedCurrencies != 'any' && this._config.allowedCurrencies.indexOf(currency) == -1)) { log.debug(TAG, 'Currency not in whitelist, switching to base currency.'); currency = this._config.defaultCurrency; } this._state.currency = currency; this._session.saveCurrency(currency); this.parse(); this.render(); this.emit('currencyChanged', currency); } /** * Returns the active currency. * @return {String} */ getActiveCurrency() { return this._state.currency; } /** * Returns the available currency codes. * @return {String[]} */ async getAvailableCurrencies() { return this._resolver.listCurrencyCodes(); } /** * Attempts to find new money spans on the page. * Change moneySpanSelectors / moneySpanParser config options to modify * how money spans are parsed. * @emits {null} beforeParse * @emits {null} parse */ parse() { this.emit('beforeParse'); log.debug(TAG, 'Parsing'); var els = []; for (let selector of this._config.moneySpanSelectors) { var els = document.querySelectorAll(selector); for (let i = 0; i < els.length; i++) { var el = els[i]; this._processElement(el); } } this.emit('parse'); } /** * @param {DOMNode} el - Element to process */ _processElement(el) { var money = this._config.moneySpanParser(el, this); var moneySpan = new MoneySpan(money, this); moneySpan.setElement(el); this._moneySpanSet.add(moneySpan); } /** * Forces all money spans to re-render. * @emits {null} beforeRender * @emits {null} render */ render() { this.emit('beforeRender'); log.debug(TAG, 'Rendering'); for (let moneySpan of this._moneySpanSet.list()) { moneySpan.render(); } this.emit('render'); } /** * Returns the current state. * @return {src/plugins/easycurrency/state.js~State} */ getState() { return this._state; } /** * Format a value as a currency * @param {js-money|Number} amount * @param {String|null} [currency] If null, uses current currency. * @return {String} */ format(amount, currency) { if (typeof amount == 'number') { amount = new Money(amount, currency || this._state.currency); } var str = this._formatter.format(amount.amount, amount.currency); return str; } /** * Convert an amount to another currency. * @param {js-money|Number} amount * @param {String} [to] - If null, uses current currency * @param {null|String} [from] Ignored if amount is a Money object. * @return {Promise<js-money>} */ async convert(amount, to, from) { if (typeof amount == 'number') { amount = new Money(amount, from || this._state.currency); } var rate = await this._resolver.getConversionRate(amount.currency, to || this._state.currency); return new Money(amount.multiply(rate).amount, Money[to || this._state.currency]); } /** * Adds the current tax rate to the given amount * @param {js-money|Number} amount * @return {Promise<js-money>} */ async addTax(amount) { if (typeof amount == 'number') { amount = new Money(amount, this._state.currency); } return amount.multiply(1 + this._state.taxRate); } /** * Sets the current tax rate. * @param {type} taxRate - Tax rate as a decimal percentage (i.e. 20% = 0.2) * @emits {null} beforeChangeTaxRate * @emits {null} taxRateChanged */ setTaxRate(taxRate) { this.emit('beforeChangeTaxRate'); this._state.taxRate = taxRate; this.parse(); this.render(); this.emit('taxRateChanged'); } /** * Overrides the default currency resolver, which provides information * about the available currencies. * @param {src/plugins/easycurrency/resolvers/CurrencyResolver.js~CurrencyResolver} resolver * @emits {src/plugins/easycurrency/resolvers/CurrencyResolver.js~CurrencyResolver} currencyResolverChanged(resolver) */ setCurrencyResolver(resolver) { this._resolver = resolver; this.emit('currencyResolverChanged', resolver); } /** * Overrides the default formatter. * @param {src/plugins/easycurrency/formatters/Formatter.js~Formatter} formatter * @emits {src/plugins/easycurrency/formatters/Formatter.js~Formatter} formatterChanged(formatter) */ setFormatter(formatter) { this._formatter = formatter; this.emit('formatterChanged', resolver); } } EasyCurrency.formatters = { DefaultFormatter, Formatter }; EasyCurrency.helpers = { SelectHelper, }; EasyCurrency.resolvers = { CurrencyResolver, GeoserviceResolver }; export default EasyCurrency;