aboutsummaryrefslogtreecommitdiffstats
path: root/packages/instant/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/instant/src')
-rw-r--r--packages/instant/src/components/buy_button.tsx4
-rw-r--r--packages/instant/src/components/instant_heading.tsx29
-rw-r--r--packages/instant/src/components/view_transaction_button.tsx11
-rw-r--r--packages/instant/src/containers/selected_asset_amount_input.ts2
-rw-r--r--packages/instant/src/containers/selected_asset_button.tsx15
-rw-r--r--packages/instant/src/containers/selected_asset_buy_button.ts9
-rw-r--r--packages/instant/src/containers/selected_asset_instant_heading.ts4
-rw-r--r--packages/instant/src/containers/selected_asset_view_transaction_button.tsx35
-rw-r--r--packages/instant/src/redux/actions.ts7
-rw-r--r--packages/instant/src/redux/reducer.ts10
-rw-r--r--packages/instant/src/types.ts14
11 files changed, 106 insertions, 34 deletions
diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx
index 2def34fd7..1afd216d8 100644
--- a/packages/instant/src/components/buy_button.tsx
+++ b/packages/instant/src/components/buy_button.tsx
@@ -41,8 +41,8 @@ export class BuyButton extends React.Component<BuyButtonProps> {
let txnHash;
try {
txnHash = await this.props.assetBuyer.executeBuyQuoteAsync(this.props.buyQuote);
- await web3Wrapper.awaitTransactionSuccessAsync(txnHash);
- this.props.onBuySuccess(this.props.buyQuote, txnHash);
+ const txnReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txnHash);
+ this.props.onBuySuccess(this.props.buyQuote, txnReceipt.transactionHash);
} catch {
this.props.onBuyFailure(this.props.buyQuote, txnHash);
}
diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx
index 856e4d43e..ed753a3bd 100644
--- a/packages/instant/src/components/instant_heading.tsx
+++ b/packages/instant/src/components/instant_heading.tsx
@@ -4,7 +4,7 @@ import * as React from 'react';
import { SelectedAssetAmountInput } from '../containers/selected_asset_amount_input';
import { ColorOption } from '../style/theme';
-import { AsyncProcessState } from '../types';
+import { AsyncProcessState, OrderState } from '../types';
import { format } from '../util/format';
import { AmountPlaceholder } from './amount_placeholder';
@@ -16,10 +16,14 @@ export interface InstantHeadingProps {
totalEthBaseAmount?: BigNumber;
ethUsdPrice?: BigNumber;
quoteRequestState: AsyncProcessState;
- buyOrderState: AsyncProcessState;
+ buyOrderState: OrderState;
}
-const placeholderColor = ColorOption.white;
+const PLACEHOLDER_COLOR = ColorOption.white;
+const ICON_WIDTH = 34;
+const ICON_HEIGHT = 34;
+const ICON_COLOR = ColorOption.white;
+
export class InstantHeading extends React.Component<InstantHeadingProps, {}> {
public render(): React.ReactNode {
const iconOrAmounts = this._renderIcon() || this._renderAmountsSection();
@@ -62,15 +66,22 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> {
}
private _renderIcon(): React.ReactNode {
- if (this.props.buyOrderState === AsyncProcessState.FAILURE) {
- return <Icon icon={'failed'} width={34} height={34} color={ColorOption.white} />;
+ const processState = this.props.buyOrderState.processState;
+
+ if (processState === AsyncProcessState.FAILURE) {
+ return <Icon icon={'failed'} width={ICON_WIDTH} height={ICON_HEIGHT} color={ICON_COLOR} />;
+ } else if (processState === AsyncProcessState.SUCCESS) {
+ return <Icon icon={'success'} width={ICON_WIDTH} height={ICON_HEIGHT} color={ICON_COLOR} />;
}
return undefined;
}
private _renderTopText(): React.ReactNode {
- if (this.props.buyOrderState === AsyncProcessState.FAILURE) {
+ const processState = this.props.buyOrderState.processState;
+ if (processState === AsyncProcessState.FAILURE) {
return 'Order failed';
+ } else if (processState === AsyncProcessState.SUCCESS) {
+ return 'Tokens received!';
}
return 'I want to buy';
@@ -78,10 +89,10 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> {
private _placeholderOrAmount(amountFunction: () => React.ReactNode): React.ReactNode {
if (this.props.quoteRequestState === AsyncProcessState.PENDING) {
- return <AmountPlaceholder isPulsating={true} color={placeholderColor} />;
+ return <AmountPlaceholder isPulsating={true} color={PLACEHOLDER_COLOR} />;
}
if (_.isUndefined(this.props.selectedAssetAmount)) {
- return <AmountPlaceholder isPulsating={false} color={placeholderColor} />;
+ return <AmountPlaceholder isPulsating={false} color={PLACEHOLDER_COLOR} />;
}
return amountFunction();
}
@@ -92,7 +103,7 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> {
{format.ethBaseAmount(
this.props.totalEthBaseAmount,
4,
- <AmountPlaceholder isPulsating={false} color={placeholderColor} />,
+ <AmountPlaceholder isPulsating={false} color={PLACEHOLDER_COLOR} />,
)}
</Text>
);
diff --git a/packages/instant/src/components/view_transaction_button.tsx b/packages/instant/src/components/view_transaction_button.tsx
new file mode 100644
index 000000000..7aa44e657
--- /dev/null
+++ b/packages/instant/src/components/view_transaction_button.tsx
@@ -0,0 +1,11 @@
+import * as React from 'react';
+
+import { SecondaryButton } from './secondary_button';
+
+export interface ViewTransactionButtonProps {
+ onClick: () => void;
+}
+
+export const ViewTransactionButton: React.StatelessComponent<ViewTransactionButtonProps> = props => {
+ return <SecondaryButton onClick={props.onClick}>View Transaction</SecondaryButton>;
+};
diff --git a/packages/instant/src/containers/selected_asset_amount_input.ts b/packages/instant/src/containers/selected_asset_amount_input.ts
index 0d847cf02..f23b2010e 100644
--- a/packages/instant/src/containers/selected_asset_amount_input.ts
+++ b/packages/instant/src/containers/selected_asset_amount_input.ts
@@ -90,7 +90,7 @@ const mapDispatchToProps = (
// invalidate the last buy quote.
dispatch(actions.updateLatestBuyQuote(undefined));
// reset our buy state
- dispatch(actions.updateBuyOrderState(AsyncProcessState.NONE));
+ dispatch(actions.updateBuyOrderState({ processState: AsyncProcessState.NONE }));
if (!_.isUndefined(value) && !_.isUndefined(asset) && !_.isUndefined(assetBuyer)) {
// even if it's debounced, give them the illusion it's loading
diff --git a/packages/instant/src/containers/selected_asset_button.tsx b/packages/instant/src/containers/selected_asset_button.tsx
index 6fad365fa..d368d05e1 100644
--- a/packages/instant/src/containers/selected_asset_button.tsx
+++ b/packages/instant/src/containers/selected_asset_button.tsx
@@ -4,15 +4,16 @@ import { connect } from 'react-redux';
import { SecondaryButton } from '../components/secondary_button';
import { State } from '../redux/reducer';
-import { AsyncProcessState } from '../types';
+import { AsyncProcessState, OrderState } from '../types';
import { PlacingOrderButton } from '../components/placing_order_button';
import { SelectedAssetBuyButton } from './selected_asset_buy_button';
import { SelectedAssetRetryButton } from './selected_asset_retry_button';
+import { SelectedAssetViewTransactionButton } from './selected_asset_view_transaction_button';
interface ConnectedState {
- buyOrderState: AsyncProcessState;
+ buyOrderState: OrderState;
}
export interface SelectedAssetButtonProps {}
const mapStateToProps = (state: State, _ownProps: SelectedAssetButtonProps): ConnectedState => ({
@@ -20,13 +21,13 @@ const mapStateToProps = (state: State, _ownProps: SelectedAssetButtonProps): Con
});
const SelectedAssetButtonPresentationComponent: React.StatelessComponent<{
- buyOrderState: AsyncProcessState;
+ buyOrderState: OrderState;
}> = props => {
- if (props.buyOrderState === AsyncProcessState.FAILURE) {
+ if (props.buyOrderState.processState === AsyncProcessState.FAILURE) {
return <SelectedAssetRetryButton />;
- } else if (props.buyOrderState === AsyncProcessState.SUCCESS) {
- return <SecondaryButton isDisabled={true}>Success</SecondaryButton>;
- } else if (props.buyOrderState === AsyncProcessState.PENDING) {
+ } else if (props.buyOrderState.processState === AsyncProcessState.SUCCESS) {
+ return <SelectedAssetViewTransactionButton />;
+ } else if (props.buyOrderState.processState === AsyncProcessState.PENDING) {
return <PlacingOrderButton />;
}
diff --git a/packages/instant/src/containers/selected_asset_buy_button.ts b/packages/instant/src/containers/selected_asset_buy_button.ts
index 208bb2582..71d2b8cf0 100644
--- a/packages/instant/src/containers/selected_asset_buy_button.ts
+++ b/packages/instant/src/containers/selected_asset_buy_button.ts
@@ -19,7 +19,7 @@ interface ConnectedState {
interface ConnectedDispatch {
onClick: (buyQuote: BuyQuote) => void;
- onBuySuccess: (buyQuote: BuyQuote) => void;
+ onBuySuccess: (buyQuote: BuyQuote, txnHash: string) => void;
onBuyFailure: (buyQuote: BuyQuote) => void;
}
@@ -29,9 +29,10 @@ const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyButtonProps):
});
const mapDispatchToProps = (dispatch: Dispatch<Action>, ownProps: SelectedAssetBuyButtonProps): ConnectedDispatch => ({
- onClick: 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({ processState: AsyncProcessState.PENDING })),
+ onBuySuccess: (buyQuote: BuyQuote, txnHash: string) =>
+ dispatch(actions.updateBuyOrderState({ processState: AsyncProcessState.SUCCESS, txnHash })),
+ onBuyFailure: buyQuote => dispatch(actions.updateBuyOrderState({ processState: 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 24efed32e..6b2a29b07 100644
--- a/packages/instant/src/containers/selected_asset_instant_heading.ts
+++ b/packages/instant/src/containers/selected_asset_instant_heading.ts
@@ -5,7 +5,7 @@ import { connect } from 'react-redux';
import { oc } from 'ts-optchain';
import { State } from '../redux/reducer';
-import { AsyncProcessState } from '../types';
+import { AsyncProcessState, OrderState } from '../types';
import { InstantHeading } from '../components/instant_heading';
@@ -16,7 +16,7 @@ interface ConnectedState {
totalEthBaseAmount?: BigNumber;
ethUsdPrice?: BigNumber;
quoteRequestState: AsyncProcessState;
- buyOrderState: AsyncProcessState;
+ buyOrderState: OrderState;
}
const mapStateToProps = (state: State, _ownProps: InstantHeadingProps): ConnectedState => ({
diff --git a/packages/instant/src/containers/selected_asset_view_transaction_button.tsx b/packages/instant/src/containers/selected_asset_view_transaction_button.tsx
new file mode 100644
index 000000000..44de16c4a
--- /dev/null
+++ b/packages/instant/src/containers/selected_asset_view_transaction_button.tsx
@@ -0,0 +1,35 @@
+import { EtherscanLinkSuffixes, utils } from '@0x/react-shared';
+import * as _ from 'lodash';
+import * as React from 'react';
+import { connect } from 'react-redux';
+
+import { State } from '../redux/reducer';
+
+import { ViewTransactionButton } from '../components/view_transaction_button';
+import { AsyncProcessState } from '../types';
+
+export interface SelectedAssetViewTransactionButtonProps {}
+
+interface ConnectedState {
+ onClick: () => void;
+}
+
+const mapStateToProps = (state: State, _ownProps: {}): ConnectedState => ({
+ onClick: () => {
+ if (state.assetBuyer && state.buyOrderState.processState === AsyncProcessState.SUCCESS) {
+ const etherscanUrl = utils.getEtherScanLinkIfExists(
+ state.buyOrderState.txnHash,
+ state.assetBuyer.networkId,
+ EtherscanLinkSuffixes.Tx,
+ );
+ if (etherscanUrl) {
+ window.open(etherscanUrl, '_blank');
+ return;
+ }
+ }
+ },
+});
+
+export const SelectedAssetViewTransactionButton: React.ComponentClass<
+ SelectedAssetViewTransactionButtonProps
+> = connect(mapStateToProps)(ViewTransactionButton);
diff --git a/packages/instant/src/redux/actions.ts b/packages/instant/src/redux/actions.ts
index bdb53a395..1360634d7 100644
--- a/packages/instant/src/redux/actions.ts
+++ b/packages/instant/src/redux/actions.ts
@@ -2,7 +2,7 @@ import { BuyQuote } from '@0x/asset-buyer';
import { BigNumber } from '@0x/utils';
import * as _ from 'lodash';
-import { ActionsUnion, AsyncProcessState } from '../types';
+import { ActionsUnion, AsyncProcessState, OrderState } from '../types';
export interface PlainAction<T extends string> {
type: T;
@@ -23,7 +23,7 @@ function createAction<T extends string, P>(type: T, data?: P): PlainAction<T> |
export enum ActionTypes {
UPDATE_ETH_USD_PRICE = 'UPDATE_ETH_USD_PRICE',
UPDATE_SELECTED_ASSET_AMOUNT = 'UPDATE_SELECTED_ASSET_AMOUNT',
- UPDATE_SELECTED_ASSET_BUY_STATE = 'UPDATE_SELECTED_ASSET_BUY_STATE',
+ UPDATE_BUY_ORDER_STATE = 'UPDATE_BUY_ORDER_STATE',
UPDATE_LATEST_BUY_QUOTE = 'UPDATE_LATEST_BUY_QUOTE',
UPDATE_SELECTED_ASSET = 'UPDATE_SELECTED_ASSET',
SET_QUOTE_REQUEST_STATE_PENDING = 'SET_QUOTE_REQUEST_STATE_PENDING',
@@ -37,8 +37,7 @@ 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) =>
- createAction(ActionTypes.UPDATE_SELECTED_ASSET_BUY_STATE, buyState),
+ updateBuyOrderState: (orderState: OrderState) => createAction(ActionTypes.UPDATE_BUY_ORDER_STATE, orderState),
updateLatestBuyQuote: (buyQuote?: BuyQuote) => createAction(ActionTypes.UPDATE_LATEST_BUY_QUOTE, buyQuote),
updateSelectedAsset: (assetData?: string) => createAction(ActionTypes.UPDATE_SELECTED_ASSET, assetData),
setQuoteRequestStatePending: () => createAction(ActionTypes.SET_QUOTE_REQUEST_STATE_PENDING),
diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts
index 260039e3d..1aedcbcc4 100644
--- a/packages/instant/src/redux/reducer.ts
+++ b/packages/instant/src/redux/reducer.ts
@@ -4,7 +4,7 @@ import { BigNumber } from '@0x/utils';
import * as _ from 'lodash';
import { assetMetaDataMap } from '../data/asset_meta_data_map';
-import { Asset, AssetMetaData, AsyncProcessState, DisplayStatus, Network } from '../types';
+import { Asset, AssetMetaData, AsyncProcessState, DisplayStatus, Network, OrderState } from '../types';
import { assetUtils } from '../util/asset';
import { Action, ActionTypes } from './actions';
@@ -15,7 +15,7 @@ export interface State {
assetMetaDataMap: ObjectMap<AssetMetaData>;
selectedAsset?: Asset;
selectedAssetAmount?: BigNumber;
- buyOrderState: AsyncProcessState;
+ buyOrderState: OrderState;
ethUsdPrice?: BigNumber;
latestBuyQuote?: BuyQuote;
quoteRequestState: AsyncProcessState;
@@ -27,7 +27,7 @@ export const INITIAL_STATE: State = {
network: Network.Mainnet,
selectedAssetAmount: undefined,
assetMetaDataMap,
- buyOrderState: AsyncProcessState.NONE,
+ buyOrderState: { processState: AsyncProcessState.NONE },
ethUsdPrice: undefined,
latestBuyQuote: undefined,
latestError: undefined,
@@ -65,7 +65,7 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State =>
latestBuyQuote: undefined,
quoteRequestState: AsyncProcessState.FAILURE,
};
- case ActionTypes.UPDATE_SELECTED_ASSET_BUY_STATE:
+ case ActionTypes.UPDATE_BUY_ORDER_STATE:
return {
...state,
buyOrderState: action.data,
@@ -106,7 +106,7 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State =>
...state,
latestBuyQuote: undefined,
quoteRequestState: AsyncProcessState.NONE,
- buyOrderState: AsyncProcessState.NONE,
+ buyOrderState: { processState: AsyncProcessState.NONE },
selectedAssetAmount: undefined,
};
default:
diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts
index 7323123c3..b7b16f4d7 100644
--- a/packages/instant/src/types.ts
+++ b/packages/instant/src/types.ts
@@ -7,6 +7,20 @@ export enum AsyncProcessState {
SUCCESS = 'Success',
FAILURE = 'Failure',
}
+
+interface RegularOrderState {
+ processState: AsyncProcessState.NONE | AsyncProcessState.PENDING;
+}
+interface SuccessfulOrderState {
+ processState: AsyncProcessState.SUCCESS;
+ txnHash: string;
+}
+interface FailureOrderState {
+ processState: AsyncProcessState.FAILURE;
+ txnHash?: string;
+}
+export type OrderState = RegularOrderState | SuccessfulOrderState | FailureOrderState;
+
export enum DisplayStatus {
Present,
Hidden,