diff --git a/js/components/fatal_error.js b/js/components/fatal_error.js new file mode 100644 index 00000000..e69de29b diff --git a/js/utils/fetch.js b/js/utils/fetch.js new file mode 100644 index 00000000..37626a71 --- /dev/null +++ b/js/utils/fetch.js @@ -0,0 +1,113 @@ +import { default as _fetch } from 'isomorphic-fetch'; +import FetchApiUtils from '../utils/fetch_api_utils'; + + +class UrlMapError extends Error {}; +class ServerError extends Error {}; +class APIError extends Error {}; + + +class Fetch { + _merge(defaults, options) { + let merged = {}; + for (let key in defaults) { + merged[key] = defaults[key]; + } + for (let key in options) { + merged[key] = options[key]; + } + return merged; + } + + unpackResponse(response) { + if (response.status >= 500) { + throw new ServerError(); + } + return response.text(); + } + + handleFatalError(err) { + this.fatalErrorHandler(err); + throw new ServerError(err); + } + + handleAPIError(json) { + if (!json['success']) { + let error = new APIError(); + error.json = json; + throw error; + } + return json; + } + + getUrl(url) { + let name = url; + if (!url.match(/^http/)) { + url = this.urlMap[url]; + if (!url) { + throw new UrlMapError(`Cannot find a mapping for "${name}"`); + } + } + + return url; + } + + prepareUrl(url, params, attachParamsToQuery) { + let newUrl = this.getUrl(url); + let re = /\${(\w+)}/g; + + newUrl = newUrl.replace(re, (match, key) => { + let val = params[key] + if (!val) { + throw new Error(`Cannot find param ${key}`); + } + delete params[key]; + return val; + }); + + if (attachParamsToQuery && params && Object.keys(params).length > 0) { + newUrl += FetchApiUtils.argsToQueryParams(params); + } + + return newUrl; + } + + request(verb, url, options) { + options = options || {}; + let merged = this._merge(this.httpOptions, options); + merged['method'] = verb; + return _fetch(url, merged) + .then(this.unpackResponse) + .then(JSON.parse) + .catch(this.handleFatalError.bind(this)) + .then(this.handleAPIError); + } + + get(url, params) { + let paramsCopy = this._merge(params); + let newUrl = this.prepareUrl(url, params); + return this.request('get', newUrl, true); + } + + post(url, params) { + let paramsCopy = this._merge(params); + let newUrl = this.prepareUrl(url, params); + let body = null; + + if (params['body']) { + body = JSON.stringify(params['body']) + } + return this.request('post', url, { body }); + } + + defaults(options) { + this.httpOptions = options.http || {}; + this.urlMap = options.urlMap || {}; + this.fatalErrorHandler = options.fatalErrorHandler || (() => {}); + } +} + + +let fetch = new Fetch(); + +export default fetch; diff --git a/js/utils/lang_utils.js b/js/utils/lang_utils.js new file mode 100644 index 00000000..a936294e --- /dev/null +++ b/js/utils/lang_utils.js @@ -0,0 +1,18 @@ +import languages from '../constants/languages'; +import template from 'lodash.template'; + +let getText = function(s, ...args) { + let lang = navigator.language || navigator.userLanguage; + try { + if(lang in languages) { + return languages[lang][s]; + } else { + // just use the english language + return languages['en-US'][s]; + } + } catch(err) { + console.error(err); + } +}; + +export default getText; \ No newline at end of file