aboutsummaryrefslogtreecommitdiffstats
path: root/packages/instant
diff options
context:
space:
mode:
Diffstat (limited to 'packages/instant')
-rw-r--r--packages/instant/.discharge.json13
-rw-r--r--packages/instant/README.md12
-rw-r--r--packages/instant/package.json2
-rw-r--r--packages/instant/public/index.html2
-rw-r--r--packages/instant/src/components/amount_placeholder.tsx32
-rw-r--r--packages/instant/src/components/animations/pulse.tsx15
-rw-r--r--packages/instant/src/components/instant_heading.tsx145
-rw-r--r--packages/instant/src/components/order_details.tsx91
-rw-r--r--packages/instant/src/components/ui/container.tsx2
-rw-r--r--packages/instant/src/components/zero_ex_instant.tsx52
-rw-r--r--packages/instant/src/containers/latest_buy_quote_order_details.ts3
-rw-r--r--packages/instant/src/containers/latest_error.tsx6
-rw-r--r--packages/instant/src/containers/selected_asset_amount_input.ts8
-rw-r--r--packages/instant/src/containers/selected_asset_buy_button.ts8
-rw-r--r--packages/instant/src/containers/selected_asset_instant_heading.ts4
-rw-r--r--packages/instant/src/containers/selected_asset_theme_provider.ts32
-rw-r--r--packages/instant/src/redux/actions.ts10
-rw-r--r--packages/instant/src/redux/reducer.ts44
-rw-r--r--packages/instant/src/redux/store.ts11
-rw-r--r--packages/instant/src/types.ts4
-rw-r--r--packages/instant/src/util/asset.ts17
-rw-r--r--packages/instant/tslint.json3
22 files changed, 327 insertions, 189 deletions
diff --git a/packages/instant/.discharge.json b/packages/instant/.discharge.json
new file mode 100644
index 000000000..9ade97d01
--- /dev/null
+++ b/packages/instant/.discharge.json
@@ -0,0 +1,13 @@
+{
+ "domain": "0x-instant-dogfood",
+ "build_command": "yarn build:umd:prod",
+ "upload_directory": "public",
+ "index_key": "index.html",
+ "error_key": "index.html",
+ "trailing_slashes": true,
+ "cache": 3600,
+ "aws_profile": "default",
+ "aws_region": "us-east-1",
+ "cdn": false,
+ "dns_configured": true
+}
diff --git a/packages/instant/README.md b/packages/instant/README.md
index 55b4404e7..07b01ac95 100644
--- a/packages/instant/README.md
+++ b/packages/instant/README.md
@@ -46,6 +46,18 @@ The package is also available as a UMD module named `zeroExInstant`.
</body>
```
+## Deploying
+
+You can deploy a work-in-progress version of 0x Instant at http://0x-instant-dogfood.s3-website-us-east-1.amazonaws.com for easy sharing.
+
+To build and deploy the site run
+
+```
+yarn deploy
+```
+
+**NOTE: On deploying the site, it will say the site is available at a non-existent URL. Please ignore and use the (now updated) URL above.**
+
## Contributing
We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
diff --git a/packages/instant/package.json b/packages/instant/package.json
index e5c4ee12d..1a6e9d2e9 100644
--- a/packages/instant/package.json
+++ b/packages/instant/package.json
@@ -22,6 +22,7 @@
"rebuild_and_test": "run-s clean build test",
"test:circleci": "yarn test:coverage",
"clean": "shx rm -rf lib coverage scripts",
+ "deploy": "discharge deploy",
"manual:postpublish": "yarn build; node ./scripts/postpublish.js"
},
"config": {
@@ -61,6 +62,7 @@
"ts-optchain": "^0.1.1"
},
"devDependencies": {
+ "@static/discharge": "^1.2.2",
"@0x/tslint-config": "^1.0.9",
"@types/enzyme": "^3.1.14",
"@types/enzyme-adapter-react-16": "^1.0.3",
diff --git a/packages/instant/public/index.html b/packages/instant/public/index.html
index 1f6a0a9e9..14555fc64 100644
--- a/packages/instant/public/index.html
+++ b/packages/instant/public/index.html
@@ -25,7 +25,7 @@
<div id="zeroExInstantContainer"></div>
<script>
zeroExInstant.render({
- sraApiUrl: 'https://api.radarrelay.com/0x/v2/',
+ liquiditySource: 'https://api.radarrelay.com/0x/v2/',
assetData: '0xf47261b0000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498',
});
</script>
diff --git a/packages/instant/src/components/amount_placeholder.tsx b/packages/instant/src/components/amount_placeholder.tsx
new file mode 100644
index 000000000..6ef8f0ac3
--- /dev/null
+++ b/packages/instant/src/components/amount_placeholder.tsx
@@ -0,0 +1,32 @@
+import * as React from 'react';
+
+import { ColorOption } from '../style/theme';
+
+import { Pulse } from './animations/pulse';
+
+import { Text } from './ui';
+
+interface PlainPlaceholder {
+ color: ColorOption;
+}
+const PlainPlaceholder: React.StatelessComponent<PlainPlaceholder> = props => (
+ <Text fontWeight="bold" fontColor={props.color}>
+ &mdash;
+ </Text>
+);
+
+export interface AmountPlaceholderProps {
+ color: ColorOption;
+ isPulsating: boolean;
+}
+export const AmountPlaceholder: React.StatelessComponent<AmountPlaceholderProps> = props => {
+ if (props.isPulsating) {
+ return (
+ <Pulse>
+ <PlainPlaceholder color={props.color} />
+ </Pulse>
+ );
+ } else {
+ return <PlainPlaceholder color={props.color} />;
+ }
+};
diff --git a/packages/instant/src/components/animations/pulse.tsx b/packages/instant/src/components/animations/pulse.tsx
new file mode 100644
index 000000000..01d6ea070
--- /dev/null
+++ b/packages/instant/src/components/animations/pulse.tsx
@@ -0,0 +1,15 @@
+import { keyframes, styled } from '../../style/theme';
+
+const pulsingKeyframes = keyframes`
+ 0%, 100% {
+ opacity: 0.2;
+ }
+ 50% {
+ opacity: 100;
+ }
+`;
+export const Pulse = styled.div`
+ animation-name: ${pulsingKeyframes}
+ animation-duration: 2s;
+ animation-iteration-count: infinite;
+`;
diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx
index 6fc5a0963..5d39e4048 100644
--- a/packages/instant/src/components/instant_heading.tsx
+++ b/packages/instant/src/components/instant_heading.tsx
@@ -7,95 +7,90 @@ import { ColorOption } from '../style/theme';
import { AsyncProcessState } from '../types';
import { format } from '../util/format';
+import { AmountPlaceholder } from './amount_placeholder';
import { Container, Flex, Text } from './ui';
export interface InstantHeadingProps {
selectedAssetAmount?: BigNumber;
totalEthBaseAmount?: BigNumber;
ethUsdPrice?: BigNumber;
- quoteState: AsyncProcessState;
+ quoteRequestState: AsyncProcessState;
buyOrderState: AsyncProcessState;
}
-const Placeholder = () => (
- <Text fontWeight="bold" fontColor={ColorOption.white}>
- &mdash;
- </Text>
-);
-const displaytotalEthBaseAmount = ({
- selectedAssetAmount,
- totalEthBaseAmount,
-}: InstantHeadingProps): React.ReactNode => {
- if (_.isUndefined(selectedAssetAmount)) {
- return '0 ETH';
+const placeholderColor = ColorOption.white;
+export class InstantHeading extends React.Component<InstantHeadingProps, {}> {
+ public render(): React.ReactNode {
+ return (
+ <Container
+ backgroundColor={ColorOption.primaryColor}
+ padding="20px"
+ width="100%"
+ borderRadius="3px 3px 0px 0px"
+ >
+ <Container marginBottom="5px">
+ <Text
+ letterSpacing="1px"
+ fontColor={ColorOption.white}
+ opacity={0.7}
+ fontWeight={500}
+ textTransform="uppercase"
+ fontSize="12px"
+ >
+ {this._renderTopText()}
+ </Text>
+ </Container>
+ <Flex direction="row" justify="space-between">
+ <SelectedAssetAmountInput fontSize="45px" />
+ <Flex direction="column" justify="space-between">
+ <Container marginBottom="5px">{this._placeholderOrAmount(this._ethAmount)}</Container>
+ <Container opacity={0.7}>{this._placeholderOrAmount(this._dollarAmount)}</Container>
+ </Flex>
+ </Flex>
+ </Container>
+ );
}
- return format.ethBaseAmount(totalEthBaseAmount, 4, <Placeholder />);
-};
-const displayUsdAmount = ({
- totalEthBaseAmount,
- selectedAssetAmount,
- ethUsdPrice,
-}: InstantHeadingProps): React.ReactNode => {
- if (_.isUndefined(selectedAssetAmount)) {
- return '$0.00';
- }
- return format.ethBaseAmountInUsd(totalEthBaseAmount, ethUsdPrice, 2, <Placeholder />);
-};
+ private _renderTopText(): React.ReactNode {
+ if (this.props.buyOrderState === AsyncProcessState.FAILURE) {
+ return 'Order failed';
+ }
-const loadingOrAmount = (quoteState: AsyncProcessState, amount: React.ReactNode): React.ReactNode => {
- if (quoteState === AsyncProcessState.PENDING) {
- return (
- <Text fontWeight="bold" fontColor={ColorOption.white}>
- &hellip;loading
- </Text>
- );
- } else {
- return amount;
+ return 'I want to buy';
}
-};
-const topText = (buyOrderState: AsyncProcessState): string => {
- if (buyOrderState === AsyncProcessState.FAILURE) {
- return 'Order failed';
+ private _placeholderOrAmount(amountFunction: () => React.ReactNode): React.ReactNode {
+ if (this.props.quoteRequestState === AsyncProcessState.PENDING) {
+ return <AmountPlaceholder isPulsating={true} color={placeholderColor} />;
+ }
+ if (_.isUndefined(this.props.selectedAssetAmount)) {
+ return <AmountPlaceholder isPulsating={false} color={placeholderColor} />;
+ }
+ return amountFunction();
}
- return 'I want to buy';
-};
+ private readonly _ethAmount = (): React.ReactNode => {
+ return (
+ <Text fontSize="16px" fontColor={ColorOption.white} fontWeight={500}>
+ {format.ethBaseAmount(
+ this.props.totalEthBaseAmount,
+ 4,
+ <AmountPlaceholder isPulsating={false} color={placeholderColor} />,
+ )}
+ </Text>
+ );
+ };
-export const InstantHeading: React.StatelessComponent<InstantHeadingProps> = props => {
- return (
- <Container
- backgroundColor={ColorOption.primaryColor}
- padding="20px"
- width="100%"
- borderRadius="3px 3px 0px 0px"
- >
- <Container marginBottom="5px">
- <Text
- letterSpacing="1px"
- fontColor={ColorOption.white}
- opacity={0.7}
- fontWeight={500}
- textTransform="uppercase"
- fontSize="12px"
- >
- {topText(props.buyOrderState)}
- </Text>
- </Container>
- <Flex direction="row" justify="space-between">
- <SelectedAssetAmountInput fontSize="45px" />
- <Flex direction="column" justify="space-between">
- <Container marginBottom="5px">
- <Text fontSize="16px" fontColor={ColorOption.white} fontWeight={500}>
- {loadingOrAmount(props.quoteState, displaytotalEthBaseAmount(props))}
- </Text>
- </Container>
- <Text fontSize="16px" fontColor={ColorOption.white} opacity={0.7}>
- {loadingOrAmount(props.quoteState, displayUsdAmount(props))}
- </Text>
- </Flex>
- </Flex>
- </Container>
- );
-};
+ private readonly _dollarAmount = (): React.ReactNode => {
+ return (
+ <Text fontSize="16px" fontColor={ColorOption.white}>
+ {format.ethBaseAmountInUsd(
+ this.props.totalEthBaseAmount,
+ this.props.ethUsdPrice,
+ 2,
+ <AmountPlaceholder isPulsating={false} color={ColorOption.white} />,
+ )}
+ </Text>
+ );
+ };
+}
diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx
index ad4a87714..704009d89 100644
--- a/packages/instant/src/components/order_details.tsx
+++ b/packages/instant/src/components/order_details.tsx
@@ -7,13 +7,14 @@ import { oc } from 'ts-optchain';
import { ColorOption } from '../style/theme';
import { format } from '../util/format';
+import { AmountPlaceholder } from './amount_placeholder';
import { Container, Flex, Text } from './ui';
export interface OrderDetailsProps {
buyQuoteInfo?: BuyQuoteInfo;
ethUsdPrice?: BigNumber;
+ isLoading: boolean;
}
-
export class OrderDetails extends React.Component<OrderDetailsProps> {
public render(): React.ReactNode {
const { buyQuoteInfo, ethUsdPrice } = this.props;
@@ -39,13 +40,20 @@ export class OrderDetails extends React.Component<OrderDetailsProps> {
ethAmount={ethAssetPrice}
ethUsdPrice={ethUsdPrice}
isEthAmountInBaseUnits={false}
+ isLoading={this.props.isLoading}
+ />
+ <EthAmountRow
+ rowLabel="Fee"
+ ethAmount={ethTokenFee}
+ ethUsdPrice={ethUsdPrice}
+ isLoading={this.props.isLoading}
/>
- <EthAmountRow rowLabel="Fee" ethAmount={ethTokenFee} ethUsdPrice={ethUsdPrice} />
<EthAmountRow
rowLabel="Total Cost"
ethAmount={totalEthAmount}
ethUsdPrice={ethUsdPrice}
shouldEmphasize={true}
+ isLoading={this.props.isLoading}
/>
</Container>
);
@@ -58,43 +66,50 @@ export interface EthAmountRowProps {
isEthAmountInBaseUnits?: boolean;
ethUsdPrice?: BigNumber;
shouldEmphasize?: boolean;
+ isLoading: boolean;
}
-export const EthAmountRow: React.StatelessComponent<EthAmountRowProps> = ({
- rowLabel,
- ethAmount,
- isEthAmountInBaseUnits,
- ethUsdPrice,
- shouldEmphasize,
-}) => {
- const fontWeight = shouldEmphasize ? 700 : 400;
- const usdFormatter = isEthAmountInBaseUnits ? format.ethBaseAmountInUsd : format.ethUnitAmountInUsd;
- const ethFormatter = isEthAmountInBaseUnits ? format.ethBaseAmount : format.ethUnitAmount;
- const usdPriceSection = _.isUndefined(ethUsdPrice) ? null : (
- <Container marginRight="3px" display="inline-block">
- <Text fontColor={ColorOption.lightGrey}>({usdFormatter(ethAmount, ethUsdPrice)})</Text>
- </Container>
- );
- return (
- <Container padding="10px 0px" borderTop="1px dashed" borderColor={ColorOption.feintGrey}>
- <Flex justify="space-between">
- <Text fontWeight={fontWeight} fontColor={ColorOption.grey}>
- {rowLabel}
- </Text>
- <Container>
- {usdPriceSection}
+export class EthAmountRow extends React.Component<EthAmountRowProps> {
+ public static defaultProps = {
+ shouldEmphasize: false,
+ isEthAmountInBaseUnits: true,
+ };
+ public render(): React.ReactNode {
+ const { rowLabel, ethAmount, isEthAmountInBaseUnits, shouldEmphasize, isLoading } = this.props;
+
+ const fontWeight = shouldEmphasize ? 700 : 400;
+ const ethFormatter = isEthAmountInBaseUnits ? format.ethBaseAmount : format.ethUnitAmount;
+ return (
+ <Container padding="10px 0px" borderTop="1px dashed" borderColor={ColorOption.feintGrey}>
+ <Flex justify="space-between">
<Text fontWeight={fontWeight} fontColor={ColorOption.grey}>
- {ethFormatter(ethAmount)}
+ {rowLabel}
</Text>
- </Container>
- </Flex>
- </Container>
- );
-};
-
-EthAmountRow.defaultProps = {
- shouldEmphasize: false,
- isEthAmountInBaseUnits: true,
-};
-
-EthAmountRow.displayName = 'EthAmountRow';
+ <Container>
+ {this._renderUsdSection()}
+ <Text fontWeight={fontWeight} fontColor={ColorOption.grey}>
+ {ethFormatter(
+ ethAmount,
+ 4,
+ <Container opacity={0.5}>
+ <AmountPlaceholder color={ColorOption.lightGrey} isPulsating={isLoading} />
+ </Container>,
+ )}
+ </Text>
+ </Container>
+ </Flex>
+ </Container>
+ );
+ }
+ private _renderUsdSection(): React.ReactNode {
+ const usdFormatter = this.props.isEthAmountInBaseUnits ? format.ethBaseAmountInUsd : format.ethUnitAmountInUsd;
+ const shouldHideUsdPriceSection = _.isUndefined(this.props.ethUsdPrice) || _.isUndefined(this.props.ethAmount);
+ return shouldHideUsdPriceSection ? null : (
+ <Container marginRight="3px" display="inline-block">
+ <Text fontColor={ColorOption.lightGrey}>
+ ({usdFormatter(this.props.ethAmount, this.props.ethUsdPrice)})
+ </Text>
+ </Container>
+ );
+ }
+}
diff --git a/packages/instant/src/components/ui/container.tsx b/packages/instant/src/components/ui/container.tsx
index 02b16e39f..5e2218c68 100644
--- a/packages/instant/src/components/ui/container.tsx
+++ b/packages/instant/src/components/ui/container.tsx
@@ -27,6 +27,7 @@ export interface ContainerProps {
backgroundColor?: ColorOption;
hasBoxShadow?: boolean;
zIndex?: number;
+ opacity?: number;
}
const PlainContainer: React.StatelessComponent<ContainerProps> = ({ children, className }) => (
@@ -54,6 +55,7 @@ export const Container = styled(PlainContainer)`
${props => cssRuleIfExists(props, 'border-top')}
${props => cssRuleIfExists(props, 'border-bottom')}
${props => cssRuleIfExists(props, 'z-index')}
+ ${props => cssRuleIfExists(props, 'opacity')}
${props => (props.hasBoxShadow ? `box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1)` : '')};
background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')};
border-color: ${props => (props.borderColor ? props.theme[props.borderColor] : 'none')};
diff --git a/packages/instant/src/components/zero_ex_instant.tsx b/packages/instant/src/components/zero_ex_instant.tsx
index 5b75a7556..142e74dae 100644
--- a/packages/instant/src/components/zero_ex_instant.tsx
+++ b/packages/instant/src/components/zero_ex_instant.tsx
@@ -3,13 +3,12 @@ import { ObjectMap } from '@0x/types';
import * as React from 'react';
import { Provider } from 'react-redux';
-import { assetMetaDataMap } from '../data/asset_meta_data_map';
+import { SelectedAssetThemeProvider } from '../containers/selected_asset_theme_provider';
import { asyncData } from '../redux/async_data';
-import { State } from '../redux/reducer';
+import { INITIAL_STATE, State } from '../redux/reducer';
import { store, Store } from '../redux/store';
import { fonts } from '../style/fonts';
-import { theme, ThemeProvider } from '../style/theme';
-import { AssetMetaData } from '../types';
+import { AssetMetaData, Network } from '../types';
import { assetUtils } from '../util/asset';
import { getProvider } from '../util/provider';
@@ -17,32 +16,49 @@ import { ZeroExInstantContainer } from './zero_ex_instant_container';
fonts.include();
-export interface ZeroExInstantProps {
+export type ZeroExInstantProps = ZeroExInstantRequiredProps & Partial<ZeroExInstantOptionalProps>;
+
+export interface ZeroExInstantRequiredProps {
// TODO: Change API when we allow the selection of different assetDatas
assetData: string;
- sraApiUrl: string;
+ // TODO: Allow for a function that returns orders
+ liquiditySource: string;
+}
+
+export interface ZeroExInstantOptionalProps {
additionalAssetMetaDataMap: ObjectMap<AssetMetaData>;
+ network: Network;
}
export class ZeroExInstant extends React.Component<ZeroExInstantProps> {
- public static defaultProps = {
- additionalAssetMetaDataMap: {},
- };
public store: Store;
- constructor(props: ZeroExInstantProps) {
- super(props);
+ private static _mergeInitialStateWithProps(props: ZeroExInstantProps, state: State = INITIAL_STATE): State {
+ // Create merged object such that properties in props override default settings
+ const optionalPropsWithDefaults: ZeroExInstantOptionalProps = {
+ additionalAssetMetaDataMap: props.additionalAssetMetaDataMap || {},
+ network: props.network || state.network,
+ };
+ const { network } = optionalPropsWithDefaults;
// TODO: Provider needs to not be hard-coded to injected web3.
- const assetBuyer = AssetBuyer.getAssetBuyerForStandardRelayerAPIUrl(getProvider(), props.sraApiUrl);
+ const assetBuyer = AssetBuyer.getAssetBuyerForStandardRelayerAPIUrl(getProvider(), props.liquiditySource, {
+ networkId: network,
+ });
const completeAssetMetaDataMap = {
...props.additionalAssetMetaDataMap,
- ...assetMetaDataMap,
+ ...state.assetMetaDataMap,
};
- const storeStateFromProps: Partial<State> = {
+ const storeStateFromProps: State = {
+ ...state,
assetBuyer,
- selectedAsset: assetUtils.createAssetFromAssetData(props.assetData, completeAssetMetaDataMap),
+ network,
+ selectedAsset: assetUtils.createAssetFromAssetData(props.assetData, completeAssetMetaDataMap, network),
assetMetaDataMap: completeAssetMetaDataMap,
};
- this.store = store.create(storeStateFromProps);
+ return storeStateFromProps;
+ }
+ constructor(props: ZeroExInstantProps) {
+ super(props);
+ this.store = store.create(ZeroExInstant._mergeInitialStateWithProps(this.props, INITIAL_STATE));
// tslint:disable-next-line:no-floating-promises
asyncData.fetchAndDispatchToStore(this.store);
}
@@ -50,9 +66,9 @@ export class ZeroExInstant extends React.Component<ZeroExInstantProps> {
public render(): React.ReactNode {
return (
<Provider store={this.store}>
- <ThemeProvider theme={theme}>
+ <SelectedAssetThemeProvider>
<ZeroExInstantContainer />
- </ThemeProvider>
+ </SelectedAssetThemeProvider>
</Provider>
);
}
diff --git a/packages/instant/src/containers/latest_buy_quote_order_details.ts b/packages/instant/src/containers/latest_buy_quote_order_details.ts
index 597bf3088..092aaaf20 100644
--- a/packages/instant/src/containers/latest_buy_quote_order_details.ts
+++ b/packages/instant/src/containers/latest_buy_quote_order_details.ts
@@ -8,18 +8,21 @@ import { oc } from 'ts-optchain';
import { State } from '../redux/reducer';
import { OrderDetails } from '../components/order_details';
+import { AsyncProcessState } from '../types';
export interface LatestBuyQuoteOrderDetailsProps {}
interface ConnectedState {
buyQuoteInfo?: BuyQuoteInfo;
ethUsdPrice?: BigNumber;
+ isLoading: boolean;
}
const mapStateToProps = (state: State, _ownProps: LatestBuyQuoteOrderDetailsProps): ConnectedState => ({
// use the worst case quote info
buyQuoteInfo: oc(state).latestBuyQuote.worstCaseQuoteInfo(),
ethUsdPrice: state.ethUsdPrice,
+ isLoading: state.quoteRequestState === AsyncProcessState.PENDING,
});
export const LatestBuyQuoteOrderDetails: React.ComponentClass<LatestBuyQuoteOrderDetailsProps> = connect(
diff --git a/packages/instant/src/containers/latest_error.tsx b/packages/instant/src/containers/latest_error.tsx
index 1d02cab23..b75ec00aa 100644
--- a/packages/instant/src/containers/latest_error.tsx
+++ b/packages/instant/src/containers/latest_error.tsx
@@ -3,8 +3,8 @@ import * as React from 'react';
import { connect } from 'react-redux';
import { SlidingError } from '../components/sliding_error';
-import { LatestErrorDisplay, State } from '../redux/reducer';
-import { Asset } from '../types';
+import { State } from '../redux/reducer';
+import { Asset, DisplayStatus } from '../types';
import { errorUtil } from '../util/error';
export interface LatestErrorComponentProps {
@@ -30,7 +30,7 @@ export interface LatestErrorProps {}
const mapStateToProps = (state: State, _ownProps: LatestErrorProps): ConnectedState => ({
asset: state.selectedAsset,
latestError: state.latestError,
- slidingDirection: state.latestErrorDisplay === LatestErrorDisplay.Present ? 'up' : 'down',
+ slidingDirection: state.latestErrorDisplay === DisplayStatus.Present ? 'up' : 'down',
});
export const LatestError = connect(mapStateToProps)(LatestErrorComponent);
diff --git a/packages/instant/src/containers/selected_asset_amount_input.ts b/packages/instant/src/containers/selected_asset_amount_input.ts
index 6cd39b855..0d847cf02 100644
--- a/packages/instant/src/containers/selected_asset_amount_input.ts
+++ b/packages/instant/src/containers/selected_asset_amount_input.ts
@@ -62,13 +62,13 @@ const updateBuyQuoteAsync = async (
const baseUnitValue = Web3Wrapper.toBaseUnitAmount(assetAmount, asset.metaData.decimals);
// mark quote as pending
- dispatch(actions.updateBuyQuoteStatePending());
+ dispatch(actions.setQuoteRequestStatePending());
let newBuyQuote: BuyQuote | undefined;
try {
newBuyQuote = await assetBuyer.getBuyQuoteAsync(asset.assetData, baseUnitValue);
} catch (error) {
- dispatch(actions.updateBuyQuoteStateFailure());
+ dispatch(actions.setQuoteRequestStateFailure());
errorUtil.errorFlasher.flashNewError(dispatch, error);
return;
}
@@ -90,11 +90,11 @@ const mapDispatchToProps = (
// invalidate the last buy quote.
dispatch(actions.updateLatestBuyQuote(undefined));
// reset our buy state
- dispatch(actions.updatebuyOrderState(AsyncProcessState.NONE));
+ dispatch(actions.updateBuyOrderState(AsyncProcessState.NONE));
if (!_.isUndefined(value) && !_.isUndefined(asset) && !_.isUndefined(assetBuyer)) {
// even if it's debounced, give them the illusion it's loading
- dispatch(actions.updateBuyQuoteStatePending());
+ dispatch(actions.setQuoteRequestStatePending());
// tslint:disable-next-line:no-floating-promises
debouncedUpdateBuyQuoteAsync(assetBuyer, dispatch, asset, value);
}
diff --git a/packages/instant/src/containers/selected_asset_buy_button.ts b/packages/instant/src/containers/selected_asset_buy_button.ts
index 7306ec2ec..208bb2582 100644
--- a/packages/instant/src/containers/selected_asset_buy_button.ts
+++ b/packages/instant/src/containers/selected_asset_buy_button.ts
@@ -18,7 +18,7 @@ interface ConnectedState {
}
interface ConnectedDispatch {
- onBuyClick: (buyQuote: BuyQuote) => void;
+ onClick: (buyQuote: BuyQuote) => void;
onBuySuccess: (buyQuote: BuyQuote) => void;
onBuyFailure: (buyQuote: BuyQuote) => void;
}
@@ -29,9 +29,9 @@ const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyButtonProps):
});
const mapDispatchToProps = (dispatch: Dispatch<Action>, ownProps: SelectedAssetBuyButtonProps): ConnectedDispatch => ({
- onBuyClick: buyQuote => dispatch(actions.updatebuyOrderState(AsyncProcessState.PENDING)),
- onBuySuccess: buyQuote => dispatch(actions.updatebuyOrderState(AsyncProcessState.SUCCESS)),
- onBuyFailure: buyQuote => dispatch(actions.updatebuyOrderState(AsyncProcessState.FAILURE)),
+ onClick: buyQuote => dispatch(actions.updateBuyOrderState(AsyncProcessState.PENDING)),
+ onBuySuccess: buyQuote => dispatch(actions.updateBuyOrderState(AsyncProcessState.SUCCESS)),
+ onBuyFailure: buyQuote => dispatch(actions.updateBuyOrderState(AsyncProcessState.FAILURE)),
});
export const SelectedAssetBuyButton: React.ComponentClass<SelectedAssetBuyButtonProps> = connect(
diff --git a/packages/instant/src/containers/selected_asset_instant_heading.ts b/packages/instant/src/containers/selected_asset_instant_heading.ts
index 743362151..24efed32e 100644
--- a/packages/instant/src/containers/selected_asset_instant_heading.ts
+++ b/packages/instant/src/containers/selected_asset_instant_heading.ts
@@ -15,7 +15,7 @@ interface ConnectedState {
selectedAssetAmount?: BigNumber;
totalEthBaseAmount?: BigNumber;
ethUsdPrice?: BigNumber;
- quoteState: AsyncProcessState;
+ quoteRequestState: AsyncProcessState;
buyOrderState: AsyncProcessState;
}
@@ -23,7 +23,7 @@ const mapStateToProps = (state: State, _ownProps: InstantHeadingProps): Connecte
selectedAssetAmount: state.selectedAssetAmount,
totalEthBaseAmount: oc(state).latestBuyQuote.worstCaseQuoteInfo.totalEthAmount(),
ethUsdPrice: state.ethUsdPrice,
- quoteState: state.quoteState,
+ quoteRequestState: state.quoteRequestState,
buyOrderState: state.buyOrderState,
});
diff --git a/packages/instant/src/containers/selected_asset_theme_provider.ts b/packages/instant/src/containers/selected_asset_theme_provider.ts
new file mode 100644
index 000000000..6e6b83d73
--- /dev/null
+++ b/packages/instant/src/containers/selected_asset_theme_provider.ts
@@ -0,0 +1,32 @@
+import * as _ from 'lodash';
+import * as React from 'react';
+import { connect } from 'react-redux';
+
+import { State } from '../redux/reducer';
+import { Theme, theme as defaultTheme, ThemeProvider } from '../style/theme';
+import { Asset } from '../types';
+
+export interface SelectedAssetThemeProviderProps {}
+
+interface ConnectedState {
+ theme: Theme;
+}
+
+const getTheme = (asset?: Asset): Theme => {
+ if (!_.isUndefined(asset) && !_.isUndefined(asset.metaData.primaryColor)) {
+ return {
+ ...defaultTheme,
+ primaryColor: asset.metaData.primaryColor,
+ };
+ }
+ return defaultTheme;
+};
+
+const mapStateToProps = (state: State, _ownProps: SelectedAssetThemeProviderProps): ConnectedState => {
+ const theme = getTheme(state.selectedAsset);
+ return { theme };
+};
+
+export const SelectedAssetThemeProvider: React.ComponentClass<SelectedAssetThemeProviderProps> = connect(
+ mapStateToProps,
+)(ThemeProvider);
diff --git a/packages/instant/src/redux/actions.ts b/packages/instant/src/redux/actions.ts
index d6388d77e..bdb53a395 100644
--- a/packages/instant/src/redux/actions.ts
+++ b/packages/instant/src/redux/actions.ts
@@ -26,8 +26,8 @@ export enum ActionTypes {
UPDATE_SELECTED_ASSET_BUY_STATE = 'UPDATE_SELECTED_ASSET_BUY_STATE',
UPDATE_LATEST_BUY_QUOTE = 'UPDATE_LATEST_BUY_QUOTE',
UPDATE_SELECTED_ASSET = 'UPDATE_SELECTED_ASSET',
- UPDATE_BUY_QUOTE_STATE_PENDING = 'UPDATE_BUY_QUOTE_STATE_PENDING',
- UPDATE_BUY_QUOTE_STATE_FAILURE = 'UPDATE_BUY_QUOTE_STATE_FAILURE',
+ SET_QUOTE_REQUEST_STATE_PENDING = 'SET_QUOTE_REQUEST_STATE_PENDING',
+ SET_QUOTE_REQUEST_STATE_FAILURE = 'SET_QUOTE_REQUEST_STATE_FAILURE',
SET_ERROR = 'SET_ERROR',
HIDE_ERROR = 'HIDE_ERROR',
CLEAR_ERROR = 'CLEAR_ERROR',
@@ -37,12 +37,12 @@ export enum ActionTypes {
export const actions = {
updateEthUsdPrice: (price?: BigNumber) => createAction(ActionTypes.UPDATE_ETH_USD_PRICE, price),
updateSelectedAssetAmount: (amount?: BigNumber) => createAction(ActionTypes.UPDATE_SELECTED_ASSET_AMOUNT, amount),
- updatebuyOrderState: (buyState: AsyncProcessState) =>
+ updateBuyOrderState: (buyState: AsyncProcessState) =>
createAction(ActionTypes.UPDATE_SELECTED_ASSET_BUY_STATE, buyState),
updateLatestBuyQuote: (buyQuote?: BuyQuote) => createAction(ActionTypes.UPDATE_LATEST_BUY_QUOTE, buyQuote),
updateSelectedAsset: (assetData?: string) => createAction(ActionTypes.UPDATE_SELECTED_ASSET, assetData),
- updateBuyQuoteStatePending: () => createAction(ActionTypes.UPDATE_BUY_QUOTE_STATE_PENDING),
- updateBuyQuoteStateFailure: () => createAction(ActionTypes.UPDATE_BUY_QUOTE_STATE_FAILURE),
+ setQuoteRequestStatePending: () => createAction(ActionTypes.SET_QUOTE_REQUEST_STATE_PENDING),
+ setQuoteRequestStateFailure: () => createAction(ActionTypes.SET_QUOTE_REQUEST_STATE_FAILURE),
setError: (error?: any) => createAction(ActionTypes.SET_ERROR, error),
hideError: () => createAction(ActionTypes.HIDE_ERROR),
clearError: () => createAction(ActionTypes.CLEAR_ERROR),
diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts
index 10e56f152..260039e3d 100644
--- a/packages/instant/src/redux/reducer.ts
+++ b/packages/instant/src/redux/reducer.ts
@@ -3,16 +3,14 @@ import { ObjectMap } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as _ from 'lodash';
-import { Asset, AssetMetaData, AsyncProcessState } from '../types';
+import { assetMetaDataMap } from '../data/asset_meta_data_map';
+import { Asset, AssetMetaData, AsyncProcessState, DisplayStatus, Network } from '../types';
import { assetUtils } from '../util/asset';
import { Action, ActionTypes } from './actions';
-export enum LatestErrorDisplay {
- Present,
- Hidden,
-}
export interface State {
+ network: Network;
assetBuyer?: AssetBuyer;
assetMetaDataMap: ObjectMap<AssetMetaData>;
selectedAsset?: Asset;
@@ -20,23 +18,23 @@ export interface State {
buyOrderState: AsyncProcessState;
ethUsdPrice?: BigNumber;
latestBuyQuote?: BuyQuote;
- quoteState: AsyncProcessState;
+ quoteRequestState: AsyncProcessState;
latestError?: any;
- latestErrorDisplay: LatestErrorDisplay;
+ latestErrorDisplay: DisplayStatus;
}
export const INITIAL_STATE: State = {
+ network: Network.Mainnet,
selectedAssetAmount: undefined,
- assetMetaDataMap: {},
+ assetMetaDataMap,
buyOrderState: AsyncProcessState.NONE,
ethUsdPrice: undefined,
latestBuyQuote: undefined,
latestError: undefined,
- latestErrorDisplay: LatestErrorDisplay.Hidden,
- quoteState: AsyncProcessState.NONE,
+ latestErrorDisplay: DisplayStatus.Hidden,
+ quoteRequestState: AsyncProcessState.NONE,
};
-// TODO: Figure out why there is an INITIAL_STATE key in the store...
export const reducer = (state: State = INITIAL_STATE, action: Action): State => {
switch (action.type) {
case ActionTypes.UPDATE_ETH_USD_PRICE:
@@ -53,19 +51,19 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State =>
return {
...state,
latestBuyQuote: action.data,
- quoteState: AsyncProcessState.SUCCESS,
+ quoteRequestState: AsyncProcessState.SUCCESS,
};
- case ActionTypes.UPDATE_BUY_QUOTE_STATE_PENDING:
+ case ActionTypes.SET_QUOTE_REQUEST_STATE_PENDING:
return {
...state,
latestBuyQuote: undefined,
- quoteState: AsyncProcessState.PENDING,
+ quoteRequestState: AsyncProcessState.PENDING,
};
- case ActionTypes.UPDATE_BUY_QUOTE_STATE_FAILURE:
+ case ActionTypes.SET_QUOTE_REQUEST_STATE_FAILURE:
return {
...state,
latestBuyQuote: undefined,
- quoteState: AsyncProcessState.FAILURE,
+ quoteRequestState: AsyncProcessState.FAILURE,
};
case ActionTypes.UPDATE_SELECTED_ASSET_BUY_STATE:
return {
@@ -76,24 +74,28 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State =>
return {
...state,
latestError: action.data,
- latestErrorDisplay: LatestErrorDisplay.Present,
+ latestErrorDisplay: DisplayStatus.Present,
};
case ActionTypes.HIDE_ERROR:
return {
...state,
- latestErrorDisplay: LatestErrorDisplay.Hidden,
+ latestErrorDisplay: DisplayStatus.Hidden,
};
case ActionTypes.CLEAR_ERROR:
return {
...state,
latestError: undefined,
- latestErrorDisplay: LatestErrorDisplay.Hidden,
+ latestErrorDisplay: DisplayStatus.Hidden,
};
case ActionTypes.UPDATE_SELECTED_ASSET:
const newSelectedAssetData = action.data;
let newSelectedAsset: Asset | undefined;
if (!_.isUndefined(newSelectedAssetData)) {
- newSelectedAsset = assetUtils.createAssetFromAssetData(newSelectedAssetData, state.assetMetaDataMap);
+ newSelectedAsset = assetUtils.createAssetFromAssetData(
+ newSelectedAssetData,
+ state.assetMetaDataMap,
+ state.network,
+ );
}
return {
...state,
@@ -103,7 +105,7 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State =>
return {
...state,
latestBuyQuote: undefined,
- quoteState: AsyncProcessState.NONE,
+ quoteRequestState: AsyncProcessState.NONE,
buyOrderState: AsyncProcessState.NONE,
selectedAssetAmount: undefined,
};
diff --git a/packages/instant/src/redux/store.ts b/packages/instant/src/redux/store.ts
index 505234299..01deb8690 100644
--- a/packages/instant/src/redux/store.ts
+++ b/packages/instant/src/redux/store.ts
@@ -2,17 +2,12 @@ import * as _ from 'lodash';
import { createStore, Store as ReduxStore } from 'redux';
import { devToolsEnhancer } from 'redux-devtools-extension/developmentOnly';
-import { INITIAL_STATE, reducer, State } from './reducer';
+import { reducer, State } from './reducer';
export type Store = ReduxStore<State>;
export const store = {
- create: (withState: Partial<State>): Store => {
- const allInitialState = {
- INITIAL_STATE,
- ...withState,
- };
- return createStore(reducer, allInitialState, devToolsEnhancer({}));
+ create: (state: State): Store => {
+ return createStore(reducer, state, devToolsEnhancer({}));
},
};
-
diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts
index 0454bceea..7323123c3 100644
--- a/packages/instant/src/types.ts
+++ b/packages/instant/src/types.ts
@@ -7,6 +7,10 @@ export enum AsyncProcessState {
SUCCESS = 'Success',
FAILURE = 'Failure',
}
+export enum DisplayStatus {
+ Present,
+ Hidden,
+}
export type FunctionType = (...args: any[]) => any;
export type ActionCreatorsMapObject = ObjectMap<FunctionType>;
diff --git a/packages/instant/src/util/asset.ts b/packages/instant/src/util/asset.ts
index a105a7c2b..4e3b2b946 100644
--- a/packages/instant/src/util/asset.ts
+++ b/packages/instant/src/util/asset.ts
@@ -1,4 +1,3 @@
-import { assetDataUtils } from '@0x/order-utils';
import { AssetProxyId, ObjectMap } from '@0x/types';
import * as _ from 'lodash';
@@ -6,17 +5,17 @@ import { assetDataNetworkMapping } from '../data/asset_data_network_mapping';
import { Asset, AssetMetaData, Network, ZeroExInstantError } from '../types';
export const assetUtils = {
- createAssetFromAssetData: (assetData: string, assetMetaDataMap: ObjectMap<AssetMetaData>): Asset => {
+ createAssetFromAssetData: (
+ assetData: string,
+ assetMetaDataMap: ObjectMap<AssetMetaData>,
+ network: Network,
+ ): Asset => {
return {
assetData,
- metaData: assetUtils.getMetaDataOrThrow(assetData, assetMetaDataMap),
+ metaData: assetUtils.getMetaDataOrThrow(assetData, assetMetaDataMap, network),
};
},
- getMetaDataOrThrow: (
- assetData: string,
- metaDataMap: ObjectMap<AssetMetaData>,
- network: Network = Network.Mainnet,
- ): AssetMetaData => {
+ getMetaDataOrThrow: (assetData: string, metaDataMap: ObjectMap<AssetMetaData>, network: Network): AssetMetaData => {
let mainnetAssetData: string | undefined = assetData;
if (network !== Network.Mainnet) {
mainnetAssetData = assetUtils.getAssociatedAssetDataIfExists(assetData, network);
@@ -39,7 +38,7 @@ export const assetUtils = {
case AssetProxyId.ERC20:
return metaData.symbol.toUpperCase();
case AssetProxyId.ERC721:
- return metaData.name.toUpperCase();
+ return metaData.name;
default:
return defaultName;
}
diff --git a/packages/instant/tslint.json b/packages/instant/tslint.json
index abe874a6d..08b76be97 100644
--- a/packages/instant/tslint.json
+++ b/packages/instant/tslint.json
@@ -2,6 +2,7 @@
"extends": ["@0x/tslint-config"],
"rules": {
"custom-no-magic-numbers": false,
- "semicolon": [true, "always", "ignore-bound-class-methods"]
+ "semicolon": [true, "always", "ignore-bound-class-methods"],
+ "max-classes-per-file": false
}
}