aboutsummaryrefslogtreecommitdiffstats
path: root/packages/website/ts/utils
diff options
context:
space:
mode:
Diffstat (limited to 'packages/website/ts/utils')
-rw-r--r--packages/website/ts/utils/analytics.ts104
-rw-r--r--packages/website/ts/utils/backend_client.ts6
-rw-r--r--packages/website/ts/utils/configs.ts10
-rw-r--r--packages/website/ts/utils/constants.ts4
-rw-r--r--packages/website/ts/utils/doc_utils.ts6
-rw-r--r--packages/website/ts/utils/error_reporter.ts33
-rw-r--r--packages/website/ts/utils/fetch_utils.ts9
-rw-r--r--packages/website/ts/utils/utils.ts79
8 files changed, 157 insertions, 94 deletions
diff --git a/packages/website/ts/utils/analytics.ts b/packages/website/ts/utils/analytics.ts
index f4bfa083f..e5a1ddfa4 100644
--- a/packages/website/ts/utils/analytics.ts
+++ b/packages/website/ts/utils/analytics.ts
@@ -1,27 +1,83 @@
import * as _ from 'lodash';
-import * as ReactGA from 'react-ga';
-import { InjectedWeb3 } from 'ts/types';
-import { configs } from 'ts/utils/configs';
+import { ObjectMap, Order } from 'ts/types';
import { utils } from 'ts/utils/utils';
-export const analytics = {
- init(): void {
- ReactGA.initialize(configs.GOOGLE_ANALYTICS_ID);
- },
- logEvent(category: string, action: string, label: string, value?: any): void {
- ReactGA.event({
- category,
- action,
- label,
- value,
- });
- },
- async logProviderAsync(web3IfExists: InjectedWeb3): Promise<void> {
- await utils.onPageLoadAsync();
- const providerType =
- !_.isUndefined(web3IfExists) && !_.isUndefined(web3IfExists.currentProvider)
- ? utils.getProviderType(web3IfExists.currentProvider)
- : 'NONE';
- ReactGA.ga('set', 'dimension1', providerType);
- },
-};
+export interface HeapAnalytics {
+ loaded: boolean;
+ identify(id: string, idType: string): void;
+ track(eventName: string, eventProperties?: ObjectMap<string | number>): void;
+ resetIdentity(): void;
+ addUserProperties(properties: ObjectMap<string | number>): void;
+ addEventProperties(properties: ObjectMap<string | number>): void;
+ removeEventProperty(property: string): void;
+ clearEventProperties(): void;
+}
+export class Analytics {
+ private _heap: HeapAnalytics;
+ public static init(): Analytics {
+ return new Analytics(Analytics.getHeap());
+ }
+ public static getHeap(): HeapAnalytics {
+ const heap = (window as any).heap;
+ if (!_.isUndefined(heap)) {
+ return heap;
+ } else {
+ throw new Error('Could not find the Heap SDK on the page.');
+ }
+ }
+ constructor(heap: HeapAnalytics) {
+ this._heap = heap;
+ }
+ // tslint:disable:no-floating-promises
+ // HeapAnalytics Wrappers
+ public identify(id: string, idType: string): void {
+ this._heapLoadedGuardAsync(() => this._heap.identify(id, idType));
+ }
+ public track(eventName: string, eventProperties?: ObjectMap<string | number>): void {
+ this._heapLoadedGuardAsync(() => this._heap.track(eventName, eventProperties));
+ }
+ public resetIdentity(): void {
+ this._heapLoadedGuardAsync(() => this._heap.resetIdentity());
+ }
+ public addUserProperties(properties: ObjectMap<string | number>): void {
+ this._heapLoadedGuardAsync(() => this._heap.addUserProperties(properties));
+ }
+ public addEventProperties(properties: ObjectMap<string | number>): void {
+ this._heapLoadedGuardAsync(() => this._heap.addEventProperties(properties));
+ }
+ public removeEventProperty(property: string): void {
+ this._heapLoadedGuardAsync(() => this._heap.removeEventProperty(property));
+ }
+ public clearEventProperties(): void {
+ this._heapLoadedGuardAsync(() => this._heap.clearEventProperties());
+ }
+ // tslint:enable:no-floating-promises
+ // Custom methods
+ public trackOrderEvent(eventName: string, order: Order): void {
+ const orderLoggingData = {
+ takerTokenAmount: order.signedOrder.takerTokenAmount,
+ makeTokenAmount: order.signedOrder.makerTokenAmount,
+ takerToken: order.metadata.takerToken.symbol,
+ makerToken: order.metadata.makerToken.symbol,
+ };
+ this.track(eventName, orderLoggingData);
+ }
+ /**
+ * Heap is not available as a UMD module, and additionally has the strange property of replacing itself with
+ * a different object once it's loaded.
+ * Instead of having an await call before every analytics use, we opt to have the awaiting logic in here by
+ * guarding every API call with the guard below.
+ */
+ private async _heapLoadedGuardAsync(callback: () => void): Promise<void> {
+ if (this._heap.loaded) {
+ callback();
+ return undefined;
+ }
+ await utils.onPageLoadPromise;
+ // HACK: Reset heap to loaded heap
+ this._heap = (window as any).heap;
+ callback();
+ }
+}
+
+export const analytics = Analytics.init();
diff --git a/packages/website/ts/utils/backend_client.ts b/packages/website/ts/utils/backend_client.ts
index 835a6ef4d..5164211df 100644
--- a/packages/website/ts/utils/backend_client.ts
+++ b/packages/website/ts/utils/backend_client.ts
@@ -6,6 +6,7 @@ import {
WebsiteBackendJobInfo,
WebsiteBackendPriceInfo,
WebsiteBackendRelayerInfo,
+ WebsiteBackendTokenInfo,
} from 'ts/types';
import { fetchUtils } from 'ts/utils/fetch_utils';
import { utils } from 'ts/utils/utils';
@@ -14,6 +15,7 @@ const ETH_GAS_STATION_ENDPOINT = '/eth_gas_station';
const JOBS_ENDPOINT = '/jobs';
const PRICES_ENDPOINT = '/prices';
const RELAYERS_ENDPOINT = '/relayers';
+const TOKENS_ENDPOINT = '/tokens';
const WIKI_ENDPOINT = '/wiki';
const SUBSCRIBE_SUBSTACK_NEWSLETTER_ENDPOINT = '/newsletter_subscriber/substack';
@@ -41,6 +43,10 @@ export const backendClient = {
const result = await fetchUtils.requestAsync(utils.getBackendBaseUrl(), RELAYERS_ENDPOINT);
return result;
},
+ async getTokenInfosAsync(): Promise<WebsiteBackendTokenInfo[]> {
+ const result = await fetchUtils.requestAsync(utils.getBackendBaseUrl(), TOKENS_ENDPOINT);
+ return result;
+ },
async getWikiArticlesBySectionAsync(): Promise<ArticlesBySection> {
const result = await fetchUtils.requestAsync(utils.getBackendBaseUrl(), WIKI_ENDPOINT);
return result;
diff --git a/packages/website/ts/utils/configs.ts b/packages/website/ts/utils/configs.ts
index 97aabd13d..a1c64f9cb 100644
--- a/packages/website/ts/utils/configs.ts
+++ b/packages/website/ts/utils/configs.ts
@@ -1,11 +1,6 @@
-import * as _ from 'lodash';
-import { Environments, OutdatedWrappedEtherByNetworkId, PublicNodeUrlsByNetworkId } from 'ts/types';
+import { OutdatedWrappedEtherByNetworkId, PublicNodeUrlsByNetworkId } from 'ts/types';
const BASE_URL = window.location.origin;
-const isDevelopment = _.includes(
- ['https://0xproject.localhost:3572', 'https://localhost:3572', 'https://127.0.0.1'],
- BASE_URL,
-);
const INFURA_API_KEY = 'T5WSC8cautR4KXyYgsRs';
export const configs = {
@@ -19,9 +14,8 @@ export const configs = {
DEFAULT_TRACKED_TOKEN_SYMBOLS: ['WETH', 'ZRX'],
DOMAIN_STAGING: 'staging-0xproject.s3-website-us-east-1.amazonaws.com',
DOMAIN_DOGFOOD: 'dogfood.0xproject.com',
- DOMAIN_DEVELOPMENT: '0xproject.localhost:3572',
+ DOMAINS_DEVELOPMENT: ['0xproject.localhost:3572', 'localhost:3572', '127.0.0.1'],
DOMAIN_PRODUCTION: '0xproject.com',
- ENVIRONMENT: isDevelopment ? Environments.DEVELOPMENT : Environments.PRODUCTION,
GOOGLE_ANALYTICS_ID: 'UA-98720122-1',
LAST_LOCAL_STORAGE_FILL_CLEARANCE_DATE: '2017-11-22',
LAST_LOCAL_STORAGE_TRACKED_TOKEN_CLEARANCE_DATE: '2018-7-5',
diff --git a/packages/website/ts/utils/constants.ts b/packages/website/ts/utils/constants.ts
index 4b3443d21..20441cd75 100644
--- a/packages/website/ts/utils/constants.ts
+++ b/packages/website/ts/utils/constants.ts
@@ -33,7 +33,7 @@ export const constants = {
PROVIDER_NAME_TOSHI: 'Toshi',
PROVIDER_NAME_GENERIC: 'Injected Web3',
PROVIDER_NAME_PUBLIC: '0x Public',
- ROLLBAR_ACCESS_TOKEN: 'a6619002b51c4464928201e6ea94de65',
+ ROLLBAR_ACCESS_TOKEN: '32c39bfa4bb6440faedc1612a9c13d28',
S3_DOC_BUCKET_ROOT: 'https://s3.amazonaws.com/doc-jsons',
S3_STAGING_DOC_BUCKET_ROOT: 'https://s3.amazonaws.com/staging-doc-jsons',
SUCCESS_STATUS: 200,
@@ -58,7 +58,7 @@ export const constants = {
PROJECT_URL_MAKER: 'https://makerdao.com',
PROJECT_URL_ARAGON: 'https://aragon.one',
PROJECT_URL_BLOCKNET: 'https://blocknet.co',
- PROJECT_URL_0CEAN: 'http://the0cean.com',
+ PROJECT_URL_0CEAN: 'https://theocean.trade',
PROJECT_URL_IMTOKEN: 'https://tokenlon.token.im/',
PROJECT_URL_AUGUR: 'https://augur.net',
PROJECT_URL_AUCTUS: 'https://auctus.org',
diff --git a/packages/website/ts/utils/doc_utils.ts b/packages/website/ts/utils/doc_utils.ts
index 7768835fb..1627b9b0c 100644
--- a/packages/website/ts/utils/doc_utils.ts
+++ b/packages/website/ts/utils/doc_utils.ts
@@ -1,5 +1,5 @@
import { DoxityDocObj, TypeDocNode } from '@0xproject/react-docs';
-import { logUtils } from '@0xproject/utils';
+import { fetchAsync, logUtils } from '@0xproject/utils';
import findVersions = require('find-versions');
import * as _ from 'lodash';
import { S3FileObject, VersionToFilePath } from 'ts/types';
@@ -16,7 +16,7 @@ export const docUtils = {
return versionToFilePath;
},
async getVersionFileNamesAsync(s3DocJsonRoot: string, folderName: string): Promise<string[]> {
- const response = await fetch(s3DocJsonRoot);
+ const response = await fetchAsync(s3DocJsonRoot);
if (response.status !== 200) {
// TODO: Show the user an error message when the docs fail to load
const errMsg = await response.text();
@@ -73,7 +73,7 @@ export const docUtils = {
},
async getJSONDocFileAsync(filePath: string, s3DocJsonRoot: string): Promise<TypeDocNode | DoxityDocObj> {
const endpoint = `${s3DocJsonRoot}/${filePath}`;
- const response = await fetch(endpoint);
+ const response = await fetchAsync(endpoint);
if (response.status !== 200) {
// TODO: Show the user an error message when the docs fail to load
const errMsg = await response.text();
diff --git a/packages/website/ts/utils/error_reporter.ts b/packages/website/ts/utils/error_reporter.ts
index f875141fe..6008fffed 100644
--- a/packages/website/ts/utils/error_reporter.ts
+++ b/packages/website/ts/utils/error_reporter.ts
@@ -1,7 +1,7 @@
import { logUtils } from '@0xproject/utils';
-import { Environments } from 'ts/types';
import { configs } from 'ts/utils/configs';
import { constants } from 'ts/utils/constants';
+import { utils } from 'ts/utils/utils';
// Suggested way to include Rollbar with Webpack
// https://github.com/rollbar/rollbar.js/tree/master/examples/webpack
@@ -12,7 +12,15 @@ const rollbarConfig = {
itemsPerMinute: 10,
maxItems: 500,
payload: {
- environment: configs.ENVIRONMENT,
+ environment: utils.getEnvironment(),
+ client: {
+ javascript: {
+ source_map_enabled: true,
+ // This is only defined in production environments.
+ code_version: process.env.GIT_SHA,
+ guess_uncaught_frames: true,
+ },
+ },
},
uncaughtErrorLevel: 'error',
hostWhiteList: [configs.DOMAIN_PRODUCTION, configs.DOMAIN_STAGING],
@@ -28,25 +36,18 @@ const rollbarConfig = {
'SecurityError (DOM Exception 18)',
],
};
-import Rollbar = require('../../public/js/rollbar.umd.nojson.min.js');
+import Rollbar = require('../../public/js/rollbar.umd.min.js');
const rollbar = Rollbar.init(rollbarConfig);
export const errorReporter = {
- async reportAsync(err: Error): Promise<any> {
- if (configs.ENVIRONMENT === Environments.DEVELOPMENT) {
+ report(err: Error): void {
+ if (utils.isDevelopment()) {
return; // Let's not log development errors to rollbar
}
-
- return new Promise((resolve, _reject) => {
- rollbar.error(err, (rollbarErr: Error) => {
- if (rollbarErr) {
- logUtils.log(`Error reporting to rollbar, ignoring: ${rollbarErr}`);
- // We never want to reject and cause the app to throw because of rollbar
- resolve();
- } else {
- resolve();
- }
- });
+ rollbar.error(err, (rollbarErr: Error) => {
+ if (rollbarErr) {
+ logUtils.log(`Error reporting to rollbar, ignoring: ${rollbarErr}`);
+ }
});
},
};
diff --git a/packages/website/ts/utils/fetch_utils.ts b/packages/website/ts/utils/fetch_utils.ts
index 513f7e479..e9a88b6b3 100644
--- a/packages/website/ts/utils/fetch_utils.ts
+++ b/packages/website/ts/utils/fetch_utils.ts
@@ -1,4 +1,4 @@
-import { logUtils } from '@0xproject/utils';
+import { fetchAsync, logUtils } from '@0xproject/utils';
import * as _ from 'lodash';
import * as queryString from 'query-string';
@@ -9,8 +9,7 @@ const logErrorIfPresent = (response: Response, requestedURL: string) => {
const errorText = `Error requesting url: ${requestedURL}, ${response.status}: ${response.statusText}`;
logUtils.log(errorText);
const error = Error(errorText);
- // tslint:disable-next-line:no-floating-promises
- errorReporter.reportAsync(error);
+ errorReporter.report(error);
throw error;
}
};
@@ -19,14 +18,14 @@ export const fetchUtils = {
async requestAsync(baseUrl: string, path: string, queryParams?: object): Promise<any> {
const query = queryStringFromQueryParams(queryParams);
const url = `${baseUrl}${path}${query}`;
- const response = await fetch(url);
+ const response = await fetchAsync(url);
logErrorIfPresent(response, url);
const result = await response.json();
return result;
},
async postAsync(baseUrl: string, path: string, body: object): Promise<Response> {
const url = `${baseUrl}${path}`;
- const response = await fetch(url, {
+ const response = await fetchAsync(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
diff --git a/packages/website/ts/utils/utils.ts b/packages/website/ts/utils/utils.ts
index 8c76a7592..e656d5963 100644
--- a/packages/website/ts/utils/utils.ts
+++ b/packages/website/ts/utils/utils.ts
@@ -30,8 +30,6 @@ import { configs } from 'ts/utils/configs';
import { constants } from 'ts/utils/constants';
import * as u2f from 'ts/vendor/u2f_api';
-const isDogfood = (): boolean => _.includes(window.location.href, configs.DOMAIN_DOGFOOD);
-
export const utils = {
assert(condition: boolean, message: string): void {
if (!condition) {
@@ -61,7 +59,7 @@ export const utils = {
return moment.unix(unixTimestampSec.toNumber());
},
convertToReadableDateTimeFromUnixTimestamp(unixTimestampSec: BigNumber): string {
- const m = this.convertToMomentFromUnixTimestamp(unixTimestampSec);
+ const m = utils.convertToMomentFromUnixTimestamp(unixTimestampSec);
const formattedDate: string = m.format('h:MMa MMMM D YYYY');
return formattedDate;
},
@@ -177,18 +175,6 @@ export const utils = {
_.includes(errMsg, ledgerDenialErrMsg);
return isUserDeniedErrMsg;
},
- getCurrentEnvironment(): string {
- switch (location.host) {
- case configs.DOMAIN_DEVELOPMENT:
- return 'development';
- case configs.DOMAIN_STAGING:
- return 'staging';
- case configs.DOMAIN_PRODUCTION:
- return 'production';
- default:
- return 'production';
- }
- },
getAddressBeginAndEnd(address: string): string {
const truncatedAddress = `${address.substring(0, 6)}...${address.substr(-4)}`; // 0x3d5a...b287
return truncatedAddress;
@@ -313,14 +299,13 @@ export const utils = {
const baseUrl = `https://${window.location.hostname}${hasPort ? `:${port}` : ''}`;
return baseUrl;
},
- async onPageLoadAsync(): Promise<void> {
+ onPageLoadPromise: new Promise<void>((resolve, _reject) => {
if (document.readyState === 'complete') {
- return; // Already loaded
+ resolve();
+ return;
}
- return new Promise<void>((resolve, _reject) => {
- window.onload = () => resolve();
- });
- },
+ window.onload = () => resolve();
+ }),
getProviderType(provider: Provider): Providers | string {
const constructorName = provider.constructor.name;
let parsedProviderName = constructorName;
@@ -346,10 +331,10 @@ export const utils = {
return parsedProviderName;
},
getBackendBaseUrl(): string {
- return isDogfood() ? configs.BACKEND_BASE_STAGING_URL : configs.BACKEND_BASE_PROD_URL;
+ return utils.isDogfood() ? configs.BACKEND_BASE_STAGING_URL : configs.BACKEND_BASE_PROD_URL;
},
isDevelopment(): boolean {
- return configs.ENVIRONMENT === Environments.DEVELOPMENT;
+ return _.includes(configs.DOMAINS_DEVELOPMENT, window.location.origin);
},
isStaging(): boolean {
return _.includes(window.location.href, configs.DOMAIN_STAGING);
@@ -357,14 +342,29 @@ export const utils = {
isExternallyInjected(providerType: ProviderType, injectedProviderName: string): boolean {
return providerType === ProviderType.Injected && injectedProviderName !== constants.PROVIDER_NAME_PUBLIC;
},
- isDogfood,
- shouldShowPortalV2(): boolean {
- // return this.isDevelopment() || this.isStaging() || this.isDogfood();
- // TODO: Remove this method entirely after launch.
- return true;
+ isDogfood(): boolean {
+ return _.includes(window.location.href, configs.DOMAIN_DOGFOOD);
+ },
+ isProduction(): boolean {
+ return _.includes(window.location.href, configs.DOMAIN_PRODUCTION);
+ },
+ getEnvironment(): Environments {
+ if (utils.isDogfood()) {
+ return Environments.DOGFOOD;
+ }
+ if (utils.isDevelopment()) {
+ return Environments.DEVELOPMENT;
+ }
+ if (utils.isStaging()) {
+ return Environments.STAGING;
+ }
+ if (utils.isProduction()) {
+ return Environments.PRODUCTION;
+ }
+ return Environments.UNKNOWN;
},
shouldShowJobsPage(): boolean {
- return this.isDevelopment() || this.isStaging() || this.isDogfood();
+ return utils.isDevelopment() || utils.isStaging() || utils.isDogfood();
},
getEthToken(tokenByAddress: TokenByAddress): Token {
return utils.getTokenBySymbol(constants.ETHER_TOKEN_SYMBOL, tokenByAddress);
@@ -379,27 +379,34 @@ export const utils = {
},
getTrackedTokens(tokenByAddress: TokenByAddress): Token[] {
const allTokens = _.values(tokenByAddress);
- const trackedTokens = _.filter(allTokens, t => this.isTokenTracked(t));
+ const trackedTokens = _.filter(allTokens, t => utils.isTokenTracked(t));
return trackedTokens;
},
getFormattedAmountFromToken(token: Token, tokenState: TokenState): string {
return utils.getFormattedAmount(tokenState.balance, token.decimals);
},
+ format(value: BigNumber, format: string): string {
+ const formattedAmount = numeral(value).format(format);
+ if (_.isNaN(formattedAmount)) {
+ // https://github.com/adamwdraper/Numeral-js/issues/596
+ return numeral(new BigNumber(0)).format(format);
+ }
+ return formattedAmount;
+ },
getFormattedAmount(amount: BigNumber, decimals: number): string {
const unitAmount = Web3Wrapper.toUnitAmount(amount, decimals);
// if the unit amount is less than 1, show the natural number of decimal places with a max of 4
// if the unit amount is greater than or equal to 1, show only 2 decimal places
- const precision = unitAmount.lt(1)
- ? Math.min(constants.TOKEN_AMOUNT_DISPLAY_PRECISION, unitAmount.decimalPlaces())
- : 2;
+ const lessThanOnePrecision = Math.min(constants.TOKEN_AMOUNT_DISPLAY_PRECISION, unitAmount.decimalPlaces());
+ const greaterThanOnePrecision = 2;
+ const precision = unitAmount.lt(1) ? lessThanOnePrecision : greaterThanOnePrecision;
const format = `0,0.${_.repeat('0', precision)}`;
- const formattedAmount = numeral(unitAmount).format(format);
- return formattedAmount;
+ return utils.format(unitAmount, format);
},
getUsdValueFormattedAmount(amount: BigNumber, decimals: number, price: BigNumber): string {
const unitAmount = Web3Wrapper.toUnitAmount(amount, decimals);
const value = unitAmount.mul(price);
- return numeral(value).format(constants.NUMERAL_USD_FORMAT);
+ return utils.format(value, constants.NUMERAL_USD_FORMAT);
},
openUrl(url: string): void {
window.open(url, '_blank');