aboutsummaryrefslogtreecommitdiffstats
path: root/packages/website
diff options
context:
space:
mode:
authorAmir Bandeali <abandeali1@gmail.com>2018-05-16 03:52:49 +0800
committerAmir Bandeali <abandeali1@gmail.com>2018-05-16 03:52:49 +0800
commit9e0471bfbb4bb2b3b490e10ce34b16c88e8bab9a (patch)
treef72aae5170b6f1f6d3d70ebf6c03ed171680ff50 /packages/website
parent9744b1906a111aa0c65c8fafb4db66aef32a5a23 (diff)
parent6aed4fb1ae27dabed027c855f2cbdc0bfb4f3b6b (diff)
downloaddexon-sol-tools-9e0471bfbb4bb2b3b490e10ce34b16c88e8bab9a.tar
dexon-sol-tools-9e0471bfbb4bb2b3b490e10ce34b16c88e8bab9a.tar.gz
dexon-sol-tools-9e0471bfbb4bb2b3b490e10ce34b16c88e8bab9a.tar.bz2
dexon-sol-tools-9e0471bfbb4bb2b3b490e10ce34b16c88e8bab9a.tar.lz
dexon-sol-tools-9e0471bfbb4bb2b3b490e10ce34b16c88e8bab9a.tar.xz
dexon-sol-tools-9e0471bfbb4bb2b3b490e10ce34b16c88e8bab9a.tar.zst
dexon-sol-tools-9e0471bfbb4bb2b3b490e10ce34b16c88e8bab9a.zip
Merge branch 'development' into v2-prototype
Diffstat (limited to 'packages/website')
-rw-r--r--packages/website/md/docs/deployer/installation.md24
-rw-r--r--packages/website/md/docs/deployer/introduction.md18
-rw-r--r--packages/website/md/docs/deployer/usage.md56
-rw-r--r--packages/website/md/docs/order_utils/installation.md17
-rw-r--r--packages/website/md/docs/order_utils/introduction.md1
-rw-r--r--packages/website/md/docs/sol-compiler/installation.md23
-rw-r--r--packages/website/md/docs/sol-compiler/introduction.md13
-rw-r--r--packages/website/md/docs/sol-compiler/usage.md24
-rw-r--r--packages/website/md/docs/sol_cov/usage.md2
-rw-r--r--packages/website/package.json20
-rw-r--r--packages/website/public/images/landing/project_logos/the_ocean.pngbin4766 -> 6322 bytes
-rw-r--r--packages/website/public/images/team/greg.jpegbin0 -> 4100 bytes
-rw-r--r--packages/website/public/images/team/philippe.pngbin51419 -> 0 bytes
-rw-r--r--packages/website/public/images/team/remco.jpegbin0 -> 14807 bytes
-rw-r--r--packages/website/translations/chinese.json3
-rw-r--r--packages/website/translations/english.json3
-rw-r--r--packages/website/translations/korean.json3
-rw-r--r--packages/website/translations/russian.json3
-rw-r--r--packages/website/translations/spanish.json3
-rw-r--r--packages/website/ts/components/legacy_portal/legacy_portal.tsx (renamed from packages/website/ts/components/portal.tsx)67
-rw-r--r--packages/website/ts/components/legacy_portal/legacy_portal_menu.tsx (renamed from packages/website/ts/components/portal_menu.tsx)28
-rw-r--r--packages/website/ts/components/portal/portal.tsx297
-rw-r--r--packages/website/ts/components/relayer_index/relayer_grid_tile.tsx77
-rw-r--r--packages/website/ts/components/relayer_index/relayer_index.tsx70
-rw-r--r--packages/website/ts/components/relayer_index/relayer_top_tokens.tsx16
-rw-r--r--packages/website/ts/components/top_bar/provider_display.tsx36
-rw-r--r--packages/website/ts/components/top_bar/top_bar.tsx100
-rw-r--r--packages/website/ts/components/ui/input_label.tsx2
-rw-r--r--packages/website/ts/components/wallet/wallet.tsx123
-rw-r--r--packages/website/ts/containers/legacy_portal.ts92
-rw-r--r--packages/website/ts/containers/order_utils_documentation.ts99
-rw-r--r--packages/website/ts/containers/portal.ts6
-rw-r--r--packages/website/ts/containers/sol_compiler_documentation.ts (renamed from packages/website/ts/containers/deployer_documentation.ts)38
-rw-r--r--packages/website/ts/containers/subproviders_documentation.ts2
-rw-r--r--packages/website/ts/containers/zero_ex_js_documentation.ts10
-rw-r--r--packages/website/ts/index.tsx31
-rw-r--r--packages/website/ts/pages/about/about.tsx24
-rw-r--r--packages/website/ts/pages/documentation/doc_page.tsx3
-rw-r--r--packages/website/ts/pages/landing/landing.tsx25
-rw-r--r--packages/website/ts/pages/wiki/wiki.tsx2
-rw-r--r--packages/website/ts/types.ts23
-rw-r--r--packages/website/ts/utils/backend_client.ts56
-rw-r--r--packages/website/ts/utils/fetch_utils.ts33
-rw-r--r--packages/website/ts/utils/utils.ts46
44 files changed, 1072 insertions, 447 deletions
diff --git a/packages/website/md/docs/deployer/installation.md b/packages/website/md/docs/deployer/installation.md
deleted file mode 100644
index c02dbadc6..000000000
--- a/packages/website/md/docs/deployer/installation.md
+++ /dev/null
@@ -1,24 +0,0 @@
-#### CLI Installation
-
-```bash
-yarn global add @0xproject/deployer
-```
-
-#### API Installation
-
-```bash
-yarn add @0xproject/deployer
-```
-
-**Import**
-
-```typescript
-import { Deployer, Compiler } from '@0xproject/deployer';
-```
-
-or
-
-```javascript
-var Deployer = require('@0xproject/deployer').Deployer;
-var Compiler = require('@0xproject/deployer').Compiler;
-```
diff --git a/packages/website/md/docs/deployer/introduction.md b/packages/website/md/docs/deployer/introduction.md
deleted file mode 100644
index 7ebd26a3c..000000000
--- a/packages/website/md/docs/deployer/introduction.md
+++ /dev/null
@@ -1,18 +0,0 @@
-Welcome to the [Deployer](https://github.com/0xProject/0x-monorepo/tree/development/packages/deployer) documentation! Deployer is a tool for compiling and deploying Solidity smart contracts with ease.
-
-It serves a similar purpose as parts of the [Truffle framework](http://truffleframework.com/), but with the UNIX philosophy in mind: Make each program do one thing well. This tool is for intermediate to advanced Solidity developers that require greater configurability and reliability.
-
-Deployer has the following advantages over Truffle:
-
-* Deploy each smart contract with a specific version of Solidity.
-* Improved artifact files:
- * Properly segregated artifacts to support storing different versions of smart contract deployed on different networks.
- * Storage of constructor args, source maps and paths to all requisite source files.
- * An easy to maintain codebase: TypeScript + Single repo.
- * Allows you to specify the deployer RPC address.
- * Supports Solidity version ranges - contract compiled with latest Solidity version that satisfies the range.
- * Migrations that work with `async/await`.
- * Migrations that can be written synchronously in order to guarentee deterministic contract addresses.
- * No race conditions when running migrations.
-
-Deployer can be used as a command-line tool or as an imported module.
diff --git a/packages/website/md/docs/deployer/usage.md b/packages/website/md/docs/deployer/usage.md
deleted file mode 100644
index 295af55e1..000000000
--- a/packages/website/md/docs/deployer/usage.md
+++ /dev/null
@@ -1,56 +0,0 @@
-#### CLI Usage
-
-```bash
-$ 0x-deployer --help
-0x-deployer [command]
-
-Commands:
- 0x-deployer compile compile contracts
- 0x-deployer deploy deploy a single contract with provided arguments
-
-Options:
- --version Show version number [boolean]
- --contracts-dir path of contracts directory to compile [string] [default:
- "/path/to/contracts"]
- --network-id mainnet=1, kovan=42, testrpc=50 [number] [default: 50]
- --should-optimize enable optimizer [boolean] [default: false]
- --artifacts-dir path to write contracts artifacts to [string] [default:
- "/path/to/artifacts"]
- --jsonrpc-port port connected to JSON RPC [number] [default: 8545]
- --gas-price gasPrice to be used for transactions
- [string] [default: "2000000000"]
- --account account to use for deploying contracts [string]
- --contracts comma separated list of contracts to compile
- [string] [default: "*"]
- --help Show help [boolean]
-```
-
-#### API Usage
-
-##### Migrations
-
-You can write migration scripts (similar to `truffle migrate`), that deploys multiple contracts and configures them. Below you'll find a simple example of such a script to help you get started.
-
-```typescript
-import { Deployer } from '@0xproject/deployer';
-import * as path from 'path';
-
-const deployerOpts = {
- artifactsDir: path.resolve('src', 'artifacts'),
- jsonrpcUrl: 'http://localhost:8545',
- networkId: 50,
- defaults: {
- gas: 1000000,
- },
-};
-
-const deployer = new Deployer(deployerOpts);
-
-(async () => {
- const etherToken = await deployer.deployAndSaveAsync('WETH9');
-})().catch(console.log);
-```
-
-**Tip:** Be sure to start an Ethereum node at the supplied `jsonrpcUrl`. We recommend testing with [Ganache-cli](https://github.com/trufflesuite/ganache-cli)
-
-A more sophisticated example can be found [here](https://github.com/0xProject/0x-monorepo/tree/development/packages/contracts/migrations)
diff --git a/packages/website/md/docs/order_utils/installation.md b/packages/website/md/docs/order_utils/installation.md
new file mode 100644
index 000000000..68a7cf960
--- /dev/null
+++ b/packages/website/md/docs/order_utils/installation.md
@@ -0,0 +1,17 @@
+**Install**
+
+```bash
+yarn add @0xproject/order-utils
+```
+
+**Import**
+
+```javascript
+import { createSignedOrderAsync } from '@0xproject/order-utils';
+```
+
+or
+
+```javascript
+var createSignedOrderAsync = require('@0xproject/order-utils').createSignedOrderAsync;
+```
diff --git a/packages/website/md/docs/order_utils/introduction.md b/packages/website/md/docs/order_utils/introduction.md
new file mode 100644
index 000000000..d5f3f2925
--- /dev/null
+++ b/packages/website/md/docs/order_utils/introduction.md
@@ -0,0 +1 @@
+Welcome to the [@0xproject/order-utils](https://github.com/0xProject/0x-monorepo/tree/development/packages/order-utils) documentation! Order utils is a set of utils around creating, signing, validating 0x orders.
diff --git a/packages/website/md/docs/sol-compiler/installation.md b/packages/website/md/docs/sol-compiler/installation.md
new file mode 100644
index 000000000..9c8561d9b
--- /dev/null
+++ b/packages/website/md/docs/sol-compiler/installation.md
@@ -0,0 +1,23 @@
+#### CLI Installation
+
+```bash
+yarn global add @0xproject/sol-compiler
+```
+
+#### API Installation
+
+```bash
+yarn add @0xproject/sol-compiler
+```
+
+**Import**
+
+```typescript
+import { Compiler } from '@0xproject/sol-compiler';
+```
+
+or
+
+```javascript
+var Compiler = require('@0xproject/sol-compiler').Compiler;
+```
diff --git a/packages/website/md/docs/sol-compiler/introduction.md b/packages/website/md/docs/sol-compiler/introduction.md
new file mode 100644
index 000000000..aa1939006
--- /dev/null
+++ b/packages/website/md/docs/sol-compiler/introduction.md
@@ -0,0 +1,13 @@
+Welcome to the [sol-compiler](https://github.com/0xProject/0x-monorepo/tree/development/packages/sol-compiler) documentation! Sol-compiler is a tool for compiling Solidity smart contracts and generating artifacts with ease.
+
+It serves a similar purpose as parts of the [Truffle framework](http://truffleframework.com/), but with the UNIX philosophy in mind: Make each program do one thing well. This tool is for intermediate to advanced Solidity developers that require greater configurability and reliability.
+
+Sol-compiler has the following advantages over Truffle:
+
+* Compile each smart contract with a specific version of Solidity.
+* Improved artifact files:
+ * Storage of constructor args, source maps and paths to all requisite source files.
+ * An easy to maintain codebase: TypeScript + Single repo.
+ * Supports Solidity version ranges - contract compiled with latest Solidity version that satisfies the range.
+
+Sol-compiler can be used as a command-line tool or as an imported module.
diff --git a/packages/website/md/docs/sol-compiler/usage.md b/packages/website/md/docs/sol-compiler/usage.md
new file mode 100644
index 000000000..79c9b32ba
--- /dev/null
+++ b/packages/website/md/docs/sol-compiler/usage.md
@@ -0,0 +1,24 @@
+#### CLI Usage
+
+```bash
+$ sol-compiler
+Options:
+ --version Show version number [boolean]
+ --contracts-dir path of contracts directory to compile [string]
+ --artifacts-dir path to write contracts artifacts to [string]
+ --contracts comma separated list of contracts to compile
+ [string] [default: "*"]
+ --help Show help [boolean]
+```
+
+#### API Usage
+
+```typescript
+import { Compiler } from '@0xproject/sol-compiler';
+
+const compiler = new Compiler();
+
+(async () => {
+ await compiler.compileAllAsync();
+})().catch(console.log);
+```
diff --git a/packages/website/md/docs/sol_cov/usage.md b/packages/website/md/docs/sol_cov/usage.md
index ea1982d97..63a88f595 100644
--- a/packages/website/md/docs/sol_cov/usage.md
+++ b/packages/website/md/docs/sol_cov/usage.md
@@ -12,7 +12,7 @@ const contractsPath = 'src/contracts';
const networkId = 50;
// Some calls might not have `from` address specified. Nevertheless - transactions need to be submitted from an address with at least some funds. defaultFromAddress is the address that will be used to submit those calls as transactions from.
const defaultFromAddress = '0x5409ed021d9299bf6814279a6a1411a7e866a631';
-const coverageSubprovider = new CoverageSubprovider(artifactsPath, contractsPath, networkId, defaultFromAddress);
+const coverageSubprovider = new CoverageSubprovider(artifactsPath, contractsPath, defaultFromAddress);
provider.addProvider(coverageSubprovider);
```
diff --git a/packages/website/package.json b/packages/website/package.json
index 9eef5a88c..ad84a3eb9 100644
--- a/packages/website/package.json
+++ b/packages/website/package.json
@@ -1,6 +1,6 @@
{
"name": "@0xproject/website",
- "version": "0.0.28",
+ "version": "0.0.32",
"private": true,
"description": "Website and 0x portal dapp",
"scripts": {
@@ -14,13 +14,13 @@
"author": "Fabio Berger",
"license": "Apache-2.0",
"dependencies": {
- "0x.js": "^0.36.3",
- "@0xproject/react-docs": "^0.0.8",
- "@0xproject/react-shared": "^0.1.3",
- "@0xproject/subproviders": "^0.9.0",
- "@0xproject/typescript-typings": "^0.2.0",
- "@0xproject/utils": "^0.5.2",
- "@0xproject/web3-wrapper": "^0.6.1",
+ "0x.js": "^0.37.2",
+ "@0xproject/react-docs": "^0.0.11",
+ "@0xproject/react-shared": "^0.1.6",
+ "@0xproject/subproviders": "^0.10.1",
+ "@0xproject/typescript-typings": "^0.3.1",
+ "@0xproject/utils": "^0.6.1",
+ "@0xproject/web3-wrapper": "^0.6.3",
"accounting": "^0.4.1",
"basscss": "^8.0.3",
"blockies": "^0.0.2",
@@ -48,7 +48,7 @@
"thenby": "^1.2.3",
"truffle-contract": "2.0.1",
"web3": "^0.20.0",
- "web3-provider-engine": "^13.0.1",
+ "web3-provider-engine": "^14.0.4",
"whatwg-fetch": "^2.0.3",
"xml-js": "^1.3.2"
},
@@ -60,7 +60,7 @@
"@types/material-ui": "0.18.0",
"@types/node": "^8.0.53",
"@types/query-string": "^5.1.0",
- "@types/react": "16.0.41",
+ "@types/react": "16.3.13",
"@types/react-copy-to-clipboard": "^4.2.0",
"@types/react-dom": "^16.0.3",
"@types/react-redux": "^4.4.37",
diff --git a/packages/website/public/images/landing/project_logos/the_ocean.png b/packages/website/public/images/landing/project_logos/the_ocean.png
index 74678b5d4..0677abc29 100644
--- a/packages/website/public/images/landing/project_logos/the_ocean.png
+++ b/packages/website/public/images/landing/project_logos/the_ocean.png
Binary files differ
diff --git a/packages/website/public/images/team/greg.jpeg b/packages/website/public/images/team/greg.jpeg
new file mode 100644
index 000000000..a765e047f
--- /dev/null
+++ b/packages/website/public/images/team/greg.jpeg
Binary files differ
diff --git a/packages/website/public/images/team/philippe.png b/packages/website/public/images/team/philippe.png
deleted file mode 100644
index cd43c2754..000000000
--- a/packages/website/public/images/team/philippe.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/remco.jpeg b/packages/website/public/images/team/remco.jpeg
new file mode 100644
index 000000000..e87e7bfd6
--- /dev/null
+++ b/packages/website/public/images/team/remco.jpeg
Binary files differ
diff --git a/packages/website/translations/chinese.json b/packages/website/translations/chinese.json
index f610bf56c..966457a93 100644
--- a/packages/website/translations/chinese.json
+++ b/packages/website/translations/chinese.json
@@ -56,7 +56,7 @@
"ABOUT": "关于我们",
"CAREERS": "人才招聘",
"CONTACT": "联系方式",
- "DEPLOYER": "Deployer",
+ "SOL_COMPILER": "Solidity Compiler",
"JSON_SCHEMAS": "JSON Schemas",
"SOL_COV": "Solidity Coverage",
"SUBPROVIDERS": "Subproviders",
@@ -66,6 +66,7 @@
"WHITEPAPER": "白皮书",
"WIKI": "维基",
"WEB3_WRAPPER": "Web3Wrapper",
+ "ORDER_UTILS": "Order Utils",
"FAQ": "FAQ",
"SMART_CONTRACTS": "0x 智能合约",
"STANDARD_RELAYER_API": "中继方标准API",
diff --git a/packages/website/translations/english.json b/packages/website/translations/english.json
index 122d445cb..f3acea3be 100644
--- a/packages/website/translations/english.json
+++ b/packages/website/translations/english.json
@@ -57,7 +57,7 @@
"ABOUT": "about",
"CAREERS": "careers",
"CONTACT": "contact",
- "DEPLOYER": "Deployer",
+ "SOL_COMPILER": "Solidity Compiler",
"JSON_SCHEMAS": "JSON Schemas",
"SOL_COV": "Solidity Coverage",
"SUBPROVIDERS": "Subproviders",
@@ -67,6 +67,7 @@
"WHITEPAPER": "whitepaper",
"WIKI": "wiki",
"WEB3_WRAPPER": "Web3Wrapper",
+ "ORDER_UTILS": "Order Utils",
"FAQ": "FAQ",
"SMART_CONTRACTS": "0x smart contracts",
"STANDARD_RELAYER_API": "standard relayer API",
diff --git a/packages/website/translations/korean.json b/packages/website/translations/korean.json
index dd5f19b16..7414207f7 100644
--- a/packages/website/translations/korean.json
+++ b/packages/website/translations/korean.json
@@ -56,7 +56,7 @@
"ABOUT": "기업 정보",
"CAREERS": "채용",
"CONTACT": "문의",
- "DEPLOYER": "Deployer",
+ "SOL_COMPILER": "Solidity Compiler",
"JSON_SCHEMAS": "JSON Schemas",
"SOL_COV": "Solidity Coverage",
"SUBPROVIDERS": "Subproviders",
@@ -66,6 +66,7 @@
"WHITEPAPER": "백서",
"WIKI": "위키",
"WEB3_WRAPPER": "Web3Wrapper",
+ "ORDER_UTILS": "Order Utils",
"FAQ": "FAQ",
"SMART_CONTRACTS": "0x 스마트 계약",
"STANDARD_RELAYER_API": "Standard Relayer API",
diff --git a/packages/website/translations/russian.json b/packages/website/translations/russian.json
index 5a8e2c539..75ab02a27 100644
--- a/packages/website/translations/russian.json
+++ b/packages/website/translations/russian.json
@@ -56,7 +56,7 @@
"ABOUT": "Kоманда",
"CAREERS": "Карьера",
"CONTACT": "Связаться с нами",
- "DEPLOYER": "Deployer",
+ "SOL_COMPILER": "Solidity Compiler",
"JSON_SCHEMAS": "JSON Schemas",
"SOL_COV": "Solidity Coverage",
"SUBPROVIDERS": "Subproviders",
@@ -66,6 +66,7 @@
"WHITEPAPER": "Whitepaper",
"WIKI": "Вики",
"WEB3_WRAPPER": "Web3Wrapper",
+ "ORDER_UTILS": "Order Utils",
"FAQ": "Документация",
"SMART_CONTRACTS": "0x Смарт-контракты ",
"STANDARD_RELAYER_API": "standard relayer API",
diff --git a/packages/website/translations/spanish.json b/packages/website/translations/spanish.json
index dd34e805c..8f537ea40 100644
--- a/packages/website/translations/spanish.json
+++ b/packages/website/translations/spanish.json
@@ -57,7 +57,7 @@
"ABOUT": "equipo",
"CAREERS": "empleo",
"CONTACT": "contacto",
- "DEPLOYER": "Deployer",
+ "SOL_COMPILER": "Solidity Compiler",
"JSON_SCHEMAS": "JSON Schemas",
"SOL_COV": "Solidity Coverage",
"SUBPROVIDERS": "Subproviders",
@@ -67,6 +67,7 @@
"WHITEPAPER": "documento técnico",
"WIKI": "wiki",
"WEB3_WRAPPER": "Web3Wrapper",
+ "ORDER_UTILS": "Order Utils",
"FAQ": "preguntas frecuentes",
"SMART_CONTRACTS": "0x contratos inteligentes",
"STANDARD_RELAYER_API": "API de transmisión estándar",
diff --git a/packages/website/ts/components/portal.tsx b/packages/website/ts/components/legacy_portal/legacy_portal.tsx
index b79f5e288..c45b20365 100644
--- a/packages/website/ts/components/portal.tsx
+++ b/packages/website/ts/components/legacy_portal/legacy_portal.tsx
@@ -14,7 +14,7 @@ import { WrappedEthSectionNoticeDialog } from 'ts/components/dialogs/wrapped_eth
import { EthWrappers } from 'ts/components/eth_wrappers';
import { FillOrder } from 'ts/components/fill_order';
import { Footer } from 'ts/components/footer';
-import { PortalMenu } from 'ts/components/portal_menu';
+import { LegacyPortalMenu } from 'ts/components/legacy_portal/legacy_portal_menu';
import { RelayerIndex } from 'ts/components/relayer_index/relayer_index';
import { TokenBalances } from 'ts/components/token_balances';
import { TopBar } from 'ts/components/top_bar/top_bar';
@@ -43,9 +43,7 @@ import { utils } from 'ts/utils/utils';
const THROTTLE_TIMEOUT = 100;
-export interface PortalPassedProps {}
-
-export interface PortalAllProps {
+export interface LegacyPortalProps {
blockchainErr: BlockchainErrs;
blockchainIsLoaded: boolean;
dispatcher: Dispatcher;
@@ -67,7 +65,7 @@ export interface PortalAllProps {
translate: Translate;
}
-interface PortalAllState {
+interface LegacyPortalState {
prevNetworkId: number;
prevNodeVersion: string;
prevUserAddress: string;
@@ -77,7 +75,7 @@ interface PortalAllState {
isLedgerDialogOpen: boolean;
}
-export class Portal extends React.Component<PortalAllProps, PortalAllState> {
+export class LegacyPortal extends React.Component<LegacyPortalProps, LegacyPortalState> {
private _blockchain: Blockchain;
private _sharedOrderIfExists: Order;
private _throttledScreenWidthUpdate: () => void;
@@ -86,13 +84,13 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
const hasAlreadyDismissedWethNotice = !_.isUndefined(didDismissWethNotice) && !_.isEmpty(didDismissWethNotice);
return hasAlreadyDismissedWethNotice;
}
- constructor(props: PortalAllProps) {
+ constructor(props: LegacyPortalProps) {
super(props);
this._sharedOrderIfExists = this._getSharedOrderIfExists();
this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT);
const isViewingBalances = _.includes(props.location.pathname, `${WebsitePaths.Portal}/balances`);
- const hasAlreadyDismissedWethNotice = Portal.hasAlreadyDismissedWethNotice();
+ const hasAlreadyDismissedWethNotice = LegacyPortal.hasAlreadyDismissedWethNotice();
const didAcceptPortalDisclaimer = localStorage.getItemIfExists(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER);
const hasAcceptedDisclaimer =
@@ -123,7 +121,7 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
// become disconnected from their backing Ethereum node, changes user accounts, etc...)
this.props.dispatcher.resetState();
}
- public componentWillReceiveProps(nextProps: PortalAllProps) {
+ public componentWillReceiveProps(nextProps: LegacyPortalProps) {
if (nextProps.networkId !== this.state.prevNetworkId) {
// tslint:disable-next-line:no-floating-promises
this._blockchain.networkIdUpdatedFireAndForgetAsync(nextProps.networkId);
@@ -145,7 +143,7 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
}
if (nextProps.location.pathname !== this.state.prevPathname) {
const isViewingBalances = _.includes(nextProps.location.pathname, `${WebsitePaths.Portal}/balances`);
- const hasAlreadyDismissedWethNotice = Portal.hasAlreadyDismissedWethNotice();
+ const hasAlreadyDismissedWethNotice = LegacyPortal.hasAlreadyDismissedWethNotice();
this.setState({
prevPathname: nextProps.location.pathname,
isWethNoticeDialogOpen: !hasAlreadyDismissedWethNotice && isViewingBalances,
@@ -156,7 +154,6 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
const updateShouldBlockchainErrDialogBeOpen = this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen.bind(
this.props.dispatcher,
);
- const isDevelopment = configs.ENVIRONMENT === Environments.DEVELOPMENT;
const portalStyle: React.CSSProperties = {
minHeight: '100vh',
display: 'flex',
@@ -200,24 +197,12 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
) : (
<div className="mx-auto flex">
<div className="col col-2 pr2 pt1 sm-hide xs-hide" style={portalMenuContainerStyle}>
- <PortalMenu menuItemStyle={{ color: colors.white }} />
+ <LegacyPortalMenu menuItemStyle={{ color: colors.white }} />
</div>
<div className="col col-12 lg-col-10 md-col-10 sm-col sm-col-12">
<div className="py2" style={{ backgroundColor: colors.grey50 }}>
{this.props.blockchainIsLoaded ? (
<Switch>
- {isDevelopment && (
- <Route
- path={`${WebsitePaths.Portal}/wallet`}
- render={this._renderWallet.bind(this)}
- />
- )}
- {isDevelopment && (
- <Route
- path={`${WebsitePaths.Portal}/relayers`}
- render={this._renderRelayers.bind(this)}
- />
- )}
<Route
path={`${WebsitePaths.Portal}/weth`}
render={this._renderEthWrapper.bind(this)}
@@ -296,40 +281,6 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
isLedgerDialogOpen: !this.state.isLedgerDialogOpen,
});
}
- private _renderWallet() {
- const allTokens = _.values(this.props.tokenByAddress);
- const trackedTokens = _.filter(allTokens, t => t.isTracked);
- return (
- <div className="flex flex-center">
- <div className="mx-auto">
- <Wallet
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- blockchain={this._blockchain}
- blockchainIsLoaded={this.props.blockchainIsLoaded}
- blockchainErr={this.props.blockchainErr}
- dispatcher={this.props.dispatcher}
- tokenByAddress={this.props.tokenByAddress}
- trackedTokens={trackedTokens}
- userEtherBalanceInWei={this.props.userEtherBalanceInWei}
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- injectedProviderName={this.props.injectedProviderName}
- providerType={this.props.providerType}
- onToggleLedgerDialog={this.onToggleLedgerDialog.bind(this)}
- />
- </div>
- </div>
- );
- }
- private _renderRelayers() {
- return (
- <div className="flex flex-center">
- <div className="mx-auto" style={{ width: 800 }}>
- <RelayerIndex networkId={this.props.networkId} />
- </div>
- </div>
- );
- }
private _renderEthWrapper() {
return (
<EthWrappers
diff --git a/packages/website/ts/components/portal_menu.tsx b/packages/website/ts/components/legacy_portal/legacy_portal_menu.tsx
index 2b4d7eea2..94113f066 100644
--- a/packages/website/ts/components/portal_menu.tsx
+++ b/packages/website/ts/components/legacy_portal/legacy_portal_menu.tsx
@@ -4,15 +4,15 @@ import { MenuItem } from 'ts/components/ui/menu_item';
import { Environments, WebsitePaths } from 'ts/types';
import { configs } from 'ts/utils/configs';
-export interface PortalMenuProps {
+export interface LegacyPortalMenuProps {
menuItemStyle: React.CSSProperties;
onClick?: () => void;
}
-interface PortalMenuState {}
+interface LegacyPortalMenuState {}
-export class PortalMenu extends React.Component<PortalMenuProps, PortalMenuState> {
- public static defaultProps: Partial<PortalMenuProps> = {
+export class LegacyPortalMenu extends React.Component<LegacyPortalMenuProps, LegacyPortalMenuState> {
+ public static defaultProps: Partial<LegacyPortalMenuProps> = {
onClick: _.noop,
};
public render() {
@@ -58,26 +58,6 @@ export class PortalMenu extends React.Component<PortalMenuProps, PortalMenuState
>
{this._renderMenuItemWithIcon('Wrap ETH', 'zmdi-circle-o')}
</MenuItem>
- {configs.ENVIRONMENT === Environments.DEVELOPMENT && (
- <div>
- <MenuItem
- style={this.props.menuItemStyle}
- className="py2"
- to={`${WebsitePaths.Portal}/wallet`}
- onClick={this.props.onClick.bind(this)}
- >
- {this._renderMenuItemWithIcon('Wallet', 'zmdi-balance-wallet')}
- </MenuItem>
- <MenuItem
- style={this.props.menuItemStyle}
- className="py2"
- to={`${WebsitePaths.Portal}/relayers`}
- onClick={this.props.onClick.bind(this)}
- >
- {this._renderMenuItemWithIcon('Relayers', 'zmdi-input-antenna')}
- </MenuItem>
- </div>
- )}
</div>
);
}
diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx
new file mode 100644
index 000000000..4cbc65ce4
--- /dev/null
+++ b/packages/website/ts/components/portal/portal.tsx
@@ -0,0 +1,297 @@
+import { colors, Styles } from '@0xproject/react-shared';
+import { BigNumber } from '@0xproject/utils';
+import * as _ from 'lodash';
+import * as React from 'react';
+import * as DocumentTitle from 'react-document-title';
+
+import { Blockchain } from 'ts/blockchain';
+import { BlockchainErrDialog } from 'ts/components/dialogs/blockchain_err_dialog';
+import { LedgerConfigDialog } from 'ts/components/dialogs/ledger_config_dialog';
+import { PortalDisclaimerDialog } from 'ts/components/dialogs/portal_disclaimer_dialog';
+import { AssetPicker } from 'ts/components/generate_order/asset_picker';
+import { RelayerIndex } from 'ts/components/relayer_index/relayer_index';
+import { TopBar, TopBarDisplayType } from 'ts/components/top_bar/top_bar';
+import { FlashMessage } from 'ts/components/ui/flash_message';
+import { Wallet } from 'ts/components/wallet/wallet';
+import { localStorage } from 'ts/local_storage/local_storage';
+import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage';
+import { Dispatcher } from 'ts/redux/dispatcher';
+import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, TokenByAddress, TokenVisibility } from 'ts/types';
+import { configs } from 'ts/utils/configs';
+import { constants } from 'ts/utils/constants';
+import { Translate } from 'ts/utils/translate';
+import { utils } from 'ts/utils/utils';
+
+export interface PortalProps {
+ blockchainErr: BlockchainErrs;
+ blockchainIsLoaded: boolean;
+ dispatcher: Dispatcher;
+ hashData: HashData;
+ injectedProviderName: string;
+ networkId: number;
+ nodeVersion: string;
+ orderFillAmount: BigNumber;
+ providerType: ProviderType;
+ screenWidth: ScreenWidths;
+ tokenByAddress: TokenByAddress;
+ userEtherBalanceInWei: BigNumber;
+ userAddress: string;
+ shouldBlockchainErrDialogBeOpen: boolean;
+ userSuppliedOrderCache: Order;
+ location: Location;
+ flashMessage?: string | React.ReactNode;
+ lastForceTokenStateRefetch: number;
+ translate: Translate;
+}
+
+interface PortalState {
+ prevNetworkId: number;
+ prevNodeVersion: string;
+ prevUserAddress: string;
+ prevPathname: string;
+ isDisclaimerDialogOpen: boolean;
+ isLedgerDialogOpen: boolean;
+ tokenManagementState: TokenManagementState;
+}
+
+enum TokenManagementState {
+ Add = 'Add',
+ Remove = 'Remove',
+ None = 'None',
+}
+
+const THROTTLE_TIMEOUT = 100;
+const TOP_BAR_HEIGHT = TopBar.heightForDisplayType(TopBarDisplayType.Expanded);
+
+const styles: Styles = {
+ root: {
+ width: '100%',
+ height: '100%',
+ backgroundColor: colors.lightestGrey,
+ },
+ body: {
+ height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`,
+ },
+ scrollContainer: {
+ height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`,
+ WebkitOverflowScrolling: 'touch',
+ overflow: 'auto',
+ },
+ title: {
+ fontWeight: 'bold',
+ fontSize: 20,
+ },
+};
+
+export class Portal extends React.Component<PortalProps, PortalState> {
+ private _blockchain: Blockchain;
+ private _throttledScreenWidthUpdate: () => void;
+ constructor(props: PortalProps) {
+ super(props);
+ this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT);
+ const didAcceptPortalDisclaimer = localStorage.getItemIfExists(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER);
+ const hasAcceptedDisclaimer =
+ !_.isUndefined(didAcceptPortalDisclaimer) && !_.isEmpty(didAcceptPortalDisclaimer);
+ this.state = {
+ prevNetworkId: this.props.networkId,
+ prevNodeVersion: this.props.nodeVersion,
+ prevUserAddress: this.props.userAddress,
+ prevPathname: this.props.location.pathname,
+ isDisclaimerDialogOpen: !hasAcceptedDisclaimer,
+ tokenManagementState: TokenManagementState.None,
+ isLedgerDialogOpen: false,
+ };
+ }
+ public componentDidMount() {
+ window.addEventListener('resize', this._throttledScreenWidthUpdate);
+ window.scrollTo(0, 0);
+ }
+ public componentWillMount() {
+ this._blockchain = new Blockchain(this.props.dispatcher);
+ }
+ public componentWillUnmount() {
+ this._blockchain.destroy();
+ window.removeEventListener('resize', this._throttledScreenWidthUpdate);
+ // We re-set the entire redux state when the portal is unmounted so that when it is re-rendered
+ // the initialization process always occurs from the same base state. This helps avoid
+ // initialization inconsistencies (i.e While the portal was unrendered, the user might have
+ // become disconnected from their backing Ethereum node, changed user accounts, etc...)
+ this.props.dispatcher.resetState();
+ }
+ public componentWillReceiveProps(nextProps: PortalProps) {
+ if (nextProps.networkId !== this.state.prevNetworkId) {
+ // tslint:disable-next-line:no-floating-promises
+ this._blockchain.networkIdUpdatedFireAndForgetAsync(nextProps.networkId);
+ this.setState({
+ prevNetworkId: nextProps.networkId,
+ });
+ }
+ if (nextProps.userAddress !== this.state.prevUserAddress) {
+ const newUserAddress = _.isEmpty(nextProps.userAddress) ? undefined : nextProps.userAddress;
+ // tslint:disable-next-line:no-floating-promises
+ this._blockchain.userAddressUpdatedFireAndForgetAsync(newUserAddress);
+ this.setState({
+ prevUserAddress: nextProps.userAddress,
+ });
+ }
+ if (nextProps.nodeVersion !== this.state.prevNodeVersion) {
+ // tslint:disable-next-line:no-floating-promises
+ this._blockchain.nodeVersionUpdatedFireAndForgetAsync(nextProps.nodeVersion);
+ }
+ if (nextProps.location.pathname !== this.state.prevPathname) {
+ this.setState({
+ prevPathname: nextProps.location.pathname,
+ });
+ }
+ }
+ public render() {
+ const updateShouldBlockchainErrDialogBeOpen = this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen.bind(
+ this.props.dispatcher,
+ );
+ const allTokens = _.values(this.props.tokenByAddress);
+ const trackedTokens = _.filter(allTokens, t => t.isTracked);
+ const isAssetPickerDialogOpen = this.state.tokenManagementState !== TokenManagementState.None;
+ const tokenVisibility =
+ this.state.tokenManagementState === TokenManagementState.Add
+ ? TokenVisibility.UNTRACKED
+ : TokenVisibility.TRACKED;
+ return (
+ <div style={styles.root}>
+ <DocumentTitle title="0x Portal DApp" />
+ <TopBar
+ userAddress={this.props.userAddress}
+ networkId={this.props.networkId}
+ injectedProviderName={this.props.injectedProviderName}
+ onToggleLedgerDialog={this._onToggleLedgerDialog.bind(this)}
+ dispatcher={this.props.dispatcher}
+ providerType={this.props.providerType}
+ blockchainIsLoaded={this.props.blockchainIsLoaded}
+ location={this.props.location}
+ blockchain={this._blockchain}
+ translate={this.props.translate}
+ displayType={TopBarDisplayType.Expanded}
+ style={{ backgroundColor: colors.lightestGrey }}
+ />
+ <div id="portal" style={styles.body}>
+ <div className="sm-flex flex-center">
+ <div className="flex-last px3">
+ <div className="py3" style={styles.title}>
+ Your Account
+ </div>
+ <Wallet
+ userAddress={this.props.userAddress}
+ networkId={this.props.networkId}
+ blockchain={this._blockchain}
+ blockchainIsLoaded={this.props.blockchainIsLoaded}
+ blockchainErr={this.props.blockchainErr}
+ dispatcher={this.props.dispatcher}
+ tokenByAddress={this.props.tokenByAddress}
+ trackedTokens={trackedTokens}
+ userEtherBalanceInWei={this.props.userEtherBalanceInWei}
+ lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
+ injectedProviderName={this.props.injectedProviderName}
+ providerType={this.props.providerType}
+ onToggleLedgerDialog={this._onToggleLedgerDialog.bind(this)}
+ onAddToken={this._onAddToken.bind(this)}
+ onRemoveToken={this._onRemoveToken.bind(this)}
+ />
+ </div>
+ <div className="flex-auto px3" style={styles.scrollContainer}>
+ <div className="py3" style={styles.title}>
+ Explore 0x Ecosystem
+ </div>
+ <RelayerIndex networkId={this.props.networkId} />
+ </div>
+ </div>
+ <BlockchainErrDialog
+ blockchain={this._blockchain}
+ blockchainErr={this.props.blockchainErr}
+ isOpen={this.props.shouldBlockchainErrDialogBeOpen}
+ userAddress={this.props.userAddress}
+ toggleDialogFn={updateShouldBlockchainErrDialogBeOpen}
+ networkId={this.props.networkId}
+ />
+ <PortalDisclaimerDialog
+ isOpen={this.state.isDisclaimerDialogOpen}
+ onToggleDialog={this._onPortalDisclaimerAccepted.bind(this)}
+ />
+ <FlashMessage dispatcher={this.props.dispatcher} flashMessage={this.props.flashMessage} />
+ {this.props.blockchainIsLoaded && (
+ <LedgerConfigDialog
+ providerType={this.props.providerType}
+ networkId={this.props.networkId}
+ blockchain={this._blockchain}
+ dispatcher={this.props.dispatcher}
+ toggleDialogFn={this._onToggleLedgerDialog.bind(this)}
+ isOpen={this.state.isLedgerDialogOpen}
+ />
+ )}
+ <AssetPicker
+ userAddress={this.props.userAddress}
+ networkId={this.props.networkId}
+ blockchain={this._blockchain}
+ dispatcher={this.props.dispatcher}
+ isOpen={isAssetPickerDialogOpen}
+ currentTokenAddress={''}
+ onTokenChosen={this._onTokenChosen.bind(this)}
+ tokenByAddress={this.props.tokenByAddress}
+ tokenVisibility={tokenVisibility}
+ />
+ </div>
+ </div>
+ );
+ }
+ private _onTokenChosen(tokenAddress: string) {
+ if (_.isEmpty(tokenAddress)) {
+ this.setState({
+ tokenManagementState: TokenManagementState.None,
+ });
+ return;
+ }
+ const token = this.props.tokenByAddress[tokenAddress];
+ const isDefaultTrackedToken = _.includes(configs.DEFAULT_TRACKED_TOKEN_SYMBOLS, token.symbol);
+ if (this.state.tokenManagementState === TokenManagementState.Remove && !isDefaultTrackedToken) {
+ if (token.isRegistered) {
+ // Remove the token from tracked tokens
+ const newToken = {
+ ...token,
+ isTracked: false,
+ };
+ this.props.dispatcher.updateTokenByAddress([newToken]);
+ } else {
+ this.props.dispatcher.removeTokenToTokenByAddress(token);
+ }
+ trackedTokenStorage.removeTrackedToken(this.props.userAddress, this.props.networkId, tokenAddress);
+ } else if (isDefaultTrackedToken) {
+ this.props.dispatcher.showFlashMessage(`Cannot remove ${token.name} because it's a default token`);
+ }
+ this.setState({
+ tokenManagementState: TokenManagementState.None,
+ });
+ }
+ private _onToggleLedgerDialog() {
+ this.setState({
+ isLedgerDialogOpen: !this.state.isLedgerDialogOpen,
+ });
+ }
+ private _onAddToken() {
+ this.setState({
+ tokenManagementState: TokenManagementState.Add,
+ });
+ }
+ private _onRemoveToken() {
+ this.setState({
+ tokenManagementState: TokenManagementState.Remove,
+ });
+ }
+ private _onPortalDisclaimerAccepted() {
+ localStorage.setItem(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER, 'set');
+ this.setState({
+ isDisclaimerDialogOpen: false,
+ });
+ }
+ private _updateScreenWidth() {
+ const newScreenWidth = utils.getScreenWidth();
+ this.props.dispatcher.updateScreenWidth(newScreenWidth);
+ }
+}
diff --git a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx
index 0c4b2841c..d88a59d15 100644
--- a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx
+++ b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx
@@ -12,38 +12,6 @@ export interface RelayerGridTileProps {
networkId: number;
}
-// TODO: Get top tokens and headerurl from remote
-const headerUrl = '/images/og_image.png';
-const topTokens = [
- {
- address: '0x1dad4783cf3fe3085c1426157ab175a6119a04ba',
- decimals: 18,
- iconUrl: '/images/token_icons/makerdao.png',
- isRegistered: true,
- isTracked: true,
- name: 'Maker DAO',
- symbol: 'MKR',
- },
- {
- address: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
- decimals: 18,
- iconUrl: '/images/token_icons/melon.png',
- isRegistered: true,
- isTracked: true,
- name: 'Melon Token',
- symbol: 'MLN',
- },
- {
- address: '0xb18845c260f680d5b9d84649638813e342e4f8c9',
- decimals: 18,
- iconUrl: '/images/token_icons/augur.png',
- isRegistered: true,
- isTracked: true,
- name: 'Augur Reputation Token',
- symbol: 'REP',
- },
-];
-
const styles: Styles = {
root: {
backgroundColor: colors.white,
@@ -68,6 +36,9 @@ const styles: Styles = {
borderBottomLeftRadius: 4,
borderTopRightRadius: 4,
borderTopLeftRadius: 4,
+ borderWidth: 1,
+ borderStyle: 'solid',
+ borderColor: colors.walletBorder,
},
body: {
paddingLeft: 6,
@@ -91,11 +62,20 @@ const styles: Styles = {
},
};
+const FALLBACK_IMG_SRC = '/images/landing/hero_chip_image.png';
+
export const RelayerGridTile: React.StatelessComponent<RelayerGridTileProps> = (props: RelayerGridTileProps) => {
+ const link = props.relayerInfo.appUrl || props.relayerInfo.url;
return (
<GridTile style={styles.root}>
<div style={styles.innerDiv}>
- <img src={headerUrl} style={styles.header} />
+ <a href={link} target="_blank" style={{ textDecoration: 'none' }}>
+ <ImgWithFallback
+ src={props.relayerInfo.headerImgUrl}
+ fallbackSrc={FALLBACK_IMG_SRC}
+ style={styles.header}
+ />
+ </a>
<div style={styles.body}>
<div className="py1" style={styles.relayerNameLabel}>
{props.relayerInfo.name}
@@ -104,7 +84,7 @@ export const RelayerGridTile: React.StatelessComponent<RelayerGridTileProps> = (
<div className="py1" style={styles.subLabel}>
Daily Trade Volume
</div>
- <TopTokens tokens={topTokens} networkId={props.networkId} />
+ <TopTokens tokens={props.relayerInfo.topTokens} networkId={props.networkId} />
<div className="py1" style={styles.subLabel}>
Top tokens
</div>
@@ -113,3 +93,32 @@ export const RelayerGridTile: React.StatelessComponent<RelayerGridTileProps> = (
</GridTile>
);
};
+
+interface ImgWithFallbackProps {
+ src?: string;
+ fallbackSrc: string;
+ style: React.CSSProperties;
+}
+interface ImgWithFallbackState {
+ imageLoadFailed: boolean;
+}
+class ImgWithFallback extends React.Component<ImgWithFallbackProps, ImgWithFallbackState> {
+ constructor(props: ImgWithFallbackProps) {
+ super(props);
+ this.state = {
+ imageLoadFailed: false,
+ };
+ }
+ public render() {
+ if (this.state.imageLoadFailed || _.isUndefined(this.props.src)) {
+ return <img src={this.props.fallbackSrc} style={this.props.style} />;
+ } else {
+ return <img src={this.props.src} onError={this._onError.bind(this)} style={this.props.style} />;
+ }
+ }
+ private _onError() {
+ this.setState({
+ imageLoadFailed: true,
+ });
+ }
+}
diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx
index 50760c32d..dffd0f83f 100644
--- a/packages/website/ts/components/relayer_index/relayer_index.tsx
+++ b/packages/website/ts/components/relayer_index/relayer_index.tsx
@@ -1,5 +1,7 @@
import { colors, Styles } from '@0xproject/react-shared';
import * as _ from 'lodash';
+import CircularProgress from 'material-ui/CircularProgress';
+import FlatButton from 'material-ui/FlatButton';
import { GridList } from 'material-ui/GridList';
import * as React from 'react';
@@ -32,9 +34,9 @@ const styles: Styles = {
},
};
-const CELL_HEIGHT = 260;
+const CELL_HEIGHT = 290;
const NUMBER_OF_COLUMNS = 4;
-const GRID_PADDING = 16;
+const GRID_PADDING = 20;
export class RelayerIndex extends React.Component<RelayerIndexProps, RelayerIndexState> {
private _isUnmounted: boolean;
@@ -55,7 +57,24 @@ export class RelayerIndex extends React.Component<RelayerIndexProps, RelayerInde
}
public render() {
const readyToRender = _.isUndefined(this.state.error) && !_.isUndefined(this.state.relayerInfos);
- if (readyToRender) {
+ if (!readyToRender) {
+ return (
+ <div className="col col-12" style={{ ...styles.root, height: '100%' }}>
+ <div
+ className="relative sm-px2 sm-pt2 sm-m1"
+ style={{ height: 122, top: '33%', transform: 'translateY(-50%)' }}
+ >
+ <div className="center pb2">
+ {_.isUndefined(this.state.error) ? (
+ <CircularProgress size={40} thickness={5} />
+ ) : (
+ <Retry onRetry={this._fetchRelayerInfosAsync.bind(this)} />
+ )}
+ </div>
+ </div>
+ </div>
+ );
+ } else {
return (
<div style={styles.root}>
<GridList
@@ -64,23 +83,22 @@ export class RelayerIndex extends React.Component<RelayerIndexProps, RelayerInde
padding={GRID_PADDING}
style={styles.gridList}
>
- {this.state.relayerInfos.map((relayerInfo: WebsiteBackendRelayerInfo) => (
- <RelayerGridTile
- key={relayerInfo.id}
- relayerInfo={relayerInfo}
- networkId={this.props.networkId}
- />
+ {this.state.relayerInfos.map((relayerInfo: WebsiteBackendRelayerInfo, index) => (
+ <RelayerGridTile key={index} relayerInfo={relayerInfo} networkId={this.props.networkId} />
))}
</GridList>
</div>
);
- } else {
- // TODO: loading and error states with a scrolling container
- return null;
}
}
private async _fetchRelayerInfosAsync(): Promise<void> {
try {
+ if (!this._isUnmounted) {
+ this.setState({
+ relayerInfos: undefined,
+ error: undefined,
+ });
+ }
const relayerInfos = await backendClient.getRelayerInfosAsync();
if (!this._isUnmounted) {
this.setState({
@@ -96,3 +114,31 @@ export class RelayerIndex extends React.Component<RelayerIndexProps, RelayerInde
}
}
}
+
+interface RetryProps {
+ onRetry: () => void;
+}
+const Retry = (props: RetryProps) => (
+ <div className="clearfix center" style={{ color: colors.black }}>
+ <div className="mx-auto inline-block align-middle" style={{ lineHeight: '44px', textAlign: 'center' }}>
+ <div className="h2" style={{ fontFamily: 'Roboto Mono' }}>
+ Something went wrong.
+ </div>
+ <div className="py3">
+ <FlatButton
+ label={'reload'}
+ backgroundColor={colors.black}
+ labelStyle={{
+ fontSize: 18,
+ fontFamily: 'Roboto Mono',
+ fontWeight: 'lighter',
+ color: colors.white,
+ textTransform: 'lowercase',
+ }}
+ style={{ width: 280, height: 62, borderRadius: 5 }}
+ onClick={props.onRetry}
+ />
+ </div>
+ </div>
+ </div>
+);
diff --git a/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx b/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx
index 233590b78..db4d3a211 100644
--- a/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx
+++ b/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx
@@ -3,10 +3,10 @@ import * as _ from 'lodash';
import * as React from 'react';
import { TokenIcon } from 'ts/components/ui/token_icon';
-import { Token } from 'ts/types';
+import { WebsiteBackendTokenInfo } from 'ts/types';
export interface TopTokensProps {
- tokens: Token[];
+ tokens: WebsiteBackendTokenInfo[];
networkId: number;
}
@@ -23,17 +23,17 @@ const styles: Styles = {
export const TopTokens: React.StatelessComponent<TopTokensProps> = (props: TopTokensProps) => {
return (
<div className="flex">
- {_.map(props.tokens, (token: Token, index: number) => {
+ {_.map(props.tokens, (tokenInfo: WebsiteBackendTokenInfo, index: number) => {
const firstItemStyle = { ...styles.tokenLabel, ...styles.followingTokenLabel };
const style = index !== 0 ? firstItemStyle : styles.tokenLabel;
return (
<a
- key={token.address}
- href={tokenLinkFromToken(token, props.networkId)}
+ key={tokenInfo.address}
+ href={tokenLinkFromToken(tokenInfo, props.networkId)}
target="_blank"
style={style}
>
- {token.symbol}
+ {tokenInfo.symbol}
</a>
);
})}
@@ -41,6 +41,6 @@ export const TopTokens: React.StatelessComponent<TopTokensProps> = (props: TopTo
);
};
-function tokenLinkFromToken(token: Token, networkId: number) {
- return sharedUtils.getEtherScanLinkIfExists(token.address, networkId, EtherscanLinkSuffixes.Address);
+function tokenLinkFromToken(tokenInfo: WebsiteBackendTokenInfo, networkId: number) {
+ return sharedUtils.getEtherScanLinkIfExists(tokenInfo.address, networkId, EtherscanLinkSuffixes.Address);
}
diff --git a/packages/website/ts/components/top_bar/provider_display.tsx b/packages/website/ts/components/top_bar/provider_display.tsx
index 79e7c3e2d..dc6ade841 100644
--- a/packages/website/ts/components/top_bar/provider_display.tsx
+++ b/packages/website/ts/components/top_bar/provider_display.tsx
@@ -1,4 +1,4 @@
-import { colors } from '@0xproject/react-shared';
+import { colors, Styles } from '@0xproject/react-shared';
import * as _ from 'lodash';
import RaisedButton from 'material-ui/RaisedButton';
import * as React from 'react';
@@ -11,9 +11,9 @@ import { ProviderType } from 'ts/types';
import { constants } from 'ts/utils/constants';
import { utils } from 'ts/utils/utils';
-const IDENTICON_DIAMETER = 32;
+const ROOT_HEIGHT = 24;
-interface ProviderDisplayProps {
+export interface ProviderDisplayProps {
dispatcher: Dispatcher;
userAddress: string;
networkId: number;
@@ -25,6 +25,15 @@ interface ProviderDisplayProps {
interface ProviderDisplayState {}
+const styles: Styles = {
+ root: {
+ height: ROOT_HEIGHT,
+ backgroundColor: colors.white,
+ borderRadius: ROOT_HEIGHT,
+ boxShadow: `0px 4px 6px ${colors.walletBoxShadow}`,
+ },
+};
+
export class ProviderDisplay extends React.Component<ProviderDisplayProps, ProviderDisplayState> {
public render() {
const isAddressAvailable = !_.isEmpty(this.props.userAddress);
@@ -42,21 +51,20 @@ export class ProviderDisplay extends React.Component<ProviderDisplayProps, Provi
: 'Connect a wallet';
const providerTitle =
this.props.providerType === ProviderType.Injected ? injectedProviderName : 'Ledger Nano S';
+ const isProviderMetamask = providerTitle === constants.PROVIDER_NAME_METAMASK;
const hoverActiveNode = (
- <div className="flex right lg-pr0 md-pr2 sm-pr2" style={{ paddingTop: 16 }}>
+ <div className="flex right lg-pr0 md-pr2 sm-pr2 p1" style={styles.root}>
<div>
- <Identicon address={this.props.userAddress} diameter={IDENTICON_DIAMETER} />
- </div>
- <div style={{ marginLeft: 12, paddingTop: 1 }}>
- <div style={{ fontSize: 12, color: colors.amber800 }}>{providerTitle}</div>
- <div style={{ fontSize: 14 }}>{displayAddress}</div>
+ <Identicon address={this.props.userAddress} diameter={ROOT_HEIGHT} />
</div>
- <div
- style={{ borderLeft: `1px solid ${colors.grey300}`, marginLeft: 17, paddingTop: 1 }}
- className="px2"
- >
- <i style={{ fontSize: 30, color: colors.grey300 }} className="zmdi zmdi zmdi-chevron-down" />
+ <div style={{ marginLeft: 12, paddingTop: 3 }}>
+ <div style={{ fontSize: 16, color: colors.darkGrey }}>{displayAddress}</div>
</div>
+ {isProviderMetamask && (
+ <div style={{ marginLeft: 16 }}>
+ <img src="/images/metamask_icon.png" style={{ width: ROOT_HEIGHT, height: ROOT_HEIGHT }} />
+ </div>
+ )}
</div>
);
const hasInjectedProvider =
diff --git a/packages/website/ts/components/top_bar/top_bar.tsx b/packages/website/ts/components/top_bar/top_bar.tsx
index 13351dcdc..5a1b50310 100644
--- a/packages/website/ts/components/top_bar/top_bar.tsx
+++ b/packages/website/ts/components/top_bar/top_bar.tsx
@@ -8,7 +8,7 @@ import * as React from 'react';
import { Link } from 'react-router-dom';
import ReactTooltip = require('react-tooltip');
import { Blockchain } from 'ts/blockchain';
-import { PortalMenu } from 'ts/components/portal_menu';
+import { LegacyPortalMenu } from 'ts/components/legacy_portal/legacy_portal_menu';
import { SidebarHeader } from 'ts/components/sidebar_header';
import { ProviderDisplay } from 'ts/components/top_bar/provider_display';
import { TopBarMenuItem } from 'ts/components/top_bar/top_bar_menu_item';
@@ -19,7 +19,12 @@ import { Deco, Key, ProviderType, WebsiteLegacyPaths, WebsitePaths } from 'ts/ty
import { constants } from 'ts/utils/constants';
import { Translate } from 'ts/utils/translate';
-interface TopBarProps {
+export enum TopBarDisplayType {
+ Default,
+ Expanded,
+}
+
+export interface TopBarProps {
userAddress?: string;
networkId?: number;
injectedProviderName?: string;
@@ -34,7 +39,7 @@ interface TopBarProps {
availableDocVersions?: string[];
menu?: DocsMenu;
menuSubsectionsBySection?: MenuSubsectionsBySection;
- shouldFullWidth?: boolean;
+ displayType?: TopBarDisplayType;
docsInfo?: DocsInfo;
style?: React.CSSProperties;
isNightVersion?: boolean;
@@ -47,17 +52,8 @@ interface TopBarState {
}
const styles: Styles = {
- address: {
- marginRight: 12,
- overflow: 'hidden',
- paddingTop: 4,
- textOverflow: 'ellipsis',
- whiteSpace: 'nowrap',
- width: 70,
- },
topBar: {
- backgroundcolor: colors.white,
- height: 59,
+ backgroundColor: colors.white,
width: '100%',
position: 'relative',
top: 0,
@@ -78,12 +74,19 @@ const styles: Styles = {
},
};
+const DEFAULT_HEIGHT = 59;
+const EXPANDED_HEIGHT = 75;
+
export class TopBar extends React.Component<TopBarProps, TopBarState> {
public static defaultProps: Partial<TopBarProps> = {
- shouldFullWidth: false,
+ displayType: TopBarDisplayType.Default,
style: {},
isNightVersion: false,
};
+ public static heightForDisplayType(displayType: TopBarDisplayType) {
+ const result = displayType === TopBarDisplayType.Expanded ? EXPANDED_HEIGHT : DEFAULT_HEIGHT;
+ return result + 1;
+ }
constructor(props: TopBarProps) {
super(props);
this.state = {
@@ -92,8 +95,9 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
}
public render() {
const isNightVersion = this.props.isNightVersion;
- const isFullWidthPage = this.props.shouldFullWidth;
- const parentClassNames = `flex mx-auto ${isFullWidthPage ? 'pl2' : 'max-width-4'}`;
+ const isExpandedDisplayType = this.props.displayType === TopBarDisplayType.Expanded;
+ const parentClassNames = `flex mx-auto ${isExpandedDisplayType ? 'pl3 py1' : 'max-width-4'}`;
+ const height = isExpandedDisplayType ? EXPANDED_HEIGHT : DEFAULT_HEIGHT;
const developerSectionMenuItems = [
<Link key="subMenuItem-zeroEx" to={WebsitePaths.ZeroExJs} className="text-decoration-none">
<MenuItem style={{ fontSize: styles.menuItem.fontSize }} primaryText="0x.js" />
@@ -139,10 +143,16 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
primaryText={this.props.translate.get(Key.Web3Wrapper, Deco.CapWords)}
/>
</Link>,
- <Link key="subMenuItem-deployer" to={WebsitePaths.Deployer} className="text-decoration-none">
+ <Link key="subMenuItem-order-utils" to={WebsitePaths.OrderUtils} className="text-decoration-none">
<MenuItem
style={{ fontSize: styles.menuItem.fontSize }}
- primaryText={this.props.translate.get(Key.Deployer, Deco.CapWords)}
+ primaryText={this.props.translate.get(Key.OrderUtils, Deco.CapWords)}
+ />
+ </Link>,
+ <Link key="subMenuItem-sol-compiler" to={WebsitePaths.SolCompiler} className="text-decoration-none">
+ <MenuItem
+ style={{ fontSize: styles.menuItem.fontSize }}
+ primaryText={this.props.translate.get(Key.SolCompiler, Deco.CapWords)}
/>
</Link>,
<Link key="subMenuItem-sol-cov" to={WebsitePaths.SolCov} className="text-decoration-none">
@@ -172,9 +182,11 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
</a>,
];
const bottomBorderStyle = this._shouldDisplayBottomBar() ? styles.bottomBar : {};
- const fullWidthClasses = isFullWidthPage ? 'pr4' : '';
+ const fullWidthClasses = isExpandedDisplayType ? 'pr4' : '';
const logoUrl = isNightVersion ? '/images/protocol_logo_white.png' : '/images/protocol_logo_black.png';
- const menuClasses = `col col-${isFullWidthPage ? '4' : '5'} ${fullWidthClasses} lg-pr0 md-pr2 sm-hide xs-hide`;
+ const menuClasses = `col col-${
+ isExpandedDisplayType ? '4' : '5'
+ } ${fullWidthClasses} lg-pr0 md-pr2 sm-hide xs-hide`;
const menuIconStyle = {
fontSize: 25,
color: isNightVersion ? 'white' : 'black',
@@ -191,15 +203,15 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
);
const popoverContent = <Menu style={{ color: colors.darkGrey }}>{developerSectionMenuItems}</Menu>;
return (
- <div style={{ ...styles.topBar, ...bottomBorderStyle, ...this.props.style }} className="pb1">
+ <div style={{ ...styles.topBar, ...bottomBorderStyle, ...this.props.style, ...{ height } }} className="pb1">
<div className={parentClassNames}>
- <div className="col col-2 sm-pl2 md-pl2 lg-pl0" style={{ paddingTop: 15 }}>
+ <div className="col col-2 sm-pl1 md-pl2 lg-pl0" style={{ paddingTop: 15 }}>
<Link to={`${WebsitePaths.Home}`} className="text-decoration-none">
<img src={logoUrl} height="30" />
</Link>
</div>
- <div className={`col col-${isFullWidthPage ? '8' : '9'} lg-hide md-hide`} />
- <div className={`col col-${isFullWidthPage ? '6' : '5'} sm-hide xs-hide`} />
+ <div className={`col col-${isExpandedDisplayType ? '8' : '9'} lg-hide md-hide`} />
+ <div className={`col col-${isExpandedDisplayType ? '6' : '5'} sm-hide xs-hide`} />
{!this._isViewingPortal() && (
<div className={menuClasses}>
<div className="flex justify-between">
@@ -236,7 +248,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
path={`${WebsitePaths.Portal}`}
isPrimary={true}
style={styles.menuItem}
- className={`${isFullWidthPage && 'md-hide'}`}
+ className={`${isExpandedDisplayType && 'md-hide'}`}
isNightVersion={isNightVersion}
isExternal={false}
/>
@@ -244,7 +256,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
</div>
)}
{this.props.blockchainIsLoaded && (
- <div className="sm-hide xs-hide col col-5">
+ <div className="sm-hide xs-hide col col-5" style={{ paddingTop: 8, marginRight: 36 }}>
<ProviderDisplay
dispatcher={this.props.dispatcher}
userAddress={this.props.userAddress}
@@ -256,7 +268,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
/>
</div>
)}
- <div className={`col ${isFullWidthPage ? 'col-2 pl2' : 'col-1'} md-hide lg-hide`}>
+ <div className={`col ${isExpandedDisplayType ? 'col-2 pl2' : 'col-1'} md-hide lg-hide`}>
<div style={menuIconStyle}>
<i className="zmdi zmdi-menu" onClick={this._onMenuButtonClick.bind(this)} />
</div>
@@ -316,10 +328,10 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
</MenuItem>
</Link>
)}
- {!this._isViewingDeployerDocs() && (
- <Link to={WebsitePaths.Deployer} className="text-decoration-none">
+ {!this._isViewingSolCompilerDocs() && (
+ <Link to={WebsitePaths.SolCompiler} className="text-decoration-none">
<MenuItem className="py2">
- {this.props.translate.get(Key.Deployer, Deco.Cap)}{' '}
+ {this.props.translate.get(Key.SolCompiler, Deco.Cap)}{' '}
{this.props.translate.get(Key.Docs, Deco.Cap)}
</MenuItem>
</Link>
@@ -378,7 +390,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
(!this._isViewing0xjsDocs() &&
!this._isViewingSmartContractsDocs() &&
!this._isViewingWeb3WrapperDocs() &&
- !this._isViewingDeployerDocs() &&
+ !this._isViewingSolCompilerDocs() &&
!this._isViewingJsonSchemasDocs() &&
!this._isViewingSolCovDocs() &&
!this._isViewingSubprovidersDocs() &&
@@ -431,22 +443,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
<div className="pl1 py1" style={{ backgroundColor: colors.lightGrey }}>
{this.props.translate.get(Key.PortalDApp, Deco.CapWords)}
</div>
- <PortalMenu menuItemStyle={{ color: 'black' }} onClick={this._onMenuButtonClick.bind(this)} />
- </div>
- );
- }
- private _renderUser() {
- const userAddress = this.props.userAddress;
- const identiconDiameter = 26;
- return (
- <div className="flex right lg-pr0 md-pr2 sm-pr2" style={{ paddingTop: 16 }}>
- <div style={styles.address} data-tip={true} data-for="userAddressTooltip">
- {!_.isEmpty(userAddress) ? userAddress : ''}
- </div>
- <ReactTooltip id="userAddressTooltip">{userAddress}</ReactTooltip>
- <div>
- <Identicon address={userAddress} diameter={identiconDiameter} />
- </div>
+ <LegacyPortalMenu menuItemStyle={{ color: 'black' }} onClick={this._onMenuButtonClick.bind(this)} />
</div>
);
}
@@ -479,8 +476,8 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
_.includes(this.props.location.pathname, WebsiteLegacyPaths.Web3Wrapper)
);
}
- private _isViewingDeployerDocs() {
- return _.includes(this.props.location.pathname, WebsitePaths.Deployer);
+ private _isViewingSolCompilerDocs() {
+ return _.includes(this.props.location.pathname, WebsitePaths.SolCompiler);
}
private _isViewingJsonSchemasDocs() {
return _.includes(this.props.location.pathname, WebsitePaths.JSONSchemas);
@@ -501,11 +498,12 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
this._isViewingFAQ() ||
this._isViewingSmartContractsDocs() ||
this._isViewingWeb3WrapperDocs() ||
- this._isViewingDeployerDocs() ||
+ this._isViewingSolCompilerDocs() ||
this._isViewingJsonSchemasDocs() ||
this._isViewingSolCovDocs() ||
this._isViewingSubprovidersDocs() ||
- this._isViewingConnectDocs()
+ this._isViewingConnectDocs() ||
+ this._isViewingPortal()
);
}
} // tslint:disable:max-file-line-count
diff --git a/packages/website/ts/components/ui/input_label.tsx b/packages/website/ts/components/ui/input_label.tsx
index 2506db423..8eda45a5d 100644
--- a/packages/website/ts/components/ui/input_label.tsx
+++ b/packages/website/ts/components/ui/input_label.tsx
@@ -17,7 +17,7 @@ const styles: Styles = {
userSelect: 'none',
width: 240,
zIndex: 1,
- },
+ } as React.CSSProperties,
};
export const InputLabel = (props: InputLabelProps) => {
diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx
index d1ae38550..079c0e3b3 100644
--- a/packages/website/ts/components/wallet/wallet.tsx
+++ b/packages/website/ts/components/wallet/wallet.tsx
@@ -9,8 +9,11 @@ import {
import { BigNumber } from '@0xproject/utils';
import * as _ from 'lodash';
import FlatButton from 'material-ui/FlatButton';
+import FloatingActionButton from 'material-ui/FloatingActionButton';
import { List, ListItem } from 'material-ui/List';
import ActionAccountBalanceWallet from 'material-ui/svg-icons/action/account-balance-wallet';
+import ContentAdd from 'material-ui/svg-icons/content/add';
+import ContentRemove from 'material-ui/svg-icons/content/remove';
import NavigationArrowDownward from 'material-ui/svg-icons/navigation/arrow-downward';
import NavigationArrowUpward from 'material-ui/svg-icons/navigation/arrow-upward';
import Close from 'material-ui/svg-icons/navigation/close';
@@ -55,11 +58,14 @@ export interface WalletProps {
injectedProviderName: string;
providerType: ProviderType;
onToggleLedgerDialog: () => void;
+ onAddToken: () => void;
+ onRemoveToken: () => void;
}
interface WalletState {
trackedTokenStateByAddress: TokenStateByAddress;
wrappedEtherDirection?: Side;
+ isHoveringSidebar: boolean;
}
interface AllowanceToggleConfig {
@@ -94,6 +100,9 @@ const styles: Styles = {
},
footerItemInnerDiv: {
paddingLeft: 24,
+ borderTopColor: colors.walletBorder,
+ borderTopStyle: 'solid',
+ borderWidth: 1,
},
borderedItem: {
borderBottomColor: colors.walletBorder,
@@ -114,7 +123,17 @@ const styles: Styles = {
paddingTop: 8,
paddingBottom: 8,
},
- accessoryItemsContainer: { width: 150, right: 8 },
+ accessoryItemsContainer: {
+ width: 150,
+ right: 8,
+ },
+ bodyInnerDiv: {
+ padding: 0,
+ // TODO: make this completely responsive
+ maxHeight: 475,
+ overflow: 'auto',
+ WebkitOverflowScrolling: 'touch',
+ },
};
const ETHER_ICON_PATH = '/images/ether.png';
@@ -123,6 +142,7 @@ const ZRX_TOKEN_SYMBOL = 'ZRX';
const ETHER_SYMBOL = 'ETH';
const ICON_DIMENSION = 24;
const TOKEN_AMOUNT_DISPLAY_PRECISION = 3;
+const BODY_ITEM_KEY = 'BODY';
const HEADER_ITEM_KEY = 'HEADER';
const FOOTER_ITEM_KEY = 'FOOTER';
const DISCONNECTED_ITEM_KEY = 'DISCONNECTED';
@@ -139,6 +159,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
this.state = {
trackedTokenStateByAddress: initialTrackedTokenStateByAddress,
wrappedEtherDirection: undefined,
+ isHoveringSidebar: false,
};
}
public componentWillMount() {
@@ -184,12 +205,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
return (
<List style={styles.list}>
{isAddressAvailable
- ? _.concat(
- this._renderConnectedHeaderRows(),
- this._renderEthRows(),
- this._renderTokenRows(),
- this._renderFooterRows(),
- )
+ ? _.concat(this._renderConnectedHeaderRows(), this._renderBody(), this._renderFooterRows())
: _.concat(this._renderDisconnectedHeaderRows(), this._renderDisconnectedRows())}
</List>
);
@@ -230,9 +246,61 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
/>
);
}
+ private _renderBody() {
+ const bodyStyle: React.CSSProperties = {
+ ...styles.bodyInnerDiv,
+ overflow: this.state.isHoveringSidebar ? 'auto' : 'hidden',
+ };
+ return (
+ <ListItem
+ key={BODY_ITEM_KEY}
+ innerDivStyle={bodyStyle}
+ onMouseEnter={this._onSidebarHover.bind(this)}
+ onMouseLeave={this._onSidebarHoverOff.bind(this)}
+ >
+ {this._renderEthRows()}
+ {this._renderTokenRows()}
+ </ListItem>
+ );
+ }
+ private _onSidebarHover(event: React.FormEvent<HTMLInputElement>) {
+ this.setState({
+ isHoveringSidebar: true,
+ });
+ }
+ private _onSidebarHoverOff() {
+ this.setState({
+ isHoveringSidebar: false,
+ });
+ }
private _renderFooterRows() {
- const primaryText = '+ other tokens';
- return <ListItem key={FOOTER_ITEM_KEY} primaryText={primaryText} innerDivStyle={styles.footerItemInnerDiv} />;
+ return (
+ <ListItem
+ key={FOOTER_ITEM_KEY}
+ primaryText={
+ <div className="flex">
+ <FloatingActionButton mini={true} zDepth={0} onClick={this.props.onAddToken}>
+ <ContentAdd />
+ </FloatingActionButton>
+ <FloatingActionButton mini={true} zDepth={0} className="px1" onClick={this.props.onRemoveToken}>
+ <ContentRemove />
+ </FloatingActionButton>
+ <div
+ style={{
+ paddingLeft: 10,
+ position: 'relative',
+ top: '50%',
+ transform: 'translateY(33%)',
+ }}
+ >
+ add/remove tokens
+ </div>
+ </div>
+ }
+ disabled={true}
+ innerDivStyle={styles.footerItemInnerDiv}
+ />
+ );
}
private _renderEthRows() {
const primaryText = this._renderAmount(
@@ -293,7 +361,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
);
return _.map(trackedTokensStartingWithEtherToken, this._renderTokenRow.bind(this));
}
- private _renderTokenRow(token: Token) {
+ private _renderTokenRow(token: Token, index: number) {
const tokenState = this.state.trackedTokenStateByAddress[token.address];
const tokenLink = sharedUtils.getEtherScanLinkIfExists(
token.address,
@@ -310,12 +378,14 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
tokenState,
},
};
+ // if this is the last item in the list, do not render the border, it is rendered by the footer
+ const borderedStyle = index !== this.props.trackedTokens.length - 1 ? styles.borderedItem : {};
const shouldShowWrapEtherItem =
!_.isUndefined(this.state.wrappedEtherDirection) &&
this.state.wrappedEtherDirection === accessoryItemConfig.wrappedEtherDirection;
const style = shouldShowWrapEtherItem
? { ...walletItemStyles.focusedItem, ...styles.paddedItem }
- : { ...styles.tokenItem, ...styles.borderedItem, ...styles.paddedItem };
+ : { ...styles.tokenItem, ...borderedStyle, ...styles.paddedItem };
const etherToken = this._getEthToken();
return (
<div key={token.address}>
@@ -461,16 +531,16 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
);
balanceAndAllowanceTupleByAddress[tokenAddress] = balanceAndAllowanceTuple;
}
- const pricesByAddress = await this._getPricesByAddressAsync(tokenAddresses);
+ const priceByAddress = await this._getPriceByAddressAsync(tokenAddresses);
const trackedTokenStateByAddress = _.reduce(
tokenAddresses,
(acc, address) => {
const [balance, allowance] = balanceAndAllowanceTupleByAddress[address];
- const price = pricesByAddress[address];
+ const priceIfExists = _.get(priceByAddress, address);
acc[address] = {
balance,
allowance,
- price,
+ price: priceIfExists,
isLoaded: true,
};
return acc;
@@ -487,16 +557,29 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
private async _refetchTokenStateAsync(tokenAddress: string) {
await this._fetchBalancesAndAllowancesAsync([tokenAddress]);
}
- private async _getPricesByAddressAsync(tokenAddresses: string[]): Promise<ItemByAddress<BigNumber>> {
+ private async _getPriceByAddressAsync(tokenAddresses: string[]): Promise<ItemByAddress<BigNumber>> {
if (_.isEmpty(tokenAddresses)) {
return {};
}
+ // for each input token address, search for the corresponding symbol in this.props.tokenByAddress, if it exists
+ // create a mapping from existing symbols -> address
+ const tokenAddressBySymbol: { [symbol: string]: string } = {};
+ _.each(tokenAddresses, address => {
+ const tokenIfExists = _.get(this.props.tokenByAddress, address);
+ if (!_.isUndefined(tokenIfExists)) {
+ const symbol = tokenIfExists.symbol;
+ tokenAddressBySymbol[symbol] = address;
+ }
+ });
+ const tokenSymbols = _.keys(tokenAddressBySymbol);
try {
- const websiteBackendPriceInfos = await backendClient.getPriceInfosAsync(tokenAddresses);
- const addresses = _.map(websiteBackendPriceInfos, info => info.address);
- const prices = _.map(websiteBackendPriceInfos, info => new BigNumber(info.price));
- const pricesByAddress = _.zipObject(addresses, prices);
- return pricesByAddress;
+ const priceBySymbol = await backendClient.getPriceInfoAsync(tokenSymbols);
+ const priceByAddress = _.mapKeys(priceBySymbol, (value, symbol) => _.get(tokenAddressBySymbol, symbol));
+ const result = _.mapValues(priceByAddress, price => {
+ const priceBigNumber = new BigNumber(price);
+ return priceBigNumber;
+ });
+ return result;
} catch (err) {
return {};
}
diff --git a/packages/website/ts/containers/legacy_portal.ts b/packages/website/ts/containers/legacy_portal.ts
new file mode 100644
index 000000000..3b1172a44
--- /dev/null
+++ b/packages/website/ts/containers/legacy_portal.ts
@@ -0,0 +1,92 @@
+import { BigNumber } from '@0xproject/utils';
+import * as _ from 'lodash';
+import * as React from 'react';
+import { connect } from 'react-redux';
+import { Dispatch } from 'redux';
+import {
+ LegacyPortal as LegacyPortalComponent,
+ LegacyPortalProps as LegacyPortalComponentProps,
+} from 'ts/components/legacy_portal/legacy_portal';
+import { Dispatcher } from 'ts/redux/dispatcher';
+import { State } from 'ts/redux/reducer';
+import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, Side, TokenByAddress } from 'ts/types';
+import { constants } from 'ts/utils/constants';
+import { Translate } from 'ts/utils/translate';
+
+interface ConnectedState {
+ blockchainErr: BlockchainErrs;
+ blockchainIsLoaded: boolean;
+ hashData: HashData;
+ injectedProviderName: string;
+ networkId: number;
+ nodeVersion: string;
+ orderFillAmount: BigNumber;
+ providerType: ProviderType;
+ tokenByAddress: TokenByAddress;
+ lastForceTokenStateRefetch: number;
+ userEtherBalanceInWei: BigNumber;
+ screenWidth: ScreenWidths;
+ shouldBlockchainErrDialogBeOpen: boolean;
+ userAddress: string;
+ userSuppliedOrderCache: Order;
+ flashMessage?: string | React.ReactNode;
+ translate: Translate;
+}
+
+interface ConnectedDispatch {
+ dispatcher: Dispatcher;
+}
+
+const mapStateToProps = (state: State, ownProps: LegacyPortalComponentProps): ConnectedState => {
+ const receiveAssetToken = state.sideToAssetToken[Side.Receive];
+ const depositAssetToken = state.sideToAssetToken[Side.Deposit];
+ const receiveAddress = !_.isUndefined(receiveAssetToken.address)
+ ? receiveAssetToken.address
+ : constants.NULL_ADDRESS;
+ const depositAddress = !_.isUndefined(depositAssetToken.address)
+ ? depositAssetToken.address
+ : constants.NULL_ADDRESS;
+ const receiveAmount = !_.isUndefined(receiveAssetToken.amount) ? receiveAssetToken.amount : new BigNumber(0);
+ const depositAmount = !_.isUndefined(depositAssetToken.amount) ? depositAssetToken.amount : new BigNumber(0);
+ const hashData = {
+ depositAmount,
+ depositTokenContractAddr: depositAddress,
+ feeRecipientAddress: constants.NULL_ADDRESS,
+ makerFee: constants.MAKER_FEE,
+ orderExpiryTimestamp: state.orderExpiryTimestamp,
+ orderMakerAddress: state.userAddress,
+ orderTakerAddress: state.orderTakerAddress !== '' ? state.orderTakerAddress : constants.NULL_ADDRESS,
+ receiveAmount,
+ receiveTokenContractAddr: receiveAddress,
+ takerFee: constants.TAKER_FEE,
+ orderSalt: state.orderSalt,
+ };
+ return {
+ blockchainErr: state.blockchainErr,
+ blockchainIsLoaded: state.blockchainIsLoaded,
+ hashData,
+ injectedProviderName: state.injectedProviderName,
+ networkId: state.networkId,
+ nodeVersion: state.nodeVersion,
+ orderFillAmount: state.orderFillAmount,
+ providerType: state.providerType,
+ screenWidth: state.screenWidth,
+ shouldBlockchainErrDialogBeOpen: state.shouldBlockchainErrDialogBeOpen,
+ tokenByAddress: state.tokenByAddress,
+ lastForceTokenStateRefetch: state.lastForceTokenStateRefetch,
+ userAddress: state.userAddress,
+ userEtherBalanceInWei: state.userEtherBalanceInWei,
+ userSuppliedOrderCache: state.userSuppliedOrderCache,
+ flashMessage: state.flashMessage,
+ translate: state.translate,
+ };
+};
+
+const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
+ dispatcher: new Dispatcher(dispatch),
+});
+
+export const LegacyPortal: React.ComponentClass<LegacyPortalComponentProps> = connect(
+ mapStateToProps,
+ mapDispatchToProps,
+)(LegacyPortalComponent);
diff --git a/packages/website/ts/containers/order_utils_documentation.ts b/packages/website/ts/containers/order_utils_documentation.ts
new file mode 100644
index 000000000..64aa7300f
--- /dev/null
+++ b/packages/website/ts/containers/order_utils_documentation.ts
@@ -0,0 +1,99 @@
+import { constants as docConstants, DocsInfo, DocsInfoConfig, SupportedDocJson } from '@0xproject/react-docs';
+import * as _ from 'lodash';
+import * as React from 'react';
+import { connect } from 'react-redux';
+import { Dispatch } from 'redux';
+import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page';
+import { Dispatcher } from 'ts/redux/dispatcher';
+import { State } from 'ts/redux/reducer';
+import { DocPackages, Environments, WebsitePaths } from 'ts/types';
+import { configs } from 'ts/utils/configs';
+import { constants } from 'ts/utils/constants';
+import { Translate } from 'ts/utils/translate';
+
+/* tslint:disable:no-var-requires */
+const IntroMarkdown = require('md/docs/order_utils/introduction');
+const InstallationMarkdown = require('md/docs/order_utils/installation');
+/* tslint:enable:no-var-requires */
+
+const docSections = {
+ introduction: 'introduction',
+ installation: 'installation',
+ usage: 'usage',
+ types: 'types',
+};
+
+const docsInfoConfig: DocsInfoConfig = {
+ id: DocPackages.OrderUtils,
+ type: SupportedDocJson.TypeDoc,
+ displayName: 'Order utils',
+ packageUrl: 'https://github.com/0xProject/0x-monorepo',
+ menu: {
+ introduction: [docSections.introduction],
+ install: [docSections.installation],
+ usage: [docSections.usage],
+ types: [docSections.types],
+ },
+ sectionNameToMarkdown: {
+ [docSections.introduction]: IntroMarkdown,
+ [docSections.installation]: InstallationMarkdown,
+ },
+ sectionNameToModulePath: {
+ [docSections.usage]: [
+ '"order-utils/src/order_hash"',
+ '"order-utils/src/signature_utils"',
+ '"order-utils/src/order_factory"',
+ '"order-utils/src/salt"',
+ '"order-utils/src/assert"',
+ '"order-utils/src/constants"',
+ ],
+ [docSections.types]: ['"order-utils/src/types"', '"types/src/index"'],
+ },
+ menuSubsectionToVersionWhenIntroduced: {},
+ sections: docSections,
+ visibleConstructors: [],
+ typeConfigs: {
+ // Note: This needs to be kept in sync with the types exported in index.ts. Unfortunately there is
+ // currently no way to extract the re-exported types from index.ts via TypeDoc :(
+ publicTypes: [
+ 'OrderError',
+ 'Order',
+ 'SignedOrder',
+ 'ECSignature',
+ 'Provider',
+ 'JSONRPCRequestPayload',
+ 'JSONRPCResponsePayload',
+ 'JSONRPCErrorCallback',
+ ],
+ typeNameToExternalLink: {
+ BigNumber: constants.URL_BIGNUMBERJS_GITHUB,
+ },
+ },
+};
+const docsInfo = new DocsInfo(docsInfoConfig);
+
+interface ConnectedState {
+ docsVersion: string;
+ availableDocVersions: string[];
+ docsInfo: DocsInfo;
+ translate: Translate;
+}
+
+interface ConnectedDispatch {
+ dispatcher: Dispatcher;
+}
+
+const mapStateToProps = (state: State, ownProps: DocPageProps): ConnectedState => ({
+ docsVersion: state.docsVersion,
+ availableDocVersions: state.availableDocVersions,
+ translate: state.translate,
+ docsInfo,
+});
+
+const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
+ dispatcher: new Dispatcher(dispatch),
+});
+
+export const Documentation: React.ComponentClass<DocPageProps> = connect(mapStateToProps, mapDispatchToProps)(
+ DocPageComponent,
+);
diff --git a/packages/website/ts/containers/portal.ts b/packages/website/ts/containers/portal.ts
index 725564ead..3f0feb6e9 100644
--- a/packages/website/ts/containers/portal.ts
+++ b/packages/website/ts/containers/portal.ts
@@ -3,7 +3,7 @@ import * as _ from 'lodash';
import * as React from 'react';
import { connect } from 'react-redux';
import { Dispatch } from 'redux';
-import { Portal as PortalComponent, PortalAllProps as PortalComponentAllProps } from 'ts/components/portal';
+import { Portal as PortalComponent, PortalProps as PortalComponentProps } from 'ts/components/portal/portal';
import { Dispatcher } from 'ts/redux/dispatcher';
import { State } from 'ts/redux/reducer';
import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, Side, TokenByAddress } from 'ts/types';
@@ -34,7 +34,7 @@ interface ConnectedDispatch {
dispatcher: Dispatcher;
}
-const mapStateToProps = (state: State, ownProps: PortalComponentAllProps): ConnectedState => {
+const mapStateToProps = (state: State, ownProps: PortalComponentProps): ConnectedState => {
const receiveAssetToken = state.sideToAssetToken[Side.Receive];
const depositAssetToken = state.sideToAssetToken[Side.Deposit];
const receiveAddress = !_.isUndefined(receiveAssetToken.address)
@@ -83,6 +83,6 @@ const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
dispatcher: new Dispatcher(dispatch),
});
-export const Portal: React.ComponentClass<PortalComponentAllProps> = connect(mapStateToProps, mapDispatchToProps)(
+export const Portal: React.ComponentClass<PortalComponentProps> = connect(mapStateToProps, mapDispatchToProps)(
PortalComponent,
);
diff --git a/packages/website/ts/containers/deployer_documentation.ts b/packages/website/ts/containers/sol_compiler_documentation.ts
index e20cc195b..2f6486146 100644
--- a/packages/website/ts/containers/deployer_documentation.ts
+++ b/packages/website/ts/containers/sol_compiler_documentation.ts
@@ -12,9 +12,9 @@ import { constants } from 'ts/utils/constants';
import { Translate } from 'ts/utils/translate';
/* tslint:disable:no-var-requires */
-const IntroMarkdown = require('md/docs/deployer/introduction');
-const InstallationMarkdown = require('md/docs/deployer/installation');
-const UsageMarkdown = require('md/docs/deployer/usage');
+const IntroMarkdown = require('md/docs/sol-compiler/introduction');
+const InstallationMarkdown = require('md/docs/sol-compiler/installation');
+const UsageMarkdown = require('md/docs/sol-compiler/usage');
/* tslint:enable:no-var-requires */
const docSections = {
@@ -22,21 +22,19 @@ const docSections = {
installation: 'installation',
usage: 'usage',
compiler: 'compiler',
- deployer: 'deployer',
types: docConstants.TYPES_SECTION_NAME,
};
const docsInfoConfig: DocsInfoConfig = {
- id: DocPackages.Deployer,
+ id: DocPackages.SolCompiler,
type: SupportedDocJson.TypeDoc,
- displayName: 'Deployer',
+ displayName: 'Solidity Compiler',
packageUrl: 'https://github.com/0xProject/0x-monorepo',
menu: {
introduction: [docSections.introduction],
install: [docSections.installation],
usage: [docSections.usage],
compiler: [docSections.compiler],
- deployer: [docSections.deployer],
types: [docSections.types],
},
sectionNameToMarkdown: {
@@ -45,32 +43,18 @@ const docsInfoConfig: DocsInfoConfig = {
[docSections.usage]: UsageMarkdown,
},
sectionNameToModulePath: {
- [docSections.compiler]: ['"deployer/src/compiler"'],
- [docSections.deployer]: ['"deployer/src/deployer"'],
- [docSections.types]: ['"deployer/src/utils/types"', '"types/src/index"'],
+ [docSections.compiler]: ['"sol-compiler/src/compiler"'],
+ [docSections.types]: ['"sol-compiler/src/utils/types"', '"types/src/index"'],
},
menuSubsectionToVersionWhenIntroduced: {},
sections: docSections,
- visibleConstructors: [docSections.compiler, docSections.deployer],
+ visibleConstructors: [docSections.compiler],
typeConfigs: {
// Note: This needs to be kept in sync with the types exported in index.ts. Unfortunately there is
// currently no way to extract the re-exported types from index.ts via TypeDoc :(
- publicTypes: [
- 'CompilerOptions',
- 'DeployerOptions',
- 'BaseDeployerOptions',
- 'UrlDeployerOptions',
- 'ProviderDeployerOptions',
- 'TxData',
- ],
- typeNameToExternalLink: {
- Web3: constants.URL_WEB3_DOCS,
- BigNumber: constants.URL_BIGNUMBERJS_GITHUB,
- ContractInstance: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L98',
- },
- typeNameToPrefix: {
- ContractInstance: 'Web3',
- },
+ publicTypes: ['CompilerOptions'],
+ typeNameToExternalLink: {},
+ typeNameToPrefix: {},
},
};
const docsInfo = new DocsInfo(docsInfoConfig);
diff --git a/packages/website/ts/containers/subproviders_documentation.ts b/packages/website/ts/containers/subproviders_documentation.ts
index a14d06a3f..2178baea8 100644
--- a/packages/website/ts/containers/subproviders_documentation.ts
+++ b/packages/website/ts/containers/subproviders_documentation.ts
@@ -74,7 +74,7 @@ const docsInfoConfig: DocsInfoConfig = {
[docSections.redundantRPCSubprovider]: ['"subproviders/src/subproviders/redundant_rpc"'],
[docSections.ganacheSubprovider]: ['"subproviders/src/subproviders/ganache"'],
[docSections.nonceTrackerSubprovider]: ['"subproviders/src/subproviders/nonce_tracker"'],
- [docSections.types]: ['"deployer/src/utils/types"', '"types/src/index"', '"subproviders/src/types"'],
+ [docSections.types]: ['"sol-compiler/src/utils/types"', '"types/src/index"', '"subproviders/src/types"'],
},
menuSubsectionToVersionWhenIntroduced: {},
sections: docSections,
diff --git a/packages/website/ts/containers/zero_ex_js_documentation.ts b/packages/website/ts/containers/zero_ex_js_documentation.ts
index 40853cb9e..f68e2335f 100644
--- a/packages/website/ts/containers/zero_ex_js_documentation.ts
+++ b/packages/website/ts/containers/zero_ex_js_documentation.ts
@@ -68,32 +68,38 @@ const docsInfoConfig: DocsInfoConfig = {
[zeroExJsDocSections.exchange]: [
'"0x.js/src/contract_wrappers/exchange_wrapper"',
'"src/contract_wrappers/exchange_wrapper"',
+ '"contract-wrappers/src/contract_wrappers/exchange_wrapper"',
],
[zeroExJsDocSections.tokenRegistry]: [
'"0x.js/src/contract_wrappers/token_registry_wrapper"',
'"src/contract_wrappers/token_registry_wrapper"',
+ '"contract-wrappers/src/contract_wrappers/token_registry_wrapper"',
],
[zeroExJsDocSections.token]: [
'"0x.js/src/contract_wrappers/token_wrapper"',
'"src/contract_wrappers/token_wrapper"',
+ '"contract-wrappers/src/contract_wrappers/token_wrapper"',
],
[zeroExJsDocSections.etherToken]: [
'"0x.js/src/contract_wrappers/ether_token_wrapper"',
'"src/contract_wrappers/ether_token_wrapper"',
+ '"contract-wrappers/src/contract_wrappers/ether_token_wrapper"',
],
[zeroExJsDocSections.proxy]: [
'"0x.js/src/contract_wrappers/proxy_wrapper"',
'"0x.js/src/contract_wrappers/token_transfer_proxy_wrapper"',
- '"src/contract_wrappers/token_transfer_proxy_wrapper"',
+ '"contract-wrappers/src/contract_wrappers/token_transfer_proxy_wrapper"',
],
[zeroExJsDocSections.orderWatcher]: [
'"0x.js/src/order_watcher/order_state_watcher"',
'"src/order_watcher/order_state_watcher"',
+ '"order-watcher/src/order_watcher/order_watcher"',
],
[zeroExJsDocSections.types]: [
'"0x.js/src/types"',
'"src/types"',
'"types/src/index"',
+ '"contract-wrappers/src/types"',
'"0x.js/src/contract_wrappers/generated/ether_token"',
'"0x.js/src/contract_wrappers/generated/token"',
'"0x.js/src/contract_wrappers/generated/exchange"',
@@ -114,7 +120,7 @@ const docsInfoConfig: DocsInfoConfig = {
'Order',
'SignedOrder',
'ECSignature',
- 'ZeroExError',
+ 'ContractWrappersError',
'EventCallback',
'EventCallbackAsync',
'EventCallbackSync',
diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx
index 6b347145f..49bcdeaac 100644
--- a/packages/website/ts/index.tsx
+++ b/packages/website/ts/index.tsx
@@ -34,9 +34,14 @@ import 'less/all.less';
// cause we only want to import the module when the user navigates to the page.
// At the same time webpack statically parses for System.import() to determine bundle chunk split points
// so each lazy import needs it's own `System.import()` declaration.
-const LazyPortal = createLazyComponent('Portal', async () =>
- System.import<any>(/* webpackChunkName: "portal" */ 'ts/containers/portal'),
-);
+const LazyPortal =
+ utils.isDevelopment() || utils.isStaging()
+ ? createLazyComponent('Portal', async () =>
+ System.import<any>(/* webpackChunkName: "portal" */ 'ts/containers/portal'),
+ )
+ : createLazyComponent('LegacyPortal', async () =>
+ System.import<any>(/* webpackChunkName: "legacyPortal" */ 'ts/containers/legacy_portal'),
+ );
const LazyZeroExJSDocumentation = createLazyComponent('Documentation', async () =>
System.import<any>(/* webpackChunkName: "zeroExDocs" */ 'ts/containers/zero_ex_js_documentation'),
);
@@ -49,8 +54,8 @@ const LazyConnectDocumentation = createLazyComponent('Documentation', async () =
const LazyWeb3WrapperDocumentation = createLazyComponent('Documentation', async () =>
System.import<any>(/* webpackChunkName: "web3WrapperDocs" */ 'ts/containers/web3_wrapper_documentation'),
);
-const LazyDeployerDocumentation = createLazyComponent('Documentation', async () =>
- System.import<any>(/* webpackChunkName: "deployerDocs" */ 'ts/containers/deployer_documentation'),
+const LazySolCompilerDocumentation = createLazyComponent('Documentation', async () =>
+ System.import<any>(/* webpackChunkName: "solCompilerDocs" */ 'ts/containers/sol_compiler_documentation'),
);
const LazyJSONSchemasDocumentation = createLazyComponent('Documentation', async () =>
System.import<any>(/* webpackChunkName: "jsonSchemasDocs" */ 'ts/containers/json_schemas_documentation'),
@@ -61,6 +66,9 @@ const LazySolCovDocumentation = createLazyComponent('Documentation', async () =>
const LazySubprovidersDocumentation = createLazyComponent('Documentation', async () =>
System.import<any>(/* webpackChunkName: "subproviderDocs" */ 'ts/containers/subproviders_documentation'),
);
+const LazyOrderUtilsDocumentation = createLazyComponent('Documentation', async () =>
+ System.import<any>(/* webpackChunkName: "orderUtilsDocs" */ 'ts/containers/order_utils_documentation'),
+);
analytics.init();
// tslint:disable-next-line:no-floating-promises
@@ -83,7 +91,10 @@ render(
<Route path={WebsitePaths.Wiki} component={Wiki as any} />
<Route path={`${WebsitePaths.ZeroExJs}/:version?`} component={LazyZeroExJSDocumentation} />
<Route path={`${WebsitePaths.Connect}/:version?`} component={LazyConnectDocumentation} />
- <Route path={`${WebsitePaths.Deployer}/:version?`} component={LazyDeployerDocumentation} />
+ <Route
+ path={`${WebsitePaths.SolCompiler}/:version?`}
+ component={LazySolCompilerDocumentation}
+ />
<Route path={`${WebsitePaths.SolCov}/:version?`} component={LazySolCovDocumentation} />
<Route
path={`${WebsitePaths.JSONSchemas}/:version?`}
@@ -94,6 +105,10 @@ render(
component={LazySubprovidersDocumentation}
/>
<Route
+ path={`${WebsitePaths.OrderUtils}/:version?`}
+ component={LazyOrderUtilsDocumentation}
+ />
+ <Route
path={`${WebsitePaths.Web3Wrapper}/:version?`}
component={LazyWeb3WrapperDocumentation}
/>
@@ -111,6 +126,10 @@ render(
path={`${WebsiteLegacyPaths.Web3Wrapper}/:version?`}
component={LazyWeb3WrapperDocumentation}
/>
+ <Route
+ path={`${WebsiteLegacyPaths.Deployer}/:version?`}
+ component={LazySolCompilerDocumentation}
+ />
<Route component={NotFound as any} />
</Switch>
diff --git a/packages/website/ts/pages/about/about.tsx b/packages/website/ts/pages/about/about.tsx
index 97be59526..d78cca703 100644
--- a/packages/website/ts/pages/about/about.tsx
+++ b/packages/website/ts/pages/about/about.tsx
@@ -113,7 +113,7 @@ const teamRow4: ProfileInfo[] = [
{
name: 'Blake Henderson',
title: 'Operations Associate',
- description: `Operations and Analytics. Previously analytics at LinkedIn. Economics at UC San Diego. `,
+ description: `Operations and Analytics. Previously analytics at LinkedIn. Economics at UC San Diego.`,
image: '/images/team/blake.jpg',
linkedIn: 'https://www.linkedin.com/in/blakerhenderson/',
github: '',
@@ -130,6 +130,27 @@ const teamRow4: ProfileInfo[] = [
},
];
+const teamRow5: ProfileInfo[] = [
+ {
+ name: 'Greg Hysen',
+ title: 'Blockchain Engineer',
+ description: `Smart contract R&D. Previously lead distributed systems engineer at Hivemapper. Computer Science at University of Waterloo.`,
+ image: '/images/team/greg.jpeg',
+ linkedIn: 'https://www.linkedin.com/in/gregory-hysen-71741463/',
+ github: 'https://github.com/hysz',
+ medium: '',
+ },
+ {
+ name: 'Remco Bloemen',
+ title: 'Technical Fellow',
+ description: `Previously cofounder at Neufund and Coblue. Part III at Cambridge. PhD dropout at Twente Business School.`,
+ image: '/images/team/remco.jpeg',
+ linkedIn: 'https://www.linkedin.com/in/remcobloemen/',
+ github: 'http://github.com/recmo',
+ medium: '',
+ },
+];
+
const advisors: ProfileInfo[] = [
{
name: 'Fred Ehrsam',
@@ -223,6 +244,7 @@ export class About extends React.Component<AboutProps, AboutState> {
<div className="clearfix">{this._renderProfiles(teamRow2)}</div>
<div className="clearfix">{this._renderProfiles(teamRow3)}</div>
<div className="clearfix">{this._renderProfiles(teamRow4)}</div>
+ <div className="clearfix">{this._renderProfiles(teamRow5)}</div>
</div>
<div className="pt3 pb2">
<div
diff --git a/packages/website/ts/pages/documentation/doc_page.tsx b/packages/website/ts/pages/documentation/doc_page.tsx
index aca20447b..be8ae02f4 100644
--- a/packages/website/ts/pages/documentation/doc_page.tsx
+++ b/packages/website/ts/pages/documentation/doc_page.tsx
@@ -30,10 +30,11 @@ const docIdToSubpackageName: { [id: string]: string } = {
[DocPackages.Connect]: 'connect',
[DocPackages.SmartContracts]: 'contracts',
[DocPackages.Web3Wrapper]: 'web3-wrapper',
- [DocPackages.Deployer]: 'deployer',
+ [DocPackages.SolCompiler]: 'sol-compiler',
[DocPackages.JSONSchemas]: 'json-schemas',
[DocPackages.SolCov]: 'sol-cov',
[DocPackages.Subproviders]: 'subproviders',
+ [DocPackages.OrderUtils]: 'order-utils',
};
export interface DocPageProps {
diff --git a/packages/website/ts/pages/landing/landing.tsx b/packages/website/ts/pages/landing/landing.tsx
index f961220fd..a63c24fb7 100644
--- a/packages/website/ts/pages/landing/landing.tsx
+++ b/packages/website/ts/pages/landing/landing.tsx
@@ -37,6 +37,8 @@ interface Project {
}
const THROTTLE_TIMEOUT = 100;
+const WHATS_NEW_TITLE = '18 ideas for 0x relayers in 2018';
+const WHATS_NEW_URL = 'https://blog.0xproject.com/18-ideas-for-0x-relayers-in-2018-80a1498b955f';
const relayersAndDappProjects: Project[] = [
{
@@ -233,6 +235,7 @@ export class Landing extends React.Component<LandingProps, LandingState> {
return (
<div className="clearfix py4" style={{ backgroundColor: colors.heroGrey }}>
<div className="mx-auto max-width-4 clearfix">
+ {this._renderWhatsNew()}
<div className="lg-pt4 md-pt4 sm-pt2 lg-pb4 md-pb4 lg-my4 md-my4 sm-mt2 sm-mb4 clearfix">
<div className="col lg-col-5 md-col-5 col-12 sm-center">
<img src="/images/landing/hero_chip_image.png" height={isSmallScreen ? 300 : 395} />
@@ -302,6 +305,28 @@ export class Landing extends React.Component<LandingProps, LandingState> {
</div>
);
}
+ private _renderWhatsNew() {
+ return (
+ <div className="sm-center sm-px1">
+ <a href={WHATS_NEW_URL} target="_blank" className="inline-block text-decoration-none">
+ <div className="flex sm-pl0 md-pl2 lg-pl0" style={{ fontFamily: 'Roboto Mono', fontWeight: 600 }}>
+ <div
+ className="mr1 px1"
+ style={{
+ backgroundColor: colors.lightTurquois,
+ borderRadius: 3,
+ color: colors.heroGrey,
+ height: 23,
+ }}
+ >
+ New
+ </div>
+ <div style={{ color: colors.darkGrey }}>{WHATS_NEW_TITLE}</div>
+ </div>
+ </a>
+ </div>
+ );
+ }
private _renderProjects(projects: Project[], title: string, backgroundColor: string, isTitleCenter: boolean) {
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
const projectList = _.map(projects, (project: Project, i: number) => {
diff --git a/packages/website/ts/pages/wiki/wiki.tsx b/packages/website/ts/pages/wiki/wiki.tsx
index 7ed2b750d..edca5834d 100644
--- a/packages/website/ts/pages/wiki/wiki.tsx
+++ b/packages/website/ts/pages/wiki/wiki.tsx
@@ -47,7 +47,7 @@ const styles: Styles = {
left: 0,
bottom: 0,
right: 0,
- overflowZ: 'hidden',
+ overflow: 'hidden',
height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`,
WebkitOverflowScrolling: 'touch',
},
diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts
index 2544e6735..58929a0c6 100644
--- a/packages/website/ts/types.ts
+++ b/packages/website/ts/types.ts
@@ -344,6 +344,7 @@ export enum Docs {
export enum WebsiteLegacyPaths {
ZeroExJs = '/docs/0xjs',
Web3Wrapper = '/docs/web3_wrapper',
+ Deployer = '/docs/deployer',
}
export enum WebsitePaths {
@@ -357,10 +358,11 @@ export enum WebsitePaths {
SmartContracts = '/docs/contracts',
Connect = '/docs/connect',
Web3Wrapper = '/docs/web3-wrapper',
- Deployer = '/docs/deployer',
+ SolCompiler = '/docs/sol-compiler',
JSONSchemas = '/docs/json-schemas',
SolCov = '/docs/sol-cov',
Subproviders = '/docs/subproviders',
+ OrderUtils = '/docs/order-utils',
Jobs = '/jobs',
}
@@ -369,10 +371,11 @@ export enum DocPackages {
ZeroExJs = 'ZERO_EX_JS',
SmartContracts = 'SMART_CONTRACTS',
Web3Wrapper = 'WEB3_WRAPPER',
- Deployer = 'DEPLOYER',
+ SolCompiler = 'SOL_COMPILER',
JSONSchemas = 'JSON_SCHEMAS',
SolCov = 'SOL_COV',
Subproviders = 'SUBPROVIDERS',
+ OrderUtils = 'ORDER_UTILS',
}
export enum Key {
@@ -421,7 +424,7 @@ export enum Key {
About = 'ABOUT',
Careers = 'CAREERS',
Contact = 'CONTACT',
- Deployer = 'DEPLOYER',
+ SolCompiler = 'SOL_COMPILER',
JsonSchemas = 'JSON_SCHEMAS',
SolCov = 'SOL_COV',
Subproviders = 'SUBPROVIDERS',
@@ -431,6 +434,7 @@ export enum Key {
Whitepaper = 'WHITEPAPER',
Wiki = 'WIKI',
Web3Wrapper = 'WEB3_WRAPPER',
+ OrderUtils = 'ORDER_UTILS',
And = 'AND',
Faq = 'FAQ',
SmartContracts = 'SMART_CONTRACTS',
@@ -500,17 +504,24 @@ export interface TokenState {
price?: BigNumber;
}
-// TODO: Add topTokens and headerUrl properties once available from backend
export interface WebsiteBackendRelayerInfo {
- id: string;
name: string;
dailyTxnVolume: string;
url: string;
+ appUrl?: string;
+ headerImgUrl?: string;
+ topTokens: WebsiteBackendTokenInfo[];
}
export interface WebsiteBackendPriceInfo {
- price: string;
+ [symbol: string]: string;
+}
+
+export interface WebsiteBackendTokenInfo {
address: string;
+ decimals: number;
+ name: string;
+ symbol: string;
}
export interface WebsiteBackendGasInfo {
diff --git a/packages/website/ts/utils/backend_client.ts b/packages/website/ts/utils/backend_client.ts
index fdbb3e03a..63e06fda7 100644
--- a/packages/website/ts/utils/backend_client.ts
+++ b/packages/website/ts/utils/backend_client.ts
@@ -1,16 +1,8 @@
-import { BigNumber, logUtils } from '@0xproject/utils';
import * as _ from 'lodash';
-import * as queryString from 'query-string';
-import {
- ArticlesBySection,
- ItemByAddress,
- WebsiteBackendGasInfo,
- WebsiteBackendPriceInfo,
- WebsiteBackendRelayerInfo,
-} from 'ts/types';
+import { ArticlesBySection, WebsiteBackendGasInfo, WebsiteBackendPriceInfo, WebsiteBackendRelayerInfo } from 'ts/types';
import { configs } from 'ts/utils/configs';
-import { errorReporter } from 'ts/utils/error_reporter';
+import { fetchUtils } from 'ts/utils/fetch_utils';
const ETH_GAS_STATION_ENDPOINT = '/eth_gas_station';
const PRICES_ENDPOINT = '/prices';
@@ -19,52 +11,26 @@ const WIKI_ENDPOINT = '/wiki';
export const backendClient = {
async getGasInfoAsync(): Promise<WebsiteBackendGasInfo> {
- const result = await requestAsync(ETH_GAS_STATION_ENDPOINT);
+ const result = await fetchUtils.requestAsync(configs.BACKEND_BASE_URL, ETH_GAS_STATION_ENDPOINT);
return result;
},
- async getPriceInfosAsync(tokenAddresses: string[]): Promise<WebsiteBackendPriceInfo[]> {
- if (_.isEmpty(tokenAddresses)) {
- return [];
+ async getPriceInfoAsync(tokenSymbols: string[]): Promise<WebsiteBackendPriceInfo> {
+ if (_.isEmpty(tokenSymbols)) {
+ return {};
}
- const joinedTokenAddresses = tokenAddresses.join(',');
+ const joinedTokenSymbols = tokenSymbols.join(',');
const queryParams = {
- tokens: joinedTokenAddresses,
+ tokens: joinedTokenSymbols,
};
- const result = await requestAsync(PRICES_ENDPOINT, queryParams);
+ const result = await fetchUtils.requestAsync(configs.BACKEND_BASE_URL, PRICES_ENDPOINT, queryParams);
return result;
},
async getRelayerInfosAsync(): Promise<WebsiteBackendRelayerInfo[]> {
- const result = await requestAsync(RELAYERS_ENDPOINT);
+ const result = await fetchUtils.requestAsync(configs.BACKEND_BASE_URL, RELAYERS_ENDPOINT);
return result;
},
async getWikiArticlesBySectionAsync(): Promise<ArticlesBySection> {
- const result = await requestAsync(WIKI_ENDPOINT);
+ const result = await fetchUtils.requestAsync(configs.BACKEND_BASE_URL, WIKI_ENDPOINT);
return result;
},
};
-
-async function requestAsync(endpoint: string, queryParams?: object): Promise<any> {
- const query = queryStringFromQueryParams(queryParams);
- const url = `${configs.BACKEND_BASE_URL}${endpoint}${query}`;
- const response = await fetch(url);
- if (response.status !== 200) {
- const errorText = `Error requesting url: ${url}, ${response.status}: ${response.statusText}`;
- logUtils.log(errorText);
- const error = Error(errorText);
- // tslint:disable-next-line:no-floating-promises
- errorReporter.reportAsync(error);
- throw error;
- }
- const result = await response.json();
- return result;
-}
-
-function queryStringFromQueryParams(queryParams?: object): string {
- // if params are undefined or empty, return an empty string
- if (_.isUndefined(queryParams) || _.isEmpty(queryParams)) {
- return '';
- }
- // stringify the formatted object
- const stringifiedParams = queryString.stringify(queryParams);
- return `?${stringifiedParams}`;
-}
diff --git a/packages/website/ts/utils/fetch_utils.ts b/packages/website/ts/utils/fetch_utils.ts
new file mode 100644
index 000000000..d2e902db5
--- /dev/null
+++ b/packages/website/ts/utils/fetch_utils.ts
@@ -0,0 +1,33 @@
+import { logUtils } from '@0xproject/utils';
+import * as _ from 'lodash';
+import * as queryString from 'query-string';
+
+import { errorReporter } from 'ts/utils/error_reporter';
+
+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);
+ if (response.status !== 200) {
+ const errorText = `Error requesting url: ${url}, ${response.status}: ${response.statusText}`;
+ logUtils.log(errorText);
+ const error = Error(errorText);
+ // tslint:disable-next-line:no-floating-promises
+ errorReporter.reportAsync(error);
+ throw error;
+ }
+ const result = await response.json();
+ return result;
+ },
+};
+
+function queryStringFromQueryParams(queryParams?: object): string {
+ // if params are undefined or empty, return an empty string
+ if (_.isUndefined(queryParams) || _.isEmpty(queryParams)) {
+ return '';
+ }
+ // stringify the formatted object
+ const stringifiedParams = queryString.stringify(queryParams);
+ return `?${stringifiedParams}`;
+}
diff --git a/packages/website/ts/utils/utils.ts b/packages/website/ts/utils/utils.ts
index 53d60b3ce..472870f31 100644
--- a/packages/website/ts/utils/utils.ts
+++ b/packages/website/ts/utils/utils.ts
@@ -1,11 +1,22 @@
-import { ECSignature, ExchangeContractErrs, ZeroEx, ZeroExError } from '0x.js';
+import { ContractWrappersError, ECSignature, ExchangeContractErrs, ZeroEx } from '0x.js';
+import { OrderError } from '@0xproject/order-utils';
import { constants as sharedConstants, EtherscanLinkSuffixes, Networks } from '@0xproject/react-shared';
import { Provider } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
import deepEqual = require('deep-equal');
import * as _ from 'lodash';
import * as moment from 'moment';
-import { Environments, Order, Providers, ScreenWidths, Side, SideToAssetToken, Token, TokenByAddress } from 'ts/types';
+import {
+ BlockchainCallErrs,
+ Environments,
+ Order,
+ Providers,
+ ScreenWidths,
+ Side,
+ SideToAssetToken,
+ Token,
+ TokenByAddress,
+} from 'ts/types';
import { configs } from 'ts/utils/configs';
import { constants } from 'ts/utils/constants';
import * as u2f from 'ts/vendor/u2f_api';
@@ -192,21 +203,20 @@ export const utils = {
const isUniqueSymbol = _.isUndefined(tokenWithSameSymbolIfExists);
return isUniqueName && isUniqueSymbol;
},
- zeroExErrToHumanReadableErrMsg(error: ZeroExError | ExchangeContractErrs, takerAddress: string): string {
- const ZeroExErrorToHumanReadableError: { [error: string]: string } = {
- [ZeroExError.ExchangeContractDoesNotExist]: 'Exchange contract does not exist',
- [ZeroExError.EtherTokenContractDoesNotExist]: 'EtherToken contract does not exist',
- [ZeroExError.TokenTransferProxyContractDoesNotExist]: 'TokenTransferProxy contract does not exist',
- [ZeroExError.TokenRegistryContractDoesNotExist]: 'TokenRegistry contract does not exist',
- [ZeroExError.TokenContractDoesNotExist]: 'Token contract does not exist',
- [ZeroExError.ZRXContractDoesNotExist]: 'ZRX contract does not exist',
- [ZeroExError.UnhandledError]: 'Unhandled error occured',
- [ZeroExError.UserHasNoAssociatedAddress]: 'User has no addresses available',
- [ZeroExError.InvalidSignature]: 'Order signature is not valid',
- [ZeroExError.ContractNotDeployedOnNetwork]: 'Contract is not deployed on the detected network',
- [ZeroExError.InvalidJump]: 'Invalid jump occured while executing the transaction',
- [ZeroExError.OutOfGas]: 'Transaction ran out of gas',
- [ZeroExError.NoNetworkId]: 'No network id detected',
+ zeroExErrToHumanReadableErrMsg(error: ContractWrappersError | ExchangeContractErrs, takerAddress: string): string {
+ const ContractWrappersErrorToHumanReadableError: { [error: string]: string } = {
+ [ContractWrappersError.ExchangeContractDoesNotExist]: 'Exchange contract does not exist',
+ [ContractWrappersError.EtherTokenContractDoesNotExist]: 'EtherToken contract does not exist',
+ [ContractWrappersError.TokenTransferProxyContractDoesNotExist]:
+ 'TokenTransferProxy contract does not exist',
+ [ContractWrappersError.TokenRegistryContractDoesNotExist]: 'TokenRegistry contract does not exist',
+ [ContractWrappersError.TokenContractDoesNotExist]: 'Token contract does not exist',
+ [ContractWrappersError.ZRXContractDoesNotExist]: 'ZRX contract does not exist',
+ [BlockchainCallErrs.UserHasNoAssociatedAddresses]: 'User has no addresses available',
+ [OrderError.InvalidSignature]: 'Order signature is not valid',
+ [ContractWrappersError.ContractNotDeployedOnNetwork]: 'Contract is not deployed on the detected network',
+ [ContractWrappersError.InvalidJump]: 'Invalid jump occured while executing the transaction',
+ [ContractWrappersError.OutOfGas]: 'Transaction ran out of gas',
};
const exchangeContractErrorToHumanReadableError: {
[error: string]: string;
@@ -239,7 +249,7 @@ export const utils = {
[ExchangeContractErrs.InsufficientRemainingFillAmount]: 'Insufficient remaining fill amount',
};
const humanReadableErrorMsg =
- exchangeContractErrorToHumanReadableError[error] || ZeroExErrorToHumanReadableError[error];
+ exchangeContractErrorToHumanReadableError[error] || ContractWrappersErrorToHumanReadableError[error];
return humanReadableErrorMsg;
},
isParityNode(nodeVersion: string): boolean {