Merge v2-prototype

This commit is contained in:
Fabio Berger 2018-06-06 11:30:57 +02:00
commit 787eec8be4
49 changed files with 502 additions and 129 deletions

View File

@ -16,17 +16,19 @@
"types": "lib/src/index.d.ts",
"scripts": {
"watch_without_deps": "yarn pre_build && tsc -w",
"build": "yarn pre_build && tsc && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
"build": "yarn pre_build && build:all && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
"pre_build": "run-s generate_contract_wrappers copy_artifacts",
"copy_artifacts": "copyfiles -u 2 './src/compact_artifacts/**/*.json' ./lib/src/compact_artifacts",
"generate_contract_wrappers": "abi-gen --abis 'src/compact_artifacts/@(Exchange|Token|TokenTransferProxy|EtherToken|TokenRegistry|DummyToken).json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers/generated --backend ethers && prettier --write 'src/contract_wrappers/generated/**.ts'",
"lint": "tslint --project .",
"test:circleci": "run-s test:coverage",
"test": "yarn run_mocha",
"rebuild-and-test": "run-s build test",
"rebuild_and_test": "run-s build test",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
"clean": "shx rm -rf _bundles lib test_temp scripts src/contract_wrappers/generated",
"build:umd:prod": "NODE_ENV=production webpack",
"build:commonjs": "tsc && copyfiles -u 2 './src/compact_artifacts/**/*.json' ./lib/src/compact_artifacts && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
"run_mocha": "mocha lib/test/**/*_test.js lib/test/global_hooks.js --timeout 10000 --bail --exit",
"manual:postpublish": "yarn build; node ./scripts/postpublish.js",
"docs:stage": "node scripts/stage_docs.js",

View File

@ -4,8 +4,7 @@ This package allows you to generate TypeScript contract wrappers from ABI files.
It's heavily inspired by [Geth abigen](https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts) but takes a different approach.
You can write your custom handlebars templates which will allow you to seamlessly integrate the generated code into your existing codebase with existing conventions.
For an example of the generated [wrapper files](https://github.com/0xProject/0x-monorepo/tree/development/packages/0x.js/src/contract_wrappers/generated) check out 0x.js.
[Here](https://github.com/0xProject/0x-monorepo/tree/development/packages/contract_templates) are the templates used to generate those files.
[Here](https://github.com/0xProject/0x-monorepo/tree/development/packages/0x.js/contract_templates) are the templates used to generate the contract wrappers used by 0x.js.e
## Installation

View File

@ -15,7 +15,7 @@
"run_mocha": "mocha lib/test/**/*_test.js --exit",
"prepublishOnly": "run-p build",
"test": "yarn run_mocha",
"rebuild-and-test": "run-s clean build test",
"rebuild_and_test": "run-s clean build test",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
"test:circleci": "yarn test:coverage",

View File

@ -12,7 +12,7 @@
"build": "tsc && copyfiles -u 2 './lib/monorepo_scripts/**/*' ./scripts",
"clean": "shx rm -rf lib scripts",
"test": "yarn run_mocha",
"rebuild-and-test": "run-s clean build test",
"rebuild_and_test": "run-s clean build test",
"test:circleci": "yarn test:coverage",
"run_mocha": "mocha lib/test/**/*_test.js --bail --exit",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",

View File

@ -22,7 +22,7 @@
"lint": "tslint --project .",
"run_mocha": "mocha lib/test/**/*_test.js --exit",
"test": "run-s copy_test_fixtures run_mocha",
"rebuild-and-test": "run-s clean build test",
"rebuild_and_test": "run-s clean build test",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
"test:circleci": "yarn test:coverage",

View File

@ -18,7 +18,7 @@
"lint": "tslint --project .",
"test:circleci": "run-s test:coverage",
"test": "yarn run_mocha",
"rebuild-and-test": "run-s build test",
"rebuild_and_test": "run-s build test",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
"update_compact_artifacts": "copyfiles -u 2 './src/compact_artifacts/**/*.json' ./lib/src/compact_artifacts",

View File

@ -158,7 +158,7 @@ export interface MethodOpts {
/**
* gasPrice: Gas price in Wei to use for a transaction
* gasLimit: The amount of gas to send with a transaction
* gasLimit: The amount of gas to send with a transaction (in Gwei)
*/
export interface TransactionOpts {
gasPrice?: BigNumber;

View File

@ -16,7 +16,7 @@
"pre_build": "run-s compile copy_artifacts generate_contract_wrappers",
"copy_artifacts": "copyfiles -u 4 '../migrations/artifacts/2.0.0/**/*' ./lib/src/artifacts;",
"test": "yarn run_mocha",
"rebuild-and-test": "run-s build test",
"rebuild_and_test": "run-s build test",
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
"run_mocha": "mocha 'lib/test/**/*.js' --timeout 100000 --bail --exit",
"compile": "sol-compiler",

View File

@ -11,7 +11,7 @@
"watch_without_deps": "tsc -w",
"build": "tsc && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
"test": "yarn run_mocha",
"rebuild-and-test": "run-s clean build test",
"rebuild_and_test": "run-s clean build test",
"test:circleci": "yarn test:coverage",
"run_mocha": "mocha lib/test/**/*_test.js --bail --exit",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",

View File

@ -11,7 +11,7 @@
"watch_without_deps": "tsc -w",
"lint": "tslint --project .",
"test": "yarn run_mocha",
"rebuild-and-test": "run-s clean build test",
"rebuild_and_test": "run-s clean build test",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
"test:circleci": "yarn test:coverage",

View File

@ -14,7 +14,7 @@
"clean": "shx rm -rf lib artifacts src/contract_wrappers",
"copy_artifacts": "copyfiles './artifacts/**/*' './contracts/**/*' ./lib",
"test": "yarn run_mocha",
"rebuild-and-test": "run-s build test",
"rebuild_and_test": "run-s build test",
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
"run_mocha": "mocha lib/test/**/*_test.js lib/test/global_hooks.js --bail --exit",
"generate_contract_wrappers": "abi-gen --abis 'artifacts/Metacoin.json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers --backend ethers && prettier --write 'src/contract_wrappers/**.ts'",

View File

@ -16,7 +16,7 @@
"generate_contract_wrappers": "abi-gen --abis 'lib/src/artifacts/@(Exchange|IWallet|IValidator).json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/generated_contract_wrappers --backend ethers && prettier --write 'src/generated_contract_wrappers/**.ts'",
"update_artifacts": "for i in ${npm_package_config_contracts}; do copyfiles -u 4 ../migrations/artifacts/2.0.0/$i.json lib/src/artifacts; done;",
"test": "yarn run_mocha",
"rebuild-and-test": "run-s build test",
"rebuild_and_test": "run-s build test",
"test:circleci": "yarn test:coverage",
"run_mocha": "mocha lib/test/**/*_test.js --bail --exit",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",

View File

@ -19,7 +19,7 @@
"lint": "tslint --project .",
"test:circleci": "run-s test:coverage",
"test": "yarn run_mocha",
"rebuild-and-test": "run-s build test",
"rebuild_and_test": "run-s build test",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
"update_compact_artifacts": "copyfiles -u 2 './src/compact_artifacts/**/*.json' ./lib/src/compact_artifacts",

View File

@ -22,7 +22,6 @@ const baseColors = {
heroGrey: '#404040',
projectsGrey: '#343333',
darkestGrey: '#272727',
dharmaDarkGrey: '#252525',
lightBlue: '#60A4F4',
lightBlueA700: '#0091EA',
linkBlue: '#1D5CDE',

View File

@ -13,7 +13,7 @@
"pre_build": "run-s update_contract_fixtures",
"update_contract_fixtures": "copyfiles 'test/fixtures/contracts/**/*' ./lib",
"test": "yarn run_mocha",
"rebuild-and-test": "run-s build test",
"rebuild_and_test": "run-s build test",
"run_mocha": "mocha lib/test/*_test.js --bail --exit",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",

View File

@ -13,7 +13,7 @@
"pre_build": "run-s copy_test_fixtures",
"lint": "tslint --project .",
"test": "run-s compile_test run_mocha",
"rebuild-and-test": "run-s clean build test",
"rebuild_and_test": "run-s clean build test",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
"test:circleci": "yarn test:coverage",

View File

@ -13,7 +13,7 @@
"build": "tsc && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
"lint": "tslint --project .",
"test": "run-s copy_test_environments copy_test_fixtures run_mocha",
"rebuild-and-test": "run-s clean build test",
"rebuild_and_test": "run-s clean build test",
"copy_test_fixtures": "copyfiles -u 2 './test/fixtures/**/*.json' ./lib/test/fixtures",
"copy_test_environments": "copyfiles -u 2 './test/environments/**/*.json' ./lib/test/environments",
"run_mocha": "mocha lib/test/**/*_test.js --exit",

View File

@ -7,6 +7,7 @@
"async-suffix": true,
"boolean-naming": true,
"no-switch-case-fall-through": true,
"switch-default": true,
"await-promise": true,
"custom-no-magic-numbers": [true, 0, 1, 2, 3, -1],
"binary-expression-operand-order": true,

View File

@ -13,7 +13,7 @@
"clean": "shx rm -rf lib scripts",
"lint": "tslint --project .",
"test": "yarn run_mocha",
"rebuild-and-test": "run-s clean build test",
"rebuild_and_test": "run-s clean build test",
"test:circleci": "yarn test:coverage",
"run_mocha": "mocha lib/test/**/*_test.js --bail --exit",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",

View File

@ -37,6 +37,7 @@
"lodash": "^4.17.4",
"material-ui": "^0.17.1",
"moment": "2.21.0",
"polished": "^1.9.2",
"query-string": "^6.0.0",
"react": "15.6.1",
"react-copy-to-clipboard": "^4.2.3",
@ -52,6 +53,7 @@
"redux": "^3.6.0",
"redux-devtools-extension": "^2.13.2",
"semver-sort": "0.0.4",
"styled-components": "^3.3.0",
"thenby": "^1.2.3",
"truffle-contract": "2.0.1",
"web3": "^0.20.0",

View File

@ -0,0 +1,124 @@
import { colors } from '@0xproject/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
import { Button } from 'ts/components/ui/button';
import { Container } from 'ts/components/ui/container';
import { Input } from 'ts/components/ui/input';
import { Text } from 'ts/components/ui/text';
import { styled } from 'ts/style/theme';
import { backendClient } from 'ts/utils/backend_client';
export interface SubscribeFormProps {}
export enum SubscribeFormStatus {
None,
Error,
Success,
Loading,
Other,
}
export interface SubscribeFormState {
emailText: string;
lastSubmittedEmail: string;
status: SubscribeFormStatus;
}
const FORM_FONT_SIZE = '15px';
// TODO: Translate visible strings. https://app.asana.com/0/628666249318202/697485674422001
export class SubscribeForm extends React.Component<SubscribeFormProps, SubscribeFormState> {
public state = {
emailText: '',
lastSubmittedEmail: '',
status: SubscribeFormStatus.None,
};
public render(): React.ReactNode {
return (
<Container className="flex flex-column items-center justify-between md-mx2 sm-mx2">
<Container marginBottom="15px">
<Text fontFamily="Roboto Mono" fontColor={colors.grey} center={true}>
Subscribe to our newsletter for 0x relayer and dApp updates
</Text>
</Container>
<form onSubmit={this._handleFormSubmitAsync.bind(this)}>
<Container className="flex flex-wrap justify-center items-center">
<Container marginTop="15px">
<Input
placeholder="you@email.com"
value={this.state.emailText}
fontColor={colors.white}
fontSize={FORM_FONT_SIZE}
backgroundColor={colors.projectsGrey}
width="300px"
onChange={this._handleEmailInputChange.bind(this)}
/>
</Container>
<Container marginLeft="15px" marginTop="15px">
<Button
type="submit"
backgroundColor={colors.darkestGrey}
fontColor={colors.white}
fontSize={FORM_FONT_SIZE}
>
Subscribe
</Button>
</Container>
</Container>
</form>
{this._renderMessage()}
</Container>
);
}
private _renderMessage(): React.ReactNode {
let message = null;
switch (this.state.status) {
case SubscribeFormStatus.Error:
message = 'Sorry, something went wrong. Try again later.';
break;
case SubscribeFormStatus.Loading:
message = 'One second...';
break;
case SubscribeFormStatus.Success:
message = `Thanks! ${this.state.lastSubmittedEmail} is now on the mailing list.`;
break;
case SubscribeFormStatus.None:
break;
default:
throw new Error(
'The SubscribeFormStatus switch statement is not exhaustive when choosing an error message.',
);
}
return (
<Container isHidden={!message} marginTop="30px">
<Text center={true} fontFamily="Roboto Mono" fontColor={colors.grey}>
{message || 'spacer text (never shown to user)'}
</Text>
</Container>
);
}
private _handleEmailInputChange(event: React.ChangeEvent<HTMLInputElement>): void {
this.setState({ emailText: event.target.value });
}
private async _handleFormSubmitAsync(event: React.FormEvent<HTMLInputElement>): Promise<void> {
event.preventDefault();
if (_.isUndefined(this.state.emailText) || _.isEmpty(this.state.emailText)) {
return;
}
this.setState({
status: SubscribeFormStatus.Loading,
lastSubmittedEmail: this.state.emailText,
});
try {
const response = await backendClient.subscribeToNewsletterAsync(this.state.emailText);
const status = response.status === 200 ? SubscribeFormStatus.Success : SubscribeFormStatus.Error;
this.setState({ status, emailText: '' });
} catch (error) {
this._setStatus(SubscribeFormStatus.Error);
}
}
private _setStatus(status: SubscribeFormStatus): void {
this.setState({ status });
}
}

View File

@ -5,9 +5,9 @@ import Toggle from 'material-ui/Toggle';
import * as React from 'react';
import { Blockchain } from 'ts/blockchain';
import { Dispatcher } from 'ts/redux/dispatcher';
import { colors } from 'ts/style/colors';
import { BalanceErrs, Token, TokenState } from 'ts/types';
import { analytics } from 'ts/utils/analytics';
import { colors } from 'ts/utils/colors';
import { constants } from 'ts/utils/constants';
import { errorReporter } from 'ts/utils/error_reporter';
import { utils } from 'ts/utils/utils';

View File

@ -5,7 +5,7 @@ import { Placement, Popper, PopperChildrenProps } from 'react-popper';
import { ContinueButtonDisplay, OnboardingTooltip } from 'ts/components/onboarding/onboarding_tooltip';
import { Container } from 'ts/components/ui/container';
import { Overlay } from 'ts/components/ui/overlay';
import { zIndex } from 'ts/utils/style';
import { zIndex } from 'ts/style/z_index';
export interface Step {
target: string;

View File

@ -2,7 +2,7 @@ import { Styles } from '@0xproject/react-shared';
import * as React from 'react';
import { Link } from 'react-router-dom';
import { colors } from 'ts/utils/colors';
import { colors } from 'ts/style/colors';
export interface BackButtonProps {
to: string;

View File

@ -4,8 +4,8 @@ import * as React from 'react';
import { defaultMenuItemEntries, Menu } from 'ts/components/portal/menu';
import { Identicon } from 'ts/components/ui/identicon';
import { colors } from 'ts/style/colors';
import { WebsitePaths } from 'ts/types';
import { colors } from 'ts/utils/colors';
import { utils } from 'ts/utils/utils';
const IDENTICON_DIAMETER = 45;

View File

@ -2,8 +2,8 @@ import { Styles } from '@0xproject/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
import { MenuItem } from 'ts/components/ui/menu_item';
import { colors } from 'ts/style/colors';
import { Environments, WebsitePaths } from 'ts/types';
import { colors } from 'ts/utils/colors';
import { configs } from 'ts/utils/configs';
export interface MenuTheme {

View File

@ -34,6 +34,7 @@ import { Dispatcher } from 'ts/redux/dispatcher';
import {
BlockchainErrs,
HashData,
ItemByAddress,
Order,
ProviderType,
ScreenWidths,
@ -43,6 +44,7 @@ import {
TokenVisibility,
WebsitePaths,
} from 'ts/types';
import { backendClient } from 'ts/utils/backend_client';
import { configs } from 'ts/utils/configs';
import { constants } from 'ts/utils/constants';
import { orderParser } from 'ts/utils/order_parser';
@ -266,10 +268,6 @@ export class Portal extends React.Component<PortalProps, PortalState> {
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
@ -394,18 +392,24 @@ export class Portal extends React.Component<PortalProps, PortalState> {
},
];
return (
<Switch>
{_.map(accountManagementItems, item => {
return (
<Route
key={item.pathName}
path={item.pathName}
render={this._renderAccountManagementItem.bind(this, item)}
/>
);
})}}
<Route render={this._renderNotFoundMessage.bind(this)} />
</Switch>
<div>
<Switch>
{_.map(accountManagementItems, item => {
return (
<Route
key={item.pathName}
path={item.pathName}
render={this._renderAccountManagementItem.bind(this, item)}
/>
);
})}}
<Route render={this._renderNotFoundMessage.bind(this)} />
</Switch>
<PortalDisclaimerDialog
isOpen={this.state.isDisclaimerDialogOpen}
onToggleDialog={this._onPortalDisclaimerAccepted.bind(this)}
/>
</div>
);
}
private _renderAccountManagementItem(item: AccountManagementItem): React.ReactNode {
@ -587,6 +591,7 @@ export class Portal extends React.Component<PortalProps, PortalState> {
return this._blockchain.getTokenBalanceAndAllowanceAsync(userAddressIfExists, tokenAddress);
}),
);
const priceByAddress = await this._getPriceByAddressAsync(tokenAddresses);
for (let i = 0; i < tokenAddresses.length; i++) {
// Order is preserved in Promise.all
const [balance, allowance] = balancesAndAllowances[i];
@ -595,6 +600,7 @@ export class Portal extends React.Component<PortalProps, PortalState> {
balance,
allowance,
isLoaded: true,
price: priceByAddress[tokenAddress],
};
}
this.setState({
@ -602,6 +608,34 @@ export class Portal extends React.Component<PortalProps, PortalState> {
});
}
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 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 {};
}
}
private async _refetchTokenStateAsync(tokenAddress: string): Promise<void> {
await this._fetchBalancesAndAllowancesAsync([tokenAddress]);
}

View File

@ -7,8 +7,8 @@ import { TopTokens } from 'ts/components/relayer_index/relayer_top_tokens';
import { Container } from 'ts/components/ui/container';
import { Island } from 'ts/components/ui/island';
import { TokenIcon } from 'ts/components/ui/token_icon';
import { colors } from 'ts/style/colors';
import { Token, WebsiteBackendRelayerInfo } from 'ts/types';
import { colors } from 'ts/utils/colors';
export interface RelayerGridTileProps {
relayerInfo: WebsiteBackendRelayerInfo;

View File

@ -6,9 +6,9 @@ import { GridList } from 'material-ui/GridList';
import * as React from 'react';
import { RelayerGridTile } from 'ts/components/relayer_index/relayer_grid_tile';
import { colors } from 'ts/style/colors';
import { ScreenWidths, WebsiteBackendRelayerInfo } from 'ts/types';
import { backendClient } from 'ts/utils/backend_client';
import { colors } from 'ts/utils/colors';
export interface RelayerIndexProps {
networkId: number;

View File

@ -77,11 +77,11 @@ interface TokenBalancesProps {
interface TokenBalancesState {
errorType: BalanceErrs;
trackedTokenStateByAddress: TokenStateByAddress;
isBalanceSpinnerVisible: boolean;
isZRXSpinnerVisible: boolean;
isTokenPickerOpen: boolean;
isAddingToken: boolean;
trackedTokenStateByAddress: TokenStateByAddress;
}
export class TokenBalances extends React.Component<TokenBalancesProps, TokenBalancesState> {

View File

@ -9,10 +9,10 @@ import { ProviderPicker } from 'ts/components/top_bar/provider_picker';
import { DropDown } from 'ts/components/ui/drop_down';
import { Identicon } from 'ts/components/ui/identicon';
import { Dispatcher } from 'ts/redux/dispatcher';
import { colors } from 'ts/style/colors';
import { zIndex } from 'ts/style/z_index';
import { ProviderType } from 'ts/types';
import { colors } from 'ts/utils/colors';
import { constants } from 'ts/utils/constants';
import { zIndex } from 'ts/utils/style';
import { utils } from 'ts/utils/utils';
const ROOT_HEIGHT = 24;

View File

@ -16,9 +16,9 @@ import { TopBarMenuItem } from 'ts/components/top_bar/top_bar_menu_item';
import { DropDown } from 'ts/components/ui/drop_down';
import { Identicon } from 'ts/components/ui/identicon';
import { Dispatcher } from 'ts/redux/dispatcher';
import { zIndex } from 'ts/style/z_index';
import { Deco, Key, ProviderType, WebsiteLegacyPaths, WebsitePaths } from 'ts/types';
import { constants } from 'ts/utils/constants';
import { zIndex } from 'ts/utils/style';
import { Translate } from 'ts/utils/translate';
import { utils } from 'ts/utils/utils';

View File

@ -0,0 +1,79 @@
import { colors } from '@0xproject/react-shared';
import { darken } from 'polished';
import * as React from 'react';
import { styled } from 'ts/style/theme';
export interface ButtonProps {
className?: string;
fontSize?: string;
fontColor?: string;
backgroundColor?: string;
borderColor?: string;
width?: string;
type?: string;
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
}
const PlainButton: React.StatelessComponent<ButtonProps> = ({ children, onClick, type, className }) => (
<button type={type} className={className} onClick={onClick}>
{children}
</button>
);
export const Button = styled(PlainButton)`
cursor: pointer;
font-size: ${props => props.fontSize};
color: ${props => props.fontColor};
padding: 0.8em 2.2em;
border-radius: 6px;
box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.25);
font-weight: 500;
font-family: 'Roboto';
width: ${props => props.width};
background-color: ${props => props.backgroundColor};
border: ${props => (props.borderColor ? `1px solid ${props.borderColor}` : 'none')};
&:hover {
background-color: ${props => darken(0.1, props.backgroundColor)};
}
&:active {
background-color: ${props => darken(0.2, props.backgroundColor)};
}
`;
Button.defaultProps = {
fontSize: '12px',
backgroundColor: colors.white,
width: 'auto',
};
Button.displayName = 'Button';
type CallToActionType = 'light' | 'dark';
export interface CallToActionProps {
type?: CallToActionType;
fontSize?: string;
width?: string;
}
export const CallToAction: React.StatelessComponent<CallToActionProps> = ({ children, type, fontSize, width }) => {
const isLight = type === 'light';
const backgroundColor = isLight ? colors.white : colors.heroGrey;
const fontColor = isLight ? colors.heroGrey : colors.white;
const borderColor = isLight ? undefined : colors.white;
return (
<Button
fontSize={fontSize}
backgroundColor={backgroundColor}
fontColor={fontColor}
width={width}
borderColor={borderColor}
>
{children}
</Button>
);
};
CallToAction.defaultProps = {
type: 'dark',
};

View File

@ -11,13 +11,20 @@ export interface ContainerProps {
paddingBottom?: StringOrNum;
paddingRight?: StringOrNum;
paddingLeft?: StringOrNum;
backgroundColor?: string;
borderRadius?: StringOrNum;
maxWidth?: StringOrNum;
children?: React.ReactNode;
isHidden?: boolean;
className?: string;
}
export const Container: React.StatelessComponent<ContainerProps> = (props: ContainerProps) => {
const { children, ...style } = props;
return <div style={style}>{children}</div>;
export const Container: React.StatelessComponent<ContainerProps> = ({ children, className, isHidden, ...style }) => {
const visibility = isHidden ? 'hidden' : undefined;
return (
<div style={{ ...style, visibility }} className={className}>
{children}
</div>
);
};
Container.displayName = 'Container';

View File

@ -0,0 +1,43 @@
import { colors } from '@0xproject/react-shared';
import * as React from 'react';
import { styled } from 'ts/style/theme';
export interface InputProps {
className?: string;
value?: string;
width?: string;
fontSize?: string;
fontColor?: string;
placeholderColor?: string;
placeholder?: string;
backgroundColor?: string;
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
}
const PlainInput: React.StatelessComponent<InputProps> = ({ value, className, placeholder, onChange }) => (
<input className={className} value={value} onChange={onChange} placeholder={placeholder} />
);
export const Input = styled(PlainInput)`
font-size: ${props => props.fontSize};
width: ${props => props.width};
padding: 0.8em 1.2em;
border-radius: 3px;
font-family: 'Roboto Mono';
color: ${props => props.fontColor};
border: none;
background-color: ${props => props.backgroundColor};
&::placeholder {
color: ${props => props.placeholderColor};
}
`;
Input.defaultProps = {
width: 'auto',
backgroundColor: colors.white,
fontColor: colors.darkestGrey,
placeholderColor: colors.darkGrey,
fontSize: '12px',
};
Input.displayName = 'Input';

View File

@ -1,6 +1,6 @@
import * as React from 'react';
import { colors } from 'ts/style/colors';
import { Styleable } from 'ts/types';
import { colors } from 'ts/utils/colors';
export interface IslandProps {
style?: React.CSSProperties;

View File

@ -2,7 +2,7 @@ import { colors } from '@0xproject/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
import { zIndex } from 'ts/utils/style';
import { zIndex } from 'ts/style/z_index';
export interface OverlayProps {
children?: React.ReactNode;

View File

@ -0,0 +1,41 @@
import { colors } from '@0xproject/react-shared';
import * as React from 'react';
import { styled } from 'ts/style/theme';
import { Deco, Key } from 'ts/types';
import { Translate } from 'ts/utils/translate';
export type TextTag = 'p' | 'div' | 'span' | 'label';
export interface TextProps {
className?: string;
Tag?: TextTag;
fontSize?: string;
fontFamily?: string;
fontColor?: string;
lineHeight?: string;
center?: boolean;
fontWeight?: number;
}
const PlainText: React.StatelessComponent<TextProps> = ({ children, className, Tag }) => (
<Tag className={className}>{children}</Tag>
);
export const Text = styled(PlainText)`
font-family: ${props => props.fontFamily};
font-weight: ${props => props.fontWeight};
font-size: ${props => props.fontSize};
${props => (props.lineHeight ? `line-height: ${props.lineHeight}` : '')};
${props => (props.center ? 'text-align: center' : '')};
color: ${props => props.fontColor};
`;
Text.defaultProps = {
fontFamily: 'Roboto',
fontWeight: 400,
fontColor: colors.white,
fontSize: '14px',
Tag: 'div',
};
Text.displayName = 'Text';

View File

@ -32,10 +32,11 @@ import { TokenIcon } from 'ts/components/ui/token_icon';
import { WalletDisconnectedItem } from 'ts/components/wallet/wallet_disconnected_item';
import { WrapEtherItem } from 'ts/components/wallet/wrap_ether_item';
import { Dispatcher } from 'ts/redux/dispatcher';
import { colors } from 'ts/style/colors';
import { zIndex } from 'ts/style/z_index';
import {
BalanceErrs,
BlockchainErrs,
ItemByAddress,
ProviderType,
ScreenWidths,
Side,
@ -45,10 +46,7 @@ import {
TokenStateByAddress,
WebsitePaths,
} from 'ts/types';
import { backendClient } from 'ts/utils/backend_client';
import { colors } from 'ts/utils/colors';
import { constants } from 'ts/utils/constants';
import { zIndex } from 'ts/utils/style';
import { utils } from 'ts/utils/utils';
import { styles as walletItemStyles } from 'ts/utils/wallet_item_styles';
@ -523,34 +521,6 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
});
return trackedTokenStateByAddress;
}
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 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 {};
}
}
private _openWrappedEtherActionRow(wrappedEtherDirection: Side): void {
this.setState({
wrappedEtherDirection,

View File

@ -3,8 +3,8 @@ import FlatButton from 'material-ui/FlatButton';
import ActionAccountBalanceWallet from 'material-ui/svg-icons/action/account-balance-wallet';
import * as React from 'react';
import { colors } from 'ts/style/colors';
import { ProviderType } from 'ts/types';
import { colors } from 'ts/utils/colors';
import { constants } from 'ts/utils/constants';
import { utils } from 'ts/utils/utils';

View File

@ -10,8 +10,8 @@ import { Blockchain } from 'ts/blockchain';
import { EthAmountInput } from 'ts/components/inputs/eth_amount_input';
import { TokenAmountInput } from 'ts/components/inputs/token_amount_input';
import { Dispatcher } from 'ts/redux/dispatcher';
import { colors } from 'ts/style/colors';
import { BlockchainCallErrs, Side, Token } from 'ts/types';
import { colors } from 'ts/utils/colors';
import { constants } from 'ts/utils/constants';
import { errorReporter } from 'ts/utils/error_reporter';
import { utils } from 'ts/utils/utils';

View File

@ -1,11 +1,13 @@
import { colors } from '@0xproject/react-shared';
import * as _ from 'lodash';
import RaisedButton from 'material-ui/RaisedButton';
import * as React from 'react';
import DocumentTitle = require('react-document-title');
import { Link } from 'react-router-dom';
import { Footer } from 'ts/components/footer';
import { SubscribeForm } from 'ts/components/forms/subscribe_form';
import { TopBar } from 'ts/components/top_bar/top_bar';
import { CallToAction } from 'ts/components/ui/button';
import { Container } from 'ts/components/ui/container';
import { Dispatcher } from 'ts/redux/dispatcher';
import { Deco, Key, Language, ScreenWidths, WebsitePaths } from 'ts/types';
import { constants } from 'ts/utils/constants';
@ -236,7 +238,7 @@ export class Landing extends React.Component<LandingProps, LandingState> {
<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="lg-pt4 md-pt4 sm-pt2 lg-pb4 md-pb4 lg-mt4 md-mt4 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} />
</div>
@ -268,40 +270,31 @@ export class Landing extends React.Component<LandingProps, LandingState> {
>
{this.props.translate.get(Key.TopTagline)}
</div>
<div className="pt3 clearfix sm-mx-auto" style={{ maxWidth: 389 }}>
<div className="lg-pr2 md-pr2 col col-6 sm-center">
<Container className="pt3 clearfix sm-mx-auto" maxWidth="390px">
<div className="lg-pr2 md-pr2 lg-col lg-col-6 sm-center sm-col sm-col-12 mb2">
<Link to={WebsitePaths.ZeroExJs} className="text-decoration-none">
<RaisedButton
style={{ borderRadius: 6, minWidth: 157.36 }}
buttonStyle={{ borderRadius: 6 }}
labelStyle={buttonLabelStyle}
label={this.props.translate.get(Key.BuildCallToAction, Deco.Cap)}
onClick={_.noop}
/>
<CallToAction width="175px" type="light">
{this.props.translate.get(Key.BuildCallToAction, Deco.Cap)}
</CallToAction>
</Link>
</div>
<div className="col col-6 sm-center">
<div className="lg-col lg-col-6 sm-center sm-col sm-col-12">
<a
href={constants.URL_ZEROEX_CHAT}
target="_blank"
className="text-decoration-none"
>
<RaisedButton
style={{ borderRadius: 6, minWidth: 150 }}
buttonStyle={lightButtonStyle}
labelColor="white"
backgroundColor={colors.heroGrey}
labelStyle={buttonLabelStyle}
label={this.props.translate.get(Key.CommunityCallToAction, Deco.Cap)}
onClick={_.noop}
/>
<CallToAction width="175px">
{this.props.translate.get(Key.CommunityCallToAction, Deco.Cap)}
</CallToAction>
</a>
</div>
</div>
</Container>
</div>
</div>
</div>
</div>
{this.props.translate.getLanguage() === Language.English && <SubscribeForm />}
</div>
);
}
@ -349,6 +342,9 @@ export class Landing extends React.Component<LandingProps, LandingState> {
case ScreenWidths.Lg:
colWidth = isRelayersOnly ? 2 : 2 - i % 2;
break;
default:
throw new Error(`Encountered unknown ScreenWidths value: ${this.state.screenWidth}`);
}
return (
<div key={`project-${project.logoFileName}`} className={`col col-${colWidth} center`}>
@ -782,15 +778,9 @@ export class Landing extends React.Component<LandingProps, LandingState> {
</div>
<div className="sm-center sm-pt2 lg-table-cell md-table-cell">
<Link to={WebsitePaths.ZeroExJs} className="text-decoration-none">
<RaisedButton
style={{ borderRadius: 6, minWidth: 150 }}
buttonStyle={lightButtonStyle}
labelColor={colors.white}
backgroundColor={colors.heroGrey}
labelStyle={buttonLabelStyle}
label={this.props.translate.get(Key.BuildCallToAction, Deco.Cap)}
onClick={_.noop}
/>
<CallToAction fontSize="15px">
{this.props.translate.get(Key.BuildCallToAction, Deco.Cap)}
</CallToAction>
</Link>
</div>
</div>

View File

@ -0,0 +1,15 @@
import * as styledComponents from 'styled-components';
const {
default: styled,
css,
injectGlobal,
keyframes,
ThemeProvider,
} = styledComponents as styledComponents.ThemedStyledComponentsModule<IThemeInterface>;
export interface IThemeInterface {}
export const theme = {};
export { styled, css, injectGlobal, keyframes, ThemeProvider };

View File

@ -8,6 +8,7 @@ const ETH_GAS_STATION_ENDPOINT = '/eth_gas_station';
const PRICES_ENDPOINT = '/prices';
const RELAYERS_ENDPOINT = '/relayers';
const WIKI_ENDPOINT = '/wiki';
const SUBSCRIBE_SUBSTACK_NEWSLETTER_ENDPOINT = '/newsletter_subscriber/substack';
export const backendClient = {
async getGasInfoAsync(): Promise<WebsiteBackendGasInfo> {
@ -33,4 +34,11 @@ export const backendClient = {
const result = await fetchUtils.requestAsync(utils.getBackendBaseUrl(), WIKI_ENDPOINT);
return result;
},
async subscribeToNewsletterAsync(email: string): Promise<Response> {
const result = await fetchUtils.postAsync(utils.getBackendBaseUrl(), SUBSCRIBE_SUBSTACK_NEWSLETTER_ENDPOINT, {
email,
referrer: window.location.href,
});
return result;
},
};

View File

@ -4,22 +4,38 @@ import * as queryString from 'query-string';
import { errorReporter } from 'ts/utils/error_reporter';
const logErrorIfPresent = (response: Response, requestedURL: string) => {
if (response.status !== 200) {
const errorText = `Error requesting url: ${requestedURL}, ${response.status}: ${response.statusText}`;
logUtils.log(errorText);
const error = Error(errorText);
// tslint:disable-next-line:no-floating-promises
errorReporter.reportAsync(error);
throw error;
}
};
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;
}
logErrorIfPresent(response, url);
const result = await response.json();
return result;
},
async postAsync(baseUrl: string, path: string, body: object): Promise<Response> {
const url = `${baseUrl}${path}`;
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
});
logErrorIfPresent(response, url);
return response;
},
};
function queryStringFromQueryParams(queryParams?: object): string {

View File

@ -1,6 +1,6 @@
import { Styles } from '@0xproject/react-shared';
import { colors } from 'ts/utils/colors';
import { colors } from 'ts/style/colors';
export const styles: Styles = {
focusedItem: {

View File

@ -2044,7 +2044,7 @@ buffer@^4.3.0:
ieee754 "^1.1.4"
isarray "^1.0.0"
buffer@^5.0.5:
buffer@^5.0.3, buffer@^5.0.5:
version "5.1.0"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.1.0.tgz#c913e43678c7cb7c8bd16afbcddb6c5505e8f9fe"
dependencies:
@ -3061,6 +3061,10 @@ crypto-random-string@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
css-color-keywords@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
css-color-names@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
@ -3122,6 +3126,14 @@ css-selector-tokenizer@^0.7.0:
fastparse "^1.1.1"
regexpu-core "^1.0.0"
css-to-react-native@^2.0.3:
version "2.2.0"
resolved "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-2.2.0.tgz#d524ef7f39a2747a8914e86563669ba35b7cf2e7"
dependencies:
css-color-keywords "^1.0.0"
fbjs "^0.8.5"
postcss-value-parser "^3.3.0"
cssesc@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4"
@ -4491,7 +4503,7 @@ faye-websocket@~0.11.0:
dependencies:
websocket-driver ">=0.5.1"
fbjs@^0.8.0, fbjs@^0.8.1, fbjs@^0.8.16, fbjs@^0.8.4, fbjs@^0.8.6, fbjs@^0.8.9:
fbjs@^0.8.0, fbjs@^0.8.1, fbjs@^0.8.16, fbjs@^0.8.4, fbjs@^0.8.5, fbjs@^0.8.6, fbjs@^0.8.9:
version "0.8.16"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db"
dependencies:
@ -8721,6 +8733,10 @@ plur@^2.1.2:
dependencies:
irregular-plurals "^1.0.0"
polished@^1.9.2:
version "1.9.2"
resolved "https://registry.npmjs.org/polished/-/polished-1.9.2.tgz#d705cac66f3a3ed1bd38aad863e2c1e269baf6b6"
popper.js@^1.14.1:
version "1.14.3"
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.14.3.tgz#1438f98d046acf7b4d78cd502bf418ac64d4f095"
@ -9557,6 +9573,10 @@ react-highlight@0xproject/react-highlight:
react "^15.5.4"
react-dom "^15.5.4"
react-is@^16.3.1:
version "16.4.0"
resolved "https://registry.npmjs.org/react-is/-/react-is-16.4.0.tgz#cc9fdc855ac34d2e7d9d2eb7059bbc240d35ffcf"
react-markdown@^3.2.2:
version "3.3.0"
resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-3.3.0.tgz#a87cdd822aa9302d6add9687961dd1a82a45d02e"
@ -11188,6 +11208,29 @@ style-loader@^0.20.2:
loader-utils "^1.1.0"
schema-utils "^0.4.5"
styled-components@^3.3.0:
version "3.3.0"
resolved "https://registry.npmjs.org/styled-components/-/styled-components-3.3.0.tgz#335b1b2b673b416cd5ec012010e237ed1f877fe9"
dependencies:
buffer "^5.0.3"
css-to-react-native "^2.0.3"
fbjs "^0.8.16"
hoist-non-react-statics "^2.5.0"
is-plain-object "^2.0.1"
prop-types "^15.5.4"
react-is "^16.3.1"
stylis "^3.5.0"
stylis-rule-sheet "^0.0.10"
supports-color "^3.2.3"
stylis-rule-sheet@^0.0.10:
version "0.0.10"
resolved "https://registry.npmjs.org/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz#44e64a2b076643f4b52e5ff71efc04d8c3c4a430"
stylis@^3.5.0:
version "3.5.0"
resolved "https://registry.npmjs.org/stylis/-/stylis-3.5.0.tgz#016fa239663d77f868fef5b67cf201c4b7c701e1"
supports-color@3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5"