From f9eba65aee8e71de609801e640de4101af9645e6 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 29 Oct 2018 20:06:31 -0700 Subject: return estimated state --- packages/instant/src/components/buy_button.tsx | 4 ++-- packages/instant/src/components/zero_ex_instant.tsx | 2 +- packages/instant/src/types.ts | 1 + packages/instant/src/util/gas_price_estimator.ts | 19 +++++++++++++------ 4 files changed, 17 insertions(+), 9 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index 93bd8e635..36cc32dbc 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -57,9 +57,9 @@ export class BuyButton extends React.Component { } let txHash: string | undefined; - const gasPrice = await gasPriceEstimator.getFastAmountInWeiAsync(); + const gasInfo = await gasPriceEstimator.getGasInfoAsync(); try { - txHash = await assetBuyer.executeBuyQuoteAsync(buyQuote, { takerAddress, gasPrice }); + txHash = await assetBuyer.executeBuyQuoteAsync(buyQuote, { takerAddress, gasPrice: gasInfo.gasPriceInWei }); } catch (e) { if (e instanceof Error) { if (e.message === AssetBuyerError.SignatureRequestDenied) { diff --git a/packages/instant/src/components/zero_ex_instant.tsx b/packages/instant/src/components/zero_ex_instant.tsx index d54dfc153..365c1610f 100644 --- a/packages/instant/src/components/zero_ex_instant.tsx +++ b/packages/instant/src/components/zero_ex_instant.tsx @@ -83,7 +83,7 @@ export class ZeroExInstant extends React.Component { // warm up the gas price estimator cache just in case we can't // grab the gas price estimate when submitting the transaction // tslint:disable-next-line:no-floating-promises - gasPriceEstimator.getFastAmountInWeiAsync(); + gasPriceEstimator.getGasInfoAsync(); // tslint:disable-next-line:no-floating-promises this._flashErrorIfWrongNetwork(); diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts index 336465e43..4631c9cae 100644 --- a/packages/instant/src/types.ts +++ b/packages/instant/src/types.ts @@ -22,6 +22,7 @@ interface OrderStatePreTx { interface OrderStatePostTx { processState: OrderProcessState.PROCESSING | OrderProcessState.SUCCESS | OrderProcessState.FAILURE; txHash: string; + estimatedTimeMs?: number; } export type OrderState = OrderStatePreTx | OrderStatePostTx; diff --git a/packages/instant/src/util/gas_price_estimator.ts b/packages/instant/src/util/gas_price_estimator.ts index 336c4a3fa..0552ccde1 100644 --- a/packages/instant/src/util/gas_price_estimator.ts +++ b/packages/instant/src/util/gas_price_estimator.ts @@ -16,18 +16,25 @@ interface EthGasStationResult { safeLow: number; } -const fetchFastAmountInWeiAsync = async () => { +interface GasInfo { + gasPriceInWei: BigNumber; + estimatedTimeMs?: number; +} + +const fetchFastAmountInWeiAsync = async (): Promise => { const res = await fetchAsync(`${ETH_GAS_STATION_API_BASE_URL}/json/ethgasAPI.json`); const gasInfo = (await res.json()) as EthGasStationResult; // Eth Gas Station result is gwei * 10 const gasPriceInGwei = new BigNumber(gasInfo.fast / 10); - return gasPriceInGwei.mul(GWEI_IN_WEI); + // Time is in minutes + const estimatedTimeMs = gasInfo.fastWait * 60 * 1000; // Minutes to MS + return { gasPriceInWei: gasPriceInGwei.mul(GWEI_IN_WEI), estimatedTimeMs }; }; export class GasPriceEstimator { - private _lastFetched?: BigNumber; - public async getFastAmountInWeiAsync(): Promise { - let fetchedAmount: BigNumber | undefined; + private _lastFetched?: GasInfo; + public async getGasInfoAsync(): Promise { + let fetchedAmount: GasInfo | undefined; try { fetchedAmount = await fetchFastAmountInWeiAsync(); } catch { @@ -38,7 +45,7 @@ export class GasPriceEstimator { this._lastFetched = fetchedAmount; } - return fetchedAmount || this._lastFetched || DEFAULT_GAS_PRICE; + return fetchedAmount || this._lastFetched || { gasPriceInWei: DEFAULT_GAS_PRICE, estimatedTimeMs: undefined }; } } export const gasPriceEstimator = new GasPriceEstimator(); -- cgit v1.2.3 From 728f70f51b2fe4c5037e7b74a5dfb29f1f8ca4c9 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 29 Oct 2018 20:08:46 -0700 Subject: store estimated time in Ms on state --- packages/instant/src/components/buy_button.tsx | 4 ++-- .../src/containers/selected_asset_buy_order_state_buttons.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index 36cc32dbc..ec1010fe9 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -19,7 +19,7 @@ export interface BuyButtonProps { onValidationPending: (buyQuote: BuyQuote) => void; onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void; onSignatureDenied: (buyQuote: BuyQuote) => void; - onBuyProcessing: (buyQuote: BuyQuote, txHash: string) => void; + onBuyProcessing: (buyQuote: BuyQuote, txHash: string, estimatedTimeMs?: number) => void; onBuySuccess: (buyQuote: BuyQuote, txHash: string) => void; onBuyFailure: (buyQuote: BuyQuote, txHash: string) => void; } @@ -73,7 +73,7 @@ export class BuyButton extends React.Component { throw e; } - this.props.onBuyProcessing(buyQuote, txHash); + this.props.onBuyProcessing(buyQuote, txHash, gasInfo.estimatedTimeMs); try { await web3Wrapper.awaitTransactionSuccessAsync(txHash); } catch (e) { diff --git a/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts index 500d6b88a..3750e5219 100644 --- a/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts +++ b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts @@ -21,7 +21,7 @@ interface ConnectedState { interface ConnectedDispatch { onValidationPending: (buyQuote: BuyQuote) => void; onSignatureDenied: (buyQuote: BuyQuote) => void; - onBuyProcessing: (buyQuote: BuyQuote, txHash: string) => void; + onBuyProcessing: (buyQuote: BuyQuote, txHash: string, estimatedTimeMs?: number) => void; onBuySuccess: (buyQuote: BuyQuote, txHash: string) => void; onBuyFailure: (buyQuote: BuyQuote, txHash: string) => void; onRetry: () => void; @@ -59,8 +59,8 @@ const mapDispatchToProps = ( const newOrderState: OrderState = { processState: OrderProcessState.VALIDATING }; dispatch(actions.updateBuyOrderState(newOrderState)); }, - onBuyProcessing: (buyQuote: BuyQuote, txHash: string) => { - const newOrderState: OrderState = { processState: OrderProcessState.PROCESSING, txHash }; + onBuyProcessing: (buyQuote: BuyQuote, txHash: string, estimatedTimeMs?: number) => { + const newOrderState: OrderState = { processState: OrderProcessState.PROCESSING, txHash, estimatedTimeMs }; dispatch(actions.updateBuyOrderState(newOrderState)); }, onBuySuccess: (buyQuote: BuyQuote, txHash: string) => -- cgit v1.2.3 From 25039a036c13336eba82904ecb53f6517286c0b5 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 30 Oct 2018 10:18:00 -0700 Subject: WIP: Progress ticker with finishing --- packages/instant/src/constants.ts | 1 + packages/instant/src/util/progress.ts | 89 +++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 packages/instant/src/util/progress.ts (limited to 'packages') diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index 424f35ecb..a21de2a0f 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -7,3 +7,4 @@ export const GWEI_IN_WEI = new BigNumber(1000000000); export const DEFAULT_GAS_PRICE = GWEI_IN_WEI.mul(6); export const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info'; export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2'; +export const PROGRESS_TICK_INTERVAL_MS = 100; diff --git a/packages/instant/src/util/progress.ts b/packages/instant/src/util/progress.ts new file mode 100644 index 000000000..33b1cc313 --- /dev/null +++ b/packages/instant/src/util/progress.ts @@ -0,0 +1,89 @@ +import { Dispatch } from 'redux'; + +import { PROGRESS_TICK_INTERVAL_MS } from '../constants'; +import { Action, actions } from '../redux/actions'; + +const curTimeUnix = () => { + return new Date().getTime(); +}; + +enum TickingState { + Ticking, + Finishing, +} +interface TickingNormalState { + state: TickingState.Ticking; +} +interface TickingFinishingState { + state: TickingState.Finishing; + increasePercentageEveryTick: number; +} +type TickingStatus = TickingNormalState | TickingFinishingState; + +const TICKS_PER_SECOND = 1000 / PROGRESS_TICK_INTERVAL_MS; +export class Progress { + private _startTimeUnix: number; + private _expectedTimeMs: number; + private _intervalId: number; + private _percentageDone: number; + private _tickingStatus: TickingStatus; + + // TODO: take in dispatch + constructor(expectedTimeMs: number) { + const curTime = curTimeUnix(); + this._startTimeUnix = curTime; + this._expectedTimeMs = expectedTimeMs; + this._percentageDone = 0; + this._intervalId = window.setInterval(this._tick.bind(this), PROGRESS_TICK_INTERVAL_MS); // TODO: is bind necessary? + this._tickingStatus = { state: TickingState.Ticking }; + // TODO: clear interval + } + + public setFinishing(): void { + const percentLeft = 100 - this._percentageDone; + console.log('percentLeft', percentLeft); + const increasePercentageEveryTick = percentLeft / TICKS_PER_SECOND; + console.log('increase Tick', increasePercentageEveryTick); + this._tickingStatus = { + state: TickingState.Finishing, + increasePercentageEveryTick, + }; + } + + private _tick(): void { + const percentageDone = + this._tickingStatus.state === TickingState.Finishing + ? this._tickFinishing(this._tickingStatus) + : this._tickNormal(); + + // TODO: max 100 + + this._percentageDone = percentageDone; + console.log('percentageDone', this._percentageDone); + // TODO: max 95 + if (percentageDone >= 100) { + this._clearInterval(); + } + return; + } + + // TODO: take param and move out + private _tickNormal(): number { + const elapsedTimeMs = curTimeUnix() - this._startTimeUnix; + // TODO: zero and negative check, use mins and maxs everywhere + const percentageDone = elapsedTimeMs / this._expectedTimeMs * 100; + return percentageDone; + } + + private _tickFinishing(finishingState: TickingFinishingState): number { + return this._percentageDone + finishingState.increasePercentageEveryTick; + } + + private _clearInterval(): void { + return window.clearInterval(this._intervalId); + } + + // reset function + + // end function +} -- cgit v1.2.3 From 37405038e8f377b65f4dc32b09932fb9ba38efc5 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 30 Oct 2018 10:56:11 -0700 Subject: Stall at 95 percent --- packages/instant/src/constants.ts | 1 + packages/instant/src/util/progress.ts | 72 ++++++++++++++++++++++------------- 2 files changed, 46 insertions(+), 27 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index a21de2a0f..e099044df 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -8,3 +8,4 @@ export const DEFAULT_GAS_PRICE = GWEI_IN_WEI.mul(6); export const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info'; export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2'; export const PROGRESS_TICK_INTERVAL_MS = 100; +export const PROGRESS_STALL_AT_PERCENTAGE = 95; diff --git a/packages/instant/src/util/progress.ts b/packages/instant/src/util/progress.ts index 33b1cc313..5649a78c8 100644 --- a/packages/instant/src/util/progress.ts +++ b/packages/instant/src/util/progress.ts @@ -1,6 +1,7 @@ +import * as _ from 'lodash'; import { Dispatch } from 'redux'; -import { PROGRESS_TICK_INTERVAL_MS } from '../constants'; +import { PROGRESS_STALL_AT_PERCENTAGE, PROGRESS_TICK_INTERVAL_MS } from '../constants'; import { Action, actions } from '../redux/actions'; const curTimeUnix = () => { @@ -8,42 +9,51 @@ const curTimeUnix = () => { }; enum TickingState { - Ticking, + None, + Running, Finishing, } -interface TickingNormalState { - state: TickingState.Ticking; +interface TickingNoneState { + state: TickingState.None; } -interface TickingFinishingState { +interface TickingRunningStatus { + state: TickingState.Running; +} +interface TickingFinishingStatus { state: TickingState.Finishing; increasePercentageEveryTick: number; } -type TickingStatus = TickingNormalState | TickingFinishingState; +type TickingStatus = TickingNoneState | TickingRunningStatus | TickingFinishingStatus; const TICKS_PER_SECOND = 1000 / PROGRESS_TICK_INTERVAL_MS; export class Progress { - private _startTimeUnix: number; - private _expectedTimeMs: number; - private _intervalId: number; + private _startTimeUnix?: number; + private _expectedTimeMs?: number; + private _intervalId?: number; private _percentageDone: number; private _tickingStatus: TickingStatus; - // TODO: take in dispatch - constructor(expectedTimeMs: number) { - const curTime = curTimeUnix(); - this._startTimeUnix = curTime; - this._expectedTimeMs = expectedTimeMs; + constructor() { + this._startTimeUnix = undefined; + this._expectedTimeMs = undefined; this._percentageDone = 0; - this._intervalId = window.setInterval(this._tick.bind(this), PROGRESS_TICK_INTERVAL_MS); // TODO: is bind necessary? - this._tickingStatus = { state: TickingState.Ticking }; + this._intervalId = undefined; + this._tickingStatus = { state: TickingState.None }; // TODO: clear interval } + public beginRunning(expectedTimeMs: number): void { + this._clearTimer(); + this._startTimeUnix = curTimeUnix(); + this._expectedTimeMs = expectedTimeMs; + this._percentageDone = 0; + this._intervalId = window.setInterval(this._tick.bind(this), PROGRESS_TICK_INTERVAL_MS); + this._tickingStatus = { state: TickingState.Running }; + } + public setFinishing(): void { const percentLeft = 100 - this._percentageDone; - console.log('percentLeft', percentLeft); const increasePercentageEveryTick = percentLeft / TICKS_PER_SECOND; - console.log('increase Tick', increasePercentageEveryTick); this._tickingStatus = { state: TickingState.Finishing, increasePercentageEveryTick, @@ -51,31 +61,39 @@ export class Progress { } private _tick(): void { - const percentageDone = + const rawPercentageDone = this._tickingStatus.state === TickingState.Finishing ? this._tickFinishing(this._tickingStatus) : this._tickNormal(); - // TODO: max 100 - + const maxPercentage = this._tickingStatus.state === TickingState.Finishing ? 100 : PROGRESS_STALL_AT_PERCENTAGE; + const percentageDone = Math.min(rawPercentageDone, maxPercentage); this._percentageDone = percentageDone; console.log('percentageDone', this._percentageDone); - // TODO: max 95 if (percentageDone >= 100) { - this._clearInterval(); + this._clearTimer(); } return; } - // TODO: take param and move out + private _clearTimer(): void { + if (this._intervalId) { + window.clearTimeout(this._intervalId); + } + } + private _tickNormal(): number { + if (_.isUndefined(this._startTimeUnix) || _.isUndefined(this._expectedTimeMs)) { + throw new Error('Cant tick, missing var'); + } + const elapsedTimeMs = curTimeUnix() - this._startTimeUnix; - // TODO: zero and negative check, use mins and maxs everywhere - const percentageDone = elapsedTimeMs / this._expectedTimeMs * 100; + const safeElapsedTimeMs = Math.max(elapsedTimeMs, 1); + const percentageDone = safeElapsedTimeMs / this._expectedTimeMs * 100; return percentageDone; } - private _tickFinishing(finishingState: TickingFinishingState): number { + private _tickFinishing(finishingState: TickingFinishingStatus): number { return this._percentageDone + finishingState.increasePercentageEveryTick; } -- cgit v1.2.3 From 9a0595a607af2d5d33ea68dae01dce1f85d13680 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 30 Oct 2018 10:58:39 -0700 Subject: Rename functions and get rid of old unused function --- packages/instant/src/util/progress.ts | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/util/progress.ts b/packages/instant/src/util/progress.ts index 5649a78c8..3c328f2f1 100644 --- a/packages/instant/src/util/progress.ts +++ b/packages/instant/src/util/progress.ts @@ -63,8 +63,8 @@ export class Progress { private _tick(): void { const rawPercentageDone = this._tickingStatus.state === TickingState.Finishing - ? this._tickFinishing(this._tickingStatus) - : this._tickNormal(); + ? this._getNewPercentageFinishing(this._tickingStatus) + : this._getNewPercentageNormal(); const maxPercentage = this._tickingStatus.state === TickingState.Finishing ? 100 : PROGRESS_STALL_AT_PERCENTAGE; const percentageDone = Math.min(rawPercentageDone, maxPercentage); @@ -82,7 +82,7 @@ export class Progress { } } - private _tickNormal(): number { + private _getNewPercentageNormal(): number { if (_.isUndefined(this._startTimeUnix) || _.isUndefined(this._expectedTimeMs)) { throw new Error('Cant tick, missing var'); } @@ -93,15 +93,7 @@ export class Progress { return percentageDone; } - private _tickFinishing(finishingState: TickingFinishingStatus): number { + private _getNewPercentageFinishing(finishingState: TickingFinishingStatus): number { return this._percentageDone + finishingState.increasePercentageEveryTick; } - - private _clearInterval(): void { - return window.clearInterval(this._intervalId); - } - - // reset function - - // end function } -- cgit v1.2.3 From 12dad41143c50d858edbb665d4795142a6339dd7 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 30 Oct 2018 10:58:47 -0700 Subject: Remove old TODO --- packages/instant/src/util/progress.ts | 1 - 1 file changed, 1 deletion(-) (limited to 'packages') diff --git a/packages/instant/src/util/progress.ts b/packages/instant/src/util/progress.ts index 3c328f2f1..5cb6a6de9 100644 --- a/packages/instant/src/util/progress.ts +++ b/packages/instant/src/util/progress.ts @@ -39,7 +39,6 @@ export class Progress { this._percentageDone = 0; this._intervalId = undefined; this._tickingStatus = { state: TickingState.None }; - // TODO: clear interval } public beginRunning(expectedTimeMs: number): void { -- cgit v1.2.3 From 05b74ba1c8b10c356d396ce9a4834d053cd791b1 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 30 Oct 2018 13:27:28 -0700 Subject: Dispatching progress --- packages/instant/src/components/progress_bar.tsx | 17 ++++++++++ .../src/components/zero_ex_instant_container.tsx | 3 +- .../src/containers/selected_asset_progress_bar.tsx | 37 ++++++++++++++++++++++ packages/instant/src/redux/actions.ts | 3 ++ packages/instant/src/redux/reducer.ts | 7 ++++ packages/instant/src/types.ts | 5 +++ packages/instant/src/util/progress.ts | 16 ++++++++-- 7 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 packages/instant/src/components/progress_bar.tsx create mode 100644 packages/instant/src/containers/selected_asset_progress_bar.tsx (limited to 'packages') diff --git a/packages/instant/src/components/progress_bar.tsx b/packages/instant/src/components/progress_bar.tsx new file mode 100644 index 000000000..b89c56ed5 --- /dev/null +++ b/packages/instant/src/components/progress_bar.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; + +import { ColorOption } from '../style/theme'; + +import { Container } from './ui/container'; +import { Text } from './ui/text'; + +export interface ProgressBarProps { + percentageDone: number; +} +export const ProgressBar: React.StatelessComponent = props => ( + + + {props.percentageDone}% + + +); diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index ff19351ff..b9f8d0d92 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -4,11 +4,11 @@ import { LatestBuyQuoteOrderDetails } from '../containers/latest_buy_quote_order import { LatestError } from '../containers/latest_error'; import { SelectedAssetBuyOrderStateButtons } from '../containers/selected_asset_buy_order_state_buttons'; import { SelectedAssetInstantHeading } from '../containers/selected_asset_instant_heading'; +import { SelectedAssetProgressBar } from '../containers/selected_asset_progress_bar'; import { ColorOption } from '../style/theme'; import { Container, Flex } from './ui'; - export interface ZeroExInstantContainerProps {} export const ZeroExInstantContainer: React.StatelessComponent = props => ( @@ -25,6 +25,7 @@ export const ZeroExInstantContainer: React.StatelessComponent + diff --git a/packages/instant/src/containers/selected_asset_progress_bar.tsx b/packages/instant/src/containers/selected_asset_progress_bar.tsx new file mode 100644 index 000000000..886e223d3 --- /dev/null +++ b/packages/instant/src/containers/selected_asset_progress_bar.tsx @@ -0,0 +1,37 @@ +import * as React from 'react'; + +import { connect } from 'react-redux'; + +import { ProgressBar } from '../components/progress_bar'; +import { State } from '../redux/reducer'; +import { OrderProcessState, OrderState } from '../types'; + +interface SelectedAssetProgressComponentProps { + buyOrderState: OrderState; + percentageDone?: number; +} +export const SelectedAssetProgressComponent: React.StatelessComponent = props => { + const { buyOrderState, percentageDone } = props; + + // TODO: uncomment after done testing + // const isOrderStateOk = + // buyOrderState.processState === OrderProcessState.PROCESSING || + // buyOrderState.processState === OrderProcessState.SUCCESS; + const isOrderStateOk = true; + + if (isOrderStateOk && percentageDone) { + return ; + } + + return null; +}; + +interface ConnectedState { + buyOrderState: OrderState; + percentageDone?: number; +} +const mapStateToProps = (state: State, _ownProps: {}): ConnectedState => ({ + buyOrderState: state.buyOrderState, + percentageDone: state.orderProgress && state.orderProgress.percentageDone, +}); +export const SelectedAssetProgressBar = connect(mapStateToProps)(SelectedAssetProgressComponent); diff --git a/packages/instant/src/redux/actions.ts b/packages/instant/src/redux/actions.ts index bfae68e2b..59d059b59 100644 --- a/packages/instant/src/redux/actions.ts +++ b/packages/instant/src/redux/actions.ts @@ -28,6 +28,7 @@ export enum ActionTypes { UPDATE_BUY_ORDER_STATE = 'UPDATE_BUY_ORDER_STATE', UPDATE_LATEST_BUY_QUOTE = 'UPDATE_LATEST_BUY_QUOTE', UPDATE_SELECTED_ASSET = 'UPDATE_SELECTED_ASSET', + UPDATE_ORDER_PROGRESS_PERCENTAGE = 'UPDATE_ORDER_PROGRESS_PERCENTAGE', SET_QUOTE_REQUEST_STATE_PENDING = 'SET_QUOTE_REQUEST_STATE_PENDING', SET_QUOTE_REQUEST_STATE_FAILURE = 'SET_QUOTE_REQUEST_STATE_FAILURE', SET_ERROR_MESSAGE = 'SET_ERROR_MESSAGE', @@ -43,6 +44,8 @@ export const actions = { 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), + updateOrderProgressPercentage: (percentDone: number) => + createAction(ActionTypes.UPDATE_ORDER_PROGRESS_PERCENTAGE, percentDone), setQuoteRequestStatePending: () => createAction(ActionTypes.SET_QUOTE_REQUEST_STATE_PENDING), setQuoteRequestStateFailure: () => createAction(ActionTypes.SET_QUOTE_REQUEST_STATE_FAILURE), setErrorMessage: (errorMessage: string) => createAction(ActionTypes.SET_ERROR_MESSAGE, errorMessage), diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index dd9403052..be336f7c2 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -12,6 +12,7 @@ import { DisplayStatus, Network, OrderProcessState, + OrderProgress, OrderState, } from '../types'; import { assetUtils } from '../util/asset'; @@ -31,6 +32,7 @@ export interface State { quoteRequestState: AsyncProcessState; latestErrorMessage?: string; latestErrorDisplayStatus: DisplayStatus; + orderProgress?: OrderProgress; } export const INITIAL_STATE: State = { @@ -119,6 +121,11 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State => ...state, selectedAsset: newSelectedAsset, }; + case ActionTypes.UPDATE_ORDER_PROGRESS_PERCENTAGE: + return { + ...state, + orderProgress: { percentageDone: action.data }, + }; case ActionTypes.RESET_AMOUNT: return { ...state, diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts index 4631c9cae..722590165 100644 --- a/packages/instant/src/types.ts +++ b/packages/instant/src/types.ts @@ -16,12 +16,17 @@ export enum OrderProcessState { FAILURE = 'Failure', } +export interface OrderProgress { + percentageDone: number; +} + interface OrderStatePreTx { processState: OrderProcessState.NONE | OrderProcessState.VALIDATING; } interface OrderStatePostTx { processState: OrderProcessState.PROCESSING | OrderProcessState.SUCCESS | OrderProcessState.FAILURE; txHash: string; + // TODO: move/rename? estimatedTimeMs?: number; } export type OrderState = OrderStatePreTx | OrderStatePostTx; diff --git a/packages/instant/src/util/progress.ts b/packages/instant/src/util/progress.ts index 5cb6a6de9..08b813e3d 100644 --- a/packages/instant/src/util/progress.ts +++ b/packages/instant/src/util/progress.ts @@ -1,3 +1,4 @@ +// TODO: change filename? import * as _ from 'lodash'; import { Dispatch } from 'redux'; @@ -26,19 +27,21 @@ interface TickingFinishingStatus { type TickingStatus = TickingNoneState | TickingRunningStatus | TickingFinishingStatus; const TICKS_PER_SECOND = 1000 / PROGRESS_TICK_INTERVAL_MS; -export class Progress { +class Progress { private _startTimeUnix?: number; private _expectedTimeMs?: number; private _intervalId?: number; private _percentageDone: number; private _tickingStatus: TickingStatus; + private _dispatcher: Dispatch; - constructor() { + constructor(dispatcher: Dispatch) { this._startTimeUnix = undefined; this._expectedTimeMs = undefined; this._percentageDone = 0; this._intervalId = undefined; this._tickingStatus = { state: TickingState.None }; + this._dispatcher = dispatcher; } public beginRunning(expectedTimeMs: number): void { @@ -66,8 +69,9 @@ export class Progress { : this._getNewPercentageNormal(); const maxPercentage = this._tickingStatus.state === TickingState.Finishing ? 100 : PROGRESS_STALL_AT_PERCENTAGE; - const percentageDone = Math.min(rawPercentageDone, maxPercentage); + const percentageDone = Math.floor(Math.min(rawPercentageDone, maxPercentage)); this._percentageDone = percentageDone; + this._dispatcher(actions.updateOrderProgressPercentage(this._percentageDone)); console.log('percentageDone', this._percentageDone); if (percentageDone >= 100) { this._clearTimer(); @@ -96,3 +100,9 @@ export class Progress { return this._percentageDone + finishingState.increasePercentageEveryTick; } } + +let _currentProgress: Progress | undefined; +export const progress = (dispatcher: Dispatch): Progress => { + _currentProgress = _currentProgress || new Progress(dispatcher); + return _currentProgress; +}; -- cgit v1.2.3 From bcb633e5cbcbfdfdfe8c91170abfca7dbb003417 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 30 Oct 2018 13:34:47 -0700 Subject: Making prettier --- packages/instant/src/components/progress_bar.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/progress_bar.tsx b/packages/instant/src/components/progress_bar.tsx index b89c56ed5..5b5968703 100644 --- a/packages/instant/src/components/progress_bar.tsx +++ b/packages/instant/src/components/progress_bar.tsx @@ -3,15 +3,19 @@ import * as React from 'react'; import { ColorOption } from '../style/theme'; import { Container } from './ui/container'; -import { Text } from './ui/text'; export interface ProgressBarProps { percentageDone: number; } export const ProgressBar: React.StatelessComponent = props => ( - - - {props.percentageDone}% + + + ); -- cgit v1.2.3 From 13b41c976b42983f5869813715313c2da22abcbc Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 30 Oct 2018 13:51:18 -0700 Subject: Placeholder for estimated time --- packages/instant/src/components/progress_bar.tsx | 15 ++++++++++++++- .../src/containers/selected_asset_progress_bar.tsx | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/progress_bar.tsx b/packages/instant/src/components/progress_bar.tsx index 5b5968703..d5d1f3ded 100644 --- a/packages/instant/src/components/progress_bar.tsx +++ b/packages/instant/src/components/progress_bar.tsx @@ -3,18 +3,31 @@ import * as React from 'react'; import { ColorOption } from '../style/theme'; import { Container } from './ui/container'; +import { Flex } from './ui/flex'; +import { Text } from './ui/text'; export interface ProgressBarProps { percentageDone: number; + estTimeMs: number; + elapsedTimeMs: number; } + +// TODO: Est time to minutes with suffix +// TODO: time in minutes export const ProgressBar: React.StatelessComponent = props => ( + + + Est. Time ({props.estTimeMs / 1000} seconds) + {props.elapsedTimeMs / 1000} + + diff --git a/packages/instant/src/containers/selected_asset_progress_bar.tsx b/packages/instant/src/containers/selected_asset_progress_bar.tsx index 886e223d3..4564c790a 100644 --- a/packages/instant/src/containers/selected_asset_progress_bar.tsx +++ b/packages/instant/src/containers/selected_asset_progress_bar.tsx @@ -20,7 +20,7 @@ export const SelectedAssetProgressComponent: React.StatelessComponent; + return ; } return null; -- cgit v1.2.3 From 05f059492bbc86d61946562ac8c116259ded3487 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 30 Oct 2018 14:48:09 -0700 Subject: WIP: beginning of simulated progress bar component --- .../src/components/simulated_progress_bar.tsx | 136 +++++++++++++++++++++ packages/instant/src/util/progress.ts | 2 +- 2 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 packages/instant/src/components/simulated_progress_bar.tsx (limited to 'packages') diff --git a/packages/instant/src/components/simulated_progress_bar.tsx b/packages/instant/src/components/simulated_progress_bar.tsx new file mode 100644 index 000000000..3a957aca6 --- /dev/null +++ b/packages/instant/src/components/simulated_progress_bar.tsx @@ -0,0 +1,136 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import { Dispatch } from 'redux'; + +import { PROGRESS_STALL_AT_PERCENTAGE, PROGRESS_TICK_INTERVAL_MS } from '../constants'; +import { Action, actions } from '../redux/actions'; + +import { ColorOption } from '../style/theme'; + +import { Container } from './ui/container'; +import { Flex } from './ui/flex'; +import { Text } from './ui/text'; + +const TICKS_PER_SECOND = 1000 / PROGRESS_TICK_INTERVAL_MS; + +const curTimeUnix = () => { + return new Date().getTime(); +}; + +export interface SimulatedProgressBarProps { + startTimeUnix: number; + expectedEndTimeUnix: number; + ended: boolean; +} +enum TickingRunState { + None, + Running, + Finishing, +} +interface TickingNoneStatus { + runState: TickingRunState.None; +} +interface TickingRunningStatus { + runState: TickingRunState.Running; +} +interface TickingFinishingStatus { + runState: TickingRunState.Finishing; + increasePercentageEveryTick: number; +} +type TickingStatus = TickingNoneStatus | TickingRunningStatus | TickingFinishingStatus; + +export interface SimulatedProgressState { + percentageDone: number; + intervalId?: number; + tickingStatus: TickingStatus; +} +export class SimulatedProgressBar extends React.Component { + public constructor(props: SimulatedProgressBarProps) { + super(props); + + // TODO: look into using assert library here? + if (props.expectedEndTimeUnix <= props.startTimeUnix) { + throw new Error('End time before start time'); + } + + const intervalId = window.setInterval(this._tick.bind(this), PROGRESS_TICK_INTERVAL_MS); + this.state = { + percentageDone: 0, + intervalId, + tickingStatus: { runState: TickingRunState.Running }, + }; + } + + public componentDidUpdate(prevProps: SimulatedProgressBarProps, prevState: SimulatedProgressState): void { + const percentLeft = 100 - this.state.percentageDone; + const increasePercentageEveryTick = percentLeft / TICKS_PER_SECOND; + + if (prevProps.ended === false && this.props.ended === true) { + this.setState({ + tickingStatus: { + runState: TickingRunState.Finishing, + increasePercentageEveryTick, + }, + }); + } + } + + public componentWillUnmount(): void { + this._clearTimer(); + } + + public render(): React.ReactNode { + // TODO: Consider moving to seperate component + return ( + + + + + + ); + } + + private _tick(): void { + const rawPercentageDone = + this.state.tickingStatus.runState === TickingRunState.Finishing + ? this._getNewPercentageFinishing(this.state.tickingStatus) + : this._getNewPercentageNormal(); + + const maxPercentage = + this.state.tickingStatus.runState === TickingRunState.Finishing ? 100 : PROGRESS_STALL_AT_PERCENTAGE; + const percentageDone = Math.floor(Math.min(rawPercentageDone, maxPercentage)); + + this.setState({ + percentageDone, + }); + + if (percentageDone >= 100) { + this._clearTimer(); + } + } + + private _clearTimer(): void { + if (this.state.intervalId) { + window.clearTimeout(this.state.intervalId); + } + } + + // TODO: consider not taking in a parameter here, might be confusing + private _getNewPercentageFinishing(tickingStatus: TickingFinishingStatus): number { + return this.state.percentageDone + tickingStatus.increasePercentageEveryTick; + } + + private _getNewPercentageNormal(): number { + const elapsedTimeMs = curTimeUnix() - this.props.startTimeUnix; + const safeElapsedTimeMs = Math.max(elapsedTimeMs, 1); + + const expectedAmountOfTimeMs = this.props.expectedEndTimeUnix - this.props.startTimeUnix; + const percentageDone = safeElapsedTimeMs / expectedAmountOfTimeMs * 100; + return percentageDone; + } +} diff --git a/packages/instant/src/util/progress.ts b/packages/instant/src/util/progress.ts index 08b813e3d..2d74ef354 100644 --- a/packages/instant/src/util/progress.ts +++ b/packages/instant/src/util/progress.ts @@ -1,4 +1,4 @@ -// TODO: change filename? +// TODO: delete!! import * as _ from 'lodash'; import { Dispatch } from 'redux'; -- cgit v1.2.3 From abaa39a5e24daa8a1a7ff5617a14d2f3088cb0e3 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 30 Oct 2018 15:39:58 -0700 Subject: Simulated Progress component working --- .../src/components/simulated_progress_bar.tsx | 34 ++++++++++++--- .../src/components/zero_ex_instant_container.tsx | 4 ++ .../selected_asset_simulated_progress_bar.tsx | 48 ++++++++++++++++++++++ packages/instant/src/redux/actions.ts | 6 ++- packages/instant/src/redux/reducer.ts | 9 ++++ packages/instant/src/types.ts | 7 ++++ 6 files changed, 102 insertions(+), 6 deletions(-) create mode 100644 packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx (limited to 'packages') diff --git a/packages/instant/src/components/simulated_progress_bar.tsx b/packages/instant/src/components/simulated_progress_bar.tsx index 3a957aca6..1fd76ead7 100644 --- a/packages/instant/src/components/simulated_progress_bar.tsx +++ b/packages/instant/src/components/simulated_progress_bar.tsx @@ -23,9 +23,9 @@ export interface SimulatedProgressBarProps { ended: boolean; } enum TickingRunState { - None, - Running, - Finishing, + None = 'None', + Running = 'Running', + Finishing = 'Finishing', } interface TickingNoneStatus { runState: TickingRunState.None; @@ -53,6 +53,7 @@ export class SimulatedProgressBar extends React.Component + diff --git a/packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx b/packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx new file mode 100644 index 000000000..1ddb4ae66 --- /dev/null +++ b/packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx @@ -0,0 +1,48 @@ +import * as React from 'react'; + +import { connect } from 'react-redux'; + +import { SimulatedProgressBar } from '../components/simulated_progress_bar'; + +import { State } from '../redux/reducer'; +import { OrderProcessState, OrderState, SimulatedProgress } from '../types'; + +interface SelectedAssetProgressComponentProps { + buyOrderState: OrderState; + simulatedProgress?: SimulatedProgress; +} +export const SelectedAssetSimulatedProgressComponent: React.StatelessComponent< + SelectedAssetProgressComponentProps +> = props => { + const { buyOrderState, simulatedProgress } = props; + + console.log('simulatedProgress', simulatedProgress); + + // TODO: uncomment after done testing + // const isOrderStateOk = + // buyOrderState.processState === OrderProcessState.PROCESSING || + // buyOrderState.processState === OrderProcessState.SUCCESS; + const isOrderStateOk = true; + + if (isOrderStateOk && simulatedProgress) { + return ( + + ); + } + + return null; +}; + +interface ConnectedState { + buyOrderState: OrderState; + simulatedProgress?: SimulatedProgress; +} +const mapStateToProps = (state: State, _ownProps: {}): ConnectedState => ({ + buyOrderState: state.buyOrderState, + simulatedProgress: state.simulatedProgress, +}); +export const SelectedAssetSimulatedProgressBar = connect(mapStateToProps)(SelectedAssetSimulatedProgressComponent); diff --git a/packages/instant/src/redux/actions.ts b/packages/instant/src/redux/actions.ts index 59d059b59..e8002aa3b 100644 --- a/packages/instant/src/redux/actions.ts +++ b/packages/instant/src/redux/actions.ts @@ -4,7 +4,7 @@ import * as _ from 'lodash'; import { BigNumberInput } from '../util/big_number_input'; -import { ActionsUnion, OrderState } from '../types'; +import { ActionsUnion, OrderState, SimulatedProgress } from '../types'; export interface PlainAction { type: T; @@ -29,6 +29,7 @@ export enum ActionTypes { UPDATE_LATEST_BUY_QUOTE = 'UPDATE_LATEST_BUY_QUOTE', UPDATE_SELECTED_ASSET = 'UPDATE_SELECTED_ASSET', UPDATE_ORDER_PROGRESS_PERCENTAGE = 'UPDATE_ORDER_PROGRESS_PERCENTAGE', + UPDATE_SIMULATED_ORDER_PROGRESS = 'UPDATE_SIMULATED_ORDER_PROGRESS', SET_QUOTE_REQUEST_STATE_PENDING = 'SET_QUOTE_REQUEST_STATE_PENDING', SET_QUOTE_REQUEST_STATE_FAILURE = 'SET_QUOTE_REQUEST_STATE_FAILURE', SET_ERROR_MESSAGE = 'SET_ERROR_MESSAGE', @@ -44,8 +45,11 @@ export const actions = { 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), + // TODO: this is old, delete updateOrderProgressPercentage: (percentDone: number) => createAction(ActionTypes.UPDATE_ORDER_PROGRESS_PERCENTAGE, percentDone), + updateSimulatedOrderProgress: (orderProgress: SimulatedProgress) => + createAction(ActionTypes.UPDATE_SIMULATED_ORDER_PROGRESS, orderProgress), setQuoteRequestStatePending: () => createAction(ActionTypes.SET_QUOTE_REQUEST_STATE_PENDING), setQuoteRequestStateFailure: () => createAction(ActionTypes.SET_QUOTE_REQUEST_STATE_FAILURE), setErrorMessage: (errorMessage: string) => createAction(ActionTypes.SET_ERROR_MESSAGE, errorMessage), diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index be336f7c2..428cf0984 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -14,6 +14,7 @@ import { OrderProcessState, OrderProgress, OrderState, + SimulatedProgress, } from '../types'; import { assetUtils } from '../util/asset'; import { BigNumberInput } from '../util/big_number_input'; @@ -32,7 +33,9 @@ export interface State { quoteRequestState: AsyncProcessState; latestErrorMessage?: string; latestErrorDisplayStatus: DisplayStatus; + // TODO: this is old, cleanup orderProgress?: OrderProgress; + simulatedProgress?: SimulatedProgress; } export const INITIAL_STATE: State = { @@ -121,11 +124,17 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State => ...state, selectedAsset: newSelectedAsset, }; + // TODO: this is old, delete case ActionTypes.UPDATE_ORDER_PROGRESS_PERCENTAGE: return { ...state, orderProgress: { percentageDone: action.data }, }; + case ActionTypes.UPDATE_SIMULATED_ORDER_PROGRESS: + return { + ...state, + simulatedProgress: action.data, + }; case ActionTypes.RESET_AMOUNT: return { ...state, diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts index 722590165..4b63abdda 100644 --- a/packages/instant/src/types.ts +++ b/packages/instant/src/types.ts @@ -16,10 +16,17 @@ export enum OrderProcessState { FAILURE = 'Failure', } +// TODO: this is old, delete export interface OrderProgress { percentageDone: number; } +export interface SimulatedProgress { + startTimeUnix: number; + expectedEndTimeUnix: number; + ended: boolean; +} + interface OrderStatePreTx { processState: OrderProcessState.NONE | OrderProcessState.VALIDATING; } -- cgit v1.2.3 From dc9013652914333bfdc3c067d9b83a71f28c7382 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 30 Oct 2018 15:43:38 -0700 Subject: Remove old files --- packages/instant/src/components/progress_bar.tsx | 34 ------- .../src/components/zero_ex_instant_container.tsx | 3 - .../src/containers/selected_asset_progress_bar.tsx | 37 ------- packages/instant/src/redux/actions.ts | 4 - packages/instant/src/redux/reducer.ts | 9 -- packages/instant/src/types.ts | 5 - packages/instant/src/util/progress.ts | 108 --------------------- 7 files changed, 200 deletions(-) delete mode 100644 packages/instant/src/components/progress_bar.tsx delete mode 100644 packages/instant/src/containers/selected_asset_progress_bar.tsx delete mode 100644 packages/instant/src/util/progress.ts (limited to 'packages') diff --git a/packages/instant/src/components/progress_bar.tsx b/packages/instant/src/components/progress_bar.tsx deleted file mode 100644 index d5d1f3ded..000000000 --- a/packages/instant/src/components/progress_bar.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import * as React from 'react'; - -import { ColorOption } from '../style/theme'; - -import { Container } from './ui/container'; -import { Flex } from './ui/flex'; -import { Text } from './ui/text'; - -export interface ProgressBarProps { - percentageDone: number; - estTimeMs: number; - elapsedTimeMs: number; -} - -// TODO: Est time to minutes with suffix -// TODO: time in minutes -export const ProgressBar: React.StatelessComponent = props => ( - - - - Est. Time ({props.estTimeMs / 1000} seconds) - {props.elapsedTimeMs / 1000} - - - - - - -); diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index ae315da47..6b1042668 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -5,8 +5,6 @@ import { LatestError } from '../containers/latest_error'; import { SelectedAssetBuyOrderStateButtons } from '../containers/selected_asset_buy_order_state_buttons'; import { SelectedAssetInstantHeading } from '../containers/selected_asset_instant_heading'; -// TODO: delete this import and this actual file -import { SelectedAssetProgressBar } from '../containers/selected_asset_progress_bar'; import { SelectedAssetSimulatedProgressBar } from '../containers/selected_asset_simulated_progress_bar'; import { ColorOption } from '../style/theme'; @@ -29,7 +27,6 @@ export const ZeroExInstantContainer: React.StatelessComponent - diff --git a/packages/instant/src/containers/selected_asset_progress_bar.tsx b/packages/instant/src/containers/selected_asset_progress_bar.tsx deleted file mode 100644 index 4564c790a..000000000 --- a/packages/instant/src/containers/selected_asset_progress_bar.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import * as React from 'react'; - -import { connect } from 'react-redux'; - -import { ProgressBar } from '../components/progress_bar'; -import { State } from '../redux/reducer'; -import { OrderProcessState, OrderState } from '../types'; - -interface SelectedAssetProgressComponentProps { - buyOrderState: OrderState; - percentageDone?: number; -} -export const SelectedAssetProgressComponent: React.StatelessComponent = props => { - const { buyOrderState, percentageDone } = props; - - // TODO: uncomment after done testing - // const isOrderStateOk = - // buyOrderState.processState === OrderProcessState.PROCESSING || - // buyOrderState.processState === OrderProcessState.SUCCESS; - const isOrderStateOk = true; - - if (isOrderStateOk && percentageDone) { - return ; - } - - return null; -}; - -interface ConnectedState { - buyOrderState: OrderState; - percentageDone?: number; -} -const mapStateToProps = (state: State, _ownProps: {}): ConnectedState => ({ - buyOrderState: state.buyOrderState, - percentageDone: state.orderProgress && state.orderProgress.percentageDone, -}); -export const SelectedAssetProgressBar = connect(mapStateToProps)(SelectedAssetProgressComponent); diff --git a/packages/instant/src/redux/actions.ts b/packages/instant/src/redux/actions.ts index e8002aa3b..c27c188bf 100644 --- a/packages/instant/src/redux/actions.ts +++ b/packages/instant/src/redux/actions.ts @@ -28,7 +28,6 @@ export enum ActionTypes { UPDATE_BUY_ORDER_STATE = 'UPDATE_BUY_ORDER_STATE', UPDATE_LATEST_BUY_QUOTE = 'UPDATE_LATEST_BUY_QUOTE', UPDATE_SELECTED_ASSET = 'UPDATE_SELECTED_ASSET', - UPDATE_ORDER_PROGRESS_PERCENTAGE = 'UPDATE_ORDER_PROGRESS_PERCENTAGE', UPDATE_SIMULATED_ORDER_PROGRESS = 'UPDATE_SIMULATED_ORDER_PROGRESS', SET_QUOTE_REQUEST_STATE_PENDING = 'SET_QUOTE_REQUEST_STATE_PENDING', SET_QUOTE_REQUEST_STATE_FAILURE = 'SET_QUOTE_REQUEST_STATE_FAILURE', @@ -45,9 +44,6 @@ export const actions = { 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), - // TODO: this is old, delete - updateOrderProgressPercentage: (percentDone: number) => - createAction(ActionTypes.UPDATE_ORDER_PROGRESS_PERCENTAGE, percentDone), updateSimulatedOrderProgress: (orderProgress: SimulatedProgress) => createAction(ActionTypes.UPDATE_SIMULATED_ORDER_PROGRESS, orderProgress), 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 428cf0984..3540bd4eb 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -12,7 +12,6 @@ import { DisplayStatus, Network, OrderProcessState, - OrderProgress, OrderState, SimulatedProgress, } from '../types'; @@ -33,8 +32,6 @@ export interface State { quoteRequestState: AsyncProcessState; latestErrorMessage?: string; latestErrorDisplayStatus: DisplayStatus; - // TODO: this is old, cleanup - orderProgress?: OrderProgress; simulatedProgress?: SimulatedProgress; } @@ -124,12 +121,6 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State => ...state, selectedAsset: newSelectedAsset, }; - // TODO: this is old, delete - case ActionTypes.UPDATE_ORDER_PROGRESS_PERCENTAGE: - return { - ...state, - orderProgress: { percentageDone: action.data }, - }; case ActionTypes.UPDATE_SIMULATED_ORDER_PROGRESS: return { ...state, diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts index 4b63abdda..58d6692e4 100644 --- a/packages/instant/src/types.ts +++ b/packages/instant/src/types.ts @@ -16,11 +16,6 @@ export enum OrderProcessState { FAILURE = 'Failure', } -// TODO: this is old, delete -export interface OrderProgress { - percentageDone: number; -} - export interface SimulatedProgress { startTimeUnix: number; expectedEndTimeUnix: number; diff --git a/packages/instant/src/util/progress.ts b/packages/instant/src/util/progress.ts deleted file mode 100644 index 2d74ef354..000000000 --- a/packages/instant/src/util/progress.ts +++ /dev/null @@ -1,108 +0,0 @@ -// TODO: delete!! -import * as _ from 'lodash'; -import { Dispatch } from 'redux'; - -import { PROGRESS_STALL_AT_PERCENTAGE, PROGRESS_TICK_INTERVAL_MS } from '../constants'; -import { Action, actions } from '../redux/actions'; - -const curTimeUnix = () => { - return new Date().getTime(); -}; - -enum TickingState { - None, - Running, - Finishing, -} -interface TickingNoneState { - state: TickingState.None; -} -interface TickingRunningStatus { - state: TickingState.Running; -} -interface TickingFinishingStatus { - state: TickingState.Finishing; - increasePercentageEveryTick: number; -} -type TickingStatus = TickingNoneState | TickingRunningStatus | TickingFinishingStatus; - -const TICKS_PER_SECOND = 1000 / PROGRESS_TICK_INTERVAL_MS; -class Progress { - private _startTimeUnix?: number; - private _expectedTimeMs?: number; - private _intervalId?: number; - private _percentageDone: number; - private _tickingStatus: TickingStatus; - private _dispatcher: Dispatch; - - constructor(dispatcher: Dispatch) { - this._startTimeUnix = undefined; - this._expectedTimeMs = undefined; - this._percentageDone = 0; - this._intervalId = undefined; - this._tickingStatus = { state: TickingState.None }; - this._dispatcher = dispatcher; - } - - public beginRunning(expectedTimeMs: number): void { - this._clearTimer(); - this._startTimeUnix = curTimeUnix(); - this._expectedTimeMs = expectedTimeMs; - this._percentageDone = 0; - this._intervalId = window.setInterval(this._tick.bind(this), PROGRESS_TICK_INTERVAL_MS); - this._tickingStatus = { state: TickingState.Running }; - } - - public setFinishing(): void { - const percentLeft = 100 - this._percentageDone; - const increasePercentageEveryTick = percentLeft / TICKS_PER_SECOND; - this._tickingStatus = { - state: TickingState.Finishing, - increasePercentageEveryTick, - }; - } - - private _tick(): void { - const rawPercentageDone = - this._tickingStatus.state === TickingState.Finishing - ? this._getNewPercentageFinishing(this._tickingStatus) - : this._getNewPercentageNormal(); - - const maxPercentage = this._tickingStatus.state === TickingState.Finishing ? 100 : PROGRESS_STALL_AT_PERCENTAGE; - const percentageDone = Math.floor(Math.min(rawPercentageDone, maxPercentage)); - this._percentageDone = percentageDone; - this._dispatcher(actions.updateOrderProgressPercentage(this._percentageDone)); - console.log('percentageDone', this._percentageDone); - if (percentageDone >= 100) { - this._clearTimer(); - } - return; - } - - private _clearTimer(): void { - if (this._intervalId) { - window.clearTimeout(this._intervalId); - } - } - - private _getNewPercentageNormal(): number { - if (_.isUndefined(this._startTimeUnix) || _.isUndefined(this._expectedTimeMs)) { - throw new Error('Cant tick, missing var'); - } - - const elapsedTimeMs = curTimeUnix() - this._startTimeUnix; - const safeElapsedTimeMs = Math.max(elapsedTimeMs, 1); - const percentageDone = safeElapsedTimeMs / this._expectedTimeMs * 100; - return percentageDone; - } - - private _getNewPercentageFinishing(finishingState: TickingFinishingStatus): number { - return this._percentageDone + finishingState.increasePercentageEveryTick; - } -} - -let _currentProgress: Progress | undefined; -export const progress = (dispatcher: Dispatch): Progress => { - _currentProgress = _currentProgress || new Progress(dispatcher); - return _currentProgress; -}; -- cgit v1.2.3 From d21487d0c07de307bbe9de459f8d3b00e15dc8dc Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 30 Oct 2018 15:47:35 -0700 Subject: Show estimated time --- packages/instant/src/components/simulated_progress_bar.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'packages') diff --git a/packages/instant/src/components/simulated_progress_bar.tsx b/packages/instant/src/components/simulated_progress_bar.tsx index 1fd76ead7..5742cd474 100644 --- a/packages/instant/src/components/simulated_progress_bar.tsx +++ b/packages/instant/src/components/simulated_progress_bar.tsx @@ -96,8 +96,17 @@ export class SimulatedProgressBar extends React.Component + + {/* TODO: consider moving to separate component */} + + Est. Time ({estimatedTimeSeconds} seconds) + x + + Date: Tue, 30 Oct 2018 15:55:53 -0700 Subject: Showing time --- packages/instant/src/components/simulated_progress_bar.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/instant/src/components/simulated_progress_bar.tsx b/packages/instant/src/components/simulated_progress_bar.tsx index 5742cd474..e9e547cbe 100644 --- a/packages/instant/src/components/simulated_progress_bar.tsx +++ b/packages/instant/src/components/simulated_progress_bar.tsx @@ -43,6 +43,7 @@ export interface SimulatedProgressState { percentageDone: number; intervalId?: number; tickingStatus: TickingStatus; + elapsedTimeMs: number; } export class SimulatedProgressBar extends React.Component { public constructor(props: SimulatedProgressBarProps) { @@ -59,6 +60,7 @@ export class SimulatedProgressBar extends React.Component {/* TODO: consider moving to separate component */} + {/* TODO: should do nice display of these (i.e. 'minutes' and 00:xx) */} Est. Time ({estimatedTimeSeconds} seconds) - x + Time: {elapsedTimeSeconds} @@ -126,6 +130,7 @@ export class SimulatedProgressBar extends React.Component= 100) { -- cgit v1.2.3 From 9cc82308e504a62a2bd3b16e79173a98279fdb66 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 30 Oct 2018 16:39:52 -0700 Subject: Always return estimated time, just use default if not known --- packages/instant/src/util/gas_price_estimator.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/util/gas_price_estimator.ts b/packages/instant/src/util/gas_price_estimator.ts index 0552ccde1..6b15809a3 100644 --- a/packages/instant/src/util/gas_price_estimator.ts +++ b/packages/instant/src/util/gas_price_estimator.ts @@ -1,6 +1,11 @@ import { BigNumber, fetchAsync } from '@0x/utils'; -import { DEFAULT_GAS_PRICE, ETH_GAS_STATION_API_BASE_URL, GWEI_IN_WEI } from '../constants'; +import { + DEFAULT_ESTIMATED_TRANSACTION_TIME_MS, + DEFAULT_GAS_PRICE, + ETH_GAS_STATION_API_BASE_URL, + GWEI_IN_WEI, +} from '../constants'; interface EthGasStationResult { average: number; @@ -18,7 +23,7 @@ interface EthGasStationResult { interface GasInfo { gasPriceInWei: BigNumber; - estimatedTimeMs?: number; + estimatedTimeMs: number; } const fetchFastAmountInWeiAsync = async (): Promise => { @@ -45,7 +50,13 @@ export class GasPriceEstimator { this._lastFetched = fetchedAmount; } - return fetchedAmount || this._lastFetched || { gasPriceInWei: DEFAULT_GAS_PRICE, estimatedTimeMs: undefined }; + return ( + fetchedAmount || + this._lastFetched || { + gasPriceInWei: DEFAULT_GAS_PRICE, + estimatedTimeMs: DEFAULT_ESTIMATED_TRANSACTION_TIME_MS, + } + ); } } export const gasPriceEstimator = new GasPriceEstimator(); -- cgit v1.2.3 From 1c0569cfc61d7b166d79d2d73e9bbc6d11a5b4e8 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 30 Oct 2018 16:40:51 -0700 Subject: Use simulated progress bar for txn --- packages/instant/src/components/buy_button.tsx | 14 +++-- .../src/components/buy_order_state_buttons.tsx | 39 ++++++++---- packages/instant/src/constants.ts | 1 + .../selected_asset_buy_order_state_buttons.ts | 70 +++++++++++++++++++--- .../selected_asset_simulated_progress_bar.tsx | 26 ++++---- packages/instant/src/types.ts | 3 +- 6 files changed, 108 insertions(+), 45 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index ec1010fe9..d10936d05 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -19,9 +19,9 @@ export interface BuyButtonProps { onValidationPending: (buyQuote: BuyQuote) => void; onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void; onSignatureDenied: (buyQuote: BuyQuote) => void; - onBuyProcessing: (buyQuote: BuyQuote, txHash: string, estimatedTimeMs?: number) => void; - onBuySuccess: (buyQuote: BuyQuote, txHash: string) => void; - onBuyFailure: (buyQuote: BuyQuote, txHash: string) => void; + onBuyProcessing: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => void; + onBuySuccess: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => void; + onBuyFailure: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => void; } export class BuyButton extends React.Component { @@ -73,16 +73,18 @@ export class BuyButton extends React.Component { throw e; } - this.props.onBuyProcessing(buyQuote, txHash, gasInfo.estimatedTimeMs); + const startTimeUnix = new Date().getTime(); + const expectedEndTimeUnix = startTimeUnix + gasInfo.estimatedTimeMs; + this.props.onBuyProcessing(buyQuote, txHash, startTimeUnix, expectedEndTimeUnix); try { await web3Wrapper.awaitTransactionSuccessAsync(txHash); } catch (e) { if (e instanceof Error && e.message.startsWith(WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX)) { - this.props.onBuyFailure(buyQuote, txHash); + this.props.onBuyFailure(buyQuote, txHash, startTimeUnix, expectedEndTimeUnix); return; } throw e; } - this.props.onBuySuccess(buyQuote, txHash); + this.props.onBuySuccess(buyQuote, txHash, startTimeUnix, expectedEndTimeUnix); }; } diff --git a/packages/instant/src/components/buy_order_state_buttons.tsx b/packages/instant/src/components/buy_order_state_buttons.tsx index d01e9ff57..6f197a772 100644 --- a/packages/instant/src/components/buy_order_state_buttons.tsx +++ b/packages/instant/src/components/buy_order_state_buttons.tsx @@ -6,6 +6,7 @@ import { SecondaryButton } from '../components/secondary_button'; import { Flex } from '../components/ui/flex'; import { PlacingOrderButton } from '../components/placing_order_button'; +import { SimulatedProgressBar } from '../components/simulated_progress_bar'; import { ColorOption } from '../style/theme'; import { OrderProcessState, ZeroExInstantError } from '../types'; @@ -20,10 +21,13 @@ export interface BuyOrderStateButtonProps { onValidationPending: (buyQuote: BuyQuote) => void; onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void; onSignatureDenied: (buyQuote: BuyQuote) => void; - onBuyProcessing: (buyQuote: BuyQuote, txHash: string) => void; - onBuySuccess: (buyQuote: BuyQuote, txHash: string) => void; - onBuyFailure: (buyQuote: BuyQuote, txHash: string) => void; + onBuyProcessing: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => void; + onBuySuccess: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => void; + onBuyFailure: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => void; onRetry: () => void; + + // TODO: dont commit! + secondaryProgressDemo: () => void; } // TODO: rename to buttons @@ -50,16 +54,25 @@ export const BuyOrderStateButtons: React.StatelessComponent; } + const curTime = new Date().getTime(); + const expectedEndTime = curTime + 5000; return ( - +
+ {/*
+ +
*/} + + New progress bar demo + +
); }; diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index e099044df..12e592ae8 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -5,6 +5,7 @@ export const DEFAULT_ZERO_EX_CONTAINER_SELECTOR = '#zeroExInstantContainer'; export const WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX = 'Transaction failed'; export const GWEI_IN_WEI = new BigNumber(1000000000); export const DEFAULT_GAS_PRICE = GWEI_IN_WEI.mul(6); +export const DEFAULT_ESTIMATED_TRANSACTION_TIME_MS = 2 * 60 * 1000; // 2 minutes export const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info'; export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2'; export const PROGRESS_TICK_INTERVAL_MS = 100; diff --git a/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts index 3750e5219..5cfd1ff6c 100644 --- a/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts +++ b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts @@ -21,11 +21,12 @@ interface ConnectedState { interface ConnectedDispatch { onValidationPending: (buyQuote: BuyQuote) => void; onSignatureDenied: (buyQuote: BuyQuote) => void; - onBuyProcessing: (buyQuote: BuyQuote, txHash: string, estimatedTimeMs?: number) => void; - onBuySuccess: (buyQuote: BuyQuote, txHash: string) => void; - onBuyFailure: (buyQuote: BuyQuote, txHash: string) => void; + onBuyProcessing: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => void; + onBuySuccess: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => void; + onBuyFailure: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => void; onRetry: () => void; onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void; + secondaryProgressDemo: () => void; } export interface SelectedAssetBuyOrderStateButtons {} const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyOrderStateButtons): ConnectedState => ({ @@ -59,14 +60,42 @@ const mapDispatchToProps = ( const newOrderState: OrderState = { processState: OrderProcessState.VALIDATING }; dispatch(actions.updateBuyOrderState(newOrderState)); }, - onBuyProcessing: (buyQuote: BuyQuote, txHash: string, estimatedTimeMs?: number) => { - const newOrderState: OrderState = { processState: OrderProcessState.PROCESSING, txHash, estimatedTimeMs }; + onBuyProcessing: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => { + const newOrderState: OrderState = { + processState: OrderProcessState.PROCESSING, + txHash, + progress: { + startTimeUnix, + expectedEndTimeUnix, + ended: false, + }, + }; dispatch(actions.updateBuyOrderState(newOrderState)); }, - onBuySuccess: (buyQuote: BuyQuote, txHash: string) => - dispatch(actions.updateBuyOrderState({ processState: OrderProcessState.SUCCESS, txHash })), - onBuyFailure: (buyQuote: BuyQuote, txHash: string) => - dispatch(actions.updateBuyOrderState({ processState: OrderProcessState.FAILURE, txHash })), + onBuySuccess: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => + dispatch( + actions.updateBuyOrderState({ + processState: OrderProcessState.SUCCESS, + txHash, + progress: { + startTimeUnix, + expectedEndTimeUnix, + ended: true, + }, + }), + ), + onBuyFailure: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => + dispatch( + actions.updateBuyOrderState({ + processState: OrderProcessState.FAILURE, + txHash, + progress: { + startTimeUnix, + expectedEndTimeUnix, + ended: true, + }, + }), + ), onSignatureDenied: () => { dispatch(actions.resetAmount()); const errorMessage = 'You denied this transaction'; @@ -84,6 +113,29 @@ const mapDispatchToProps = ( onRetry: () => { dispatch(actions.resetAmount()); }, + secondaryProgressDemo: () => { + const nowTime = new Date().getTime(); + const futureTime = nowTime + 5000; + dispatch( + actions.updateSimulatedOrderProgress({ + startTimeUnix: nowTime, + expectedEndTimeUnix: futureTime, + ended: false, + }), + ); + + window.setTimeout(() => { + console.log('simulate finishing'); + + dispatch( + actions.updateSimulatedOrderProgress({ + startTimeUnix: nowTime, + expectedEndTimeUnix: futureTime, + ended: true, + }), + ); + }, 2000); + }, }); export const SelectedAssetBuyOrderStateButtons: React.ComponentClass = connect( diff --git a/packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx b/packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx index 1ddb4ae66..adb5daad8 100644 --- a/packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx +++ b/packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx @@ -9,27 +9,23 @@ import { OrderProcessState, OrderState, SimulatedProgress } from '../types'; interface SelectedAssetProgressComponentProps { buyOrderState: OrderState; - simulatedProgress?: SimulatedProgress; } export const SelectedAssetSimulatedProgressComponent: React.StatelessComponent< SelectedAssetProgressComponentProps > = props => { - const { buyOrderState, simulatedProgress } = props; - - console.log('simulatedProgress', simulatedProgress); - - // TODO: uncomment after done testing - // const isOrderStateOk = - // buyOrderState.processState === OrderProcessState.PROCESSING || - // buyOrderState.processState === OrderProcessState.SUCCESS; - const isOrderStateOk = true; - - if (isOrderStateOk && simulatedProgress) { + const { buyOrderState } = props; + + if ( + buyOrderState.processState === OrderProcessState.PROCESSING || + buyOrderState.processState === OrderProcessState.SUCCESS || + buyOrderState.processState === OrderProcessState.FAILURE + ) { + const progress = buyOrderState.progress; return ( ); } diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts index 58d6692e4..34893676d 100644 --- a/packages/instant/src/types.ts +++ b/packages/instant/src/types.ts @@ -28,8 +28,7 @@ interface OrderStatePreTx { interface OrderStatePostTx { processState: OrderProcessState.PROCESSING | OrderProcessState.SUCCESS | OrderProcessState.FAILURE; txHash: string; - // TODO: move/rename? - estimatedTimeMs?: number; + progress: SimulatedProgress; } export type OrderState = OrderStatePreTx | OrderStatePostTx; -- cgit v1.2.3 From 9787d1085da225ac3180983065f63d26a6bab3e6 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 30 Oct 2018 16:43:58 -0700 Subject: Get rid of old demo --- .../src/components/buy_order_state_buttons.tsx | 11 ---------- .../selected_asset_buy_order_state_buttons.ts | 24 ---------------------- .../selected_asset_simulated_progress_bar.tsx | 1 - packages/instant/src/redux/actions.ts | 3 --- packages/instant/src/redux/reducer.ts | 6 ------ 5 files changed, 45 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/buy_order_state_buttons.tsx b/packages/instant/src/components/buy_order_state_buttons.tsx index 6f197a772..df1664cd9 100644 --- a/packages/instant/src/components/buy_order_state_buttons.tsx +++ b/packages/instant/src/components/buy_order_state_buttons.tsx @@ -25,12 +25,8 @@ export interface BuyOrderStateButtonProps { onBuySuccess: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => void; onBuyFailure: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => void; onRetry: () => void; - - // TODO: dont commit! - secondaryProgressDemo: () => void; } -// TODO: rename to buttons export const BuyOrderStateButtons: React.StatelessComponent = props => { if (props.buyOrderProcessingState === OrderProcessState.FAILURE) { return ( @@ -54,15 +50,8 @@ export const BuyOrderStateButtons: React.StatelessComponent; } - const curTime = new Date().getTime(); - const expectedEndTime = curTime + 5000; return (
- {/*
- -
*/} - - New progress bar demo void; onRetry: () => void; onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void; - secondaryProgressDemo: () => void; } export interface SelectedAssetBuyOrderStateButtons {} const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyOrderStateButtons): ConnectedState => ({ @@ -113,29 +112,6 @@ const mapDispatchToProps = ( onRetry: () => { dispatch(actions.resetAmount()); }, - secondaryProgressDemo: () => { - const nowTime = new Date().getTime(); - const futureTime = nowTime + 5000; - dispatch( - actions.updateSimulatedOrderProgress({ - startTimeUnix: nowTime, - expectedEndTimeUnix: futureTime, - ended: false, - }), - ); - - window.setTimeout(() => { - console.log('simulate finishing'); - - dispatch( - actions.updateSimulatedOrderProgress({ - startTimeUnix: nowTime, - expectedEndTimeUnix: futureTime, - ended: true, - }), - ); - }, 2000); - }, }); export const SelectedAssetBuyOrderStateButtons: React.ComponentClass = connect( diff --git a/packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx b/packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx index adb5daad8..a7acc4cb7 100644 --- a/packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx +++ b/packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx @@ -39,6 +39,5 @@ interface ConnectedState { } const mapStateToProps = (state: State, _ownProps: {}): ConnectedState => ({ buyOrderState: state.buyOrderState, - simulatedProgress: state.simulatedProgress, }); export const SelectedAssetSimulatedProgressBar = connect(mapStateToProps)(SelectedAssetSimulatedProgressComponent); diff --git a/packages/instant/src/redux/actions.ts b/packages/instant/src/redux/actions.ts index c27c188bf..61c273510 100644 --- a/packages/instant/src/redux/actions.ts +++ b/packages/instant/src/redux/actions.ts @@ -28,7 +28,6 @@ export enum ActionTypes { UPDATE_BUY_ORDER_STATE = 'UPDATE_BUY_ORDER_STATE', UPDATE_LATEST_BUY_QUOTE = 'UPDATE_LATEST_BUY_QUOTE', UPDATE_SELECTED_ASSET = 'UPDATE_SELECTED_ASSET', - UPDATE_SIMULATED_ORDER_PROGRESS = 'UPDATE_SIMULATED_ORDER_PROGRESS', SET_QUOTE_REQUEST_STATE_PENDING = 'SET_QUOTE_REQUEST_STATE_PENDING', SET_QUOTE_REQUEST_STATE_FAILURE = 'SET_QUOTE_REQUEST_STATE_FAILURE', SET_ERROR_MESSAGE = 'SET_ERROR_MESSAGE', @@ -44,8 +43,6 @@ export const actions = { 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), - updateSimulatedOrderProgress: (orderProgress: SimulatedProgress) => - createAction(ActionTypes.UPDATE_SIMULATED_ORDER_PROGRESS, orderProgress), setQuoteRequestStatePending: () => createAction(ActionTypes.SET_QUOTE_REQUEST_STATE_PENDING), setQuoteRequestStateFailure: () => createAction(ActionTypes.SET_QUOTE_REQUEST_STATE_FAILURE), setErrorMessage: (errorMessage: string) => createAction(ActionTypes.SET_ERROR_MESSAGE, errorMessage), diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index 3540bd4eb..35c0ceee6 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -32,7 +32,6 @@ export interface State { quoteRequestState: AsyncProcessState; latestErrorMessage?: string; latestErrorDisplayStatus: DisplayStatus; - simulatedProgress?: SimulatedProgress; } export const INITIAL_STATE: State = { @@ -121,11 +120,6 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State => ...state, selectedAsset: newSelectedAsset, }; - case ActionTypes.UPDATE_SIMULATED_ORDER_PROGRESS: - return { - ...state, - simulatedProgress: action.data, - }; case ActionTypes.RESET_AMOUNT: return { ...state, -- cgit v1.2.3 From 0e1e9b27f6f5b93e1f9b0e2833bc600836f8e757 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 30 Oct 2018 16:45:04 -0700 Subject: Takeout unneeded div --- .../src/components/buy_order_state_buttons.tsx | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/buy_order_state_buttons.tsx b/packages/instant/src/components/buy_order_state_buttons.tsx index df1664cd9..4a6b467d2 100644 --- a/packages/instant/src/components/buy_order_state_buttons.tsx +++ b/packages/instant/src/components/buy_order_state_buttons.tsx @@ -51,17 +51,15 @@ export const BuyOrderStateButtons: React.StatelessComponent - -
+ ); }; -- cgit v1.2.3 From 229f11f164ce5109b771295d9aee8ebb74314181 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 30 Oct 2018 20:18:21 -0700 Subject: Nice formatting of displayed time --- .../src/components/simulated_progress_bar.tsx | 9 ++-- packages/instant/src/util/time.ts | 39 ++++++++++++++++++ packages/instant/test/util/time.test.ts | 48 ++++++++++++++++++++++ 3 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 packages/instant/src/util/time.ts create mode 100644 packages/instant/test/util/time.test.ts (limited to 'packages') diff --git a/packages/instant/src/components/simulated_progress_bar.tsx b/packages/instant/src/components/simulated_progress_bar.tsx index e9e547cbe..e4b08db8c 100644 --- a/packages/instant/src/components/simulated_progress_bar.tsx +++ b/packages/instant/src/components/simulated_progress_bar.tsx @@ -1,11 +1,9 @@ import * as _ from 'lodash'; import * as React from 'react'; -import { Dispatch } from 'redux'; import { PROGRESS_STALL_AT_PERCENTAGE, PROGRESS_TICK_INTERVAL_MS } from '../constants'; -import { Action, actions } from '../redux/actions'; - import { ColorOption } from '../style/theme'; +import { timeUtil } from '../util/time'; import { Container } from './ui/container'; import { Flex } from './ui/flex'; @@ -106,9 +104,8 @@ export class SimulatedProgressBar extends React.Component {/* TODO: consider moving to separate component */} - {/* TODO: should do nice display of these (i.e. 'minutes' and 00:xx) */} - Est. Time ({estimatedTimeSeconds} seconds) - Time: {elapsedTimeSeconds} + Est. Time ({timeUtil.secondsToHumanDescription(estimatedTimeSeconds)}) + Time: {timeUtil.secondsToStopwatchTime(elapsedTimeSeconds)}
diff --git a/packages/instant/src/util/time.ts b/packages/instant/src/util/time.ts new file mode 100644 index 000000000..bfe69cad5 --- /dev/null +++ b/packages/instant/src/util/time.ts @@ -0,0 +1,39 @@ +const secondsToMinutesAndRemainingSeconds = (seconds: number): { minutes: number; remainingSeconds: number } => { + const minutes = Math.floor(seconds / 60); + const remainingSeconds = seconds - minutes * 60; + + return { + minutes, + remainingSeconds, + }; +}; + +const padZero = (aNumber: number): string => { + return aNumber < 10 ? `0${aNumber}` : aNumber.toString(); +}; + +export const timeUtil = { + // converts seconds to human readable version of seconds or minutes + secondsToHumanDescription: (seconds: number): string => { + const { minutes, remainingSeconds } = secondsToMinutesAndRemainingSeconds(seconds); + + if (minutes === 0) { + const suffix = seconds > 1 ? 's' : ''; + return `${seconds} second${suffix}`; + } + + const minuteSuffix = minutes > 1 ? 's' : ''; + const minuteText = `${minutes} minute${minuteSuffix}`; + + const secondsSuffix = remainingSeconds > 1 ? 's' : ''; + const secondsText = remainingSeconds === 0 ? '' : ` ${remainingSeconds} second${secondsSuffix}`; + + return `${minuteText}${secondsText}`; + }, + // converts seconds to stopwatch time (i.e. 05:30 and 00:30) + // only goes up to minutes, not hours + secondsToStopwatchTime: (seconds: number): string => { + const { minutes, remainingSeconds } = secondsToMinutesAndRemainingSeconds(seconds); + return `${padZero(minutes)}:${padZero(remainingSeconds)}`; + }, +}; diff --git a/packages/instant/test/util/time.test.ts b/packages/instant/test/util/time.test.ts new file mode 100644 index 000000000..7165761de --- /dev/null +++ b/packages/instant/test/util/time.test.ts @@ -0,0 +1,48 @@ +import { timeUtil } from '../../src/util/time'; + +describe('assetDataUtil', () => { + describe('secondsToHumanDescription', () => { + const numsToResults: { + [aNumber: number]: string; + } = { + 1: '1 second', + 59: '59 seconds', + 60: '1 minute', + 119: '1 minute 59 seconds', + 120: '2 minutes', + 121: '2 minutes 1 second', + 122: '2 minutes 2 seconds', + }; + + const nums = Object.keys(numsToResults); + nums.forEach(aNum => { + const numInt = parseInt(aNum, 10); + it(`should work for ${aNum} seconds`, () => { + const expectedResult = numsToResults[numInt]; + expect(timeUtil.secondsToHumanDescription(numInt)).toEqual(expectedResult); + }); + }); + }); + describe('secondsToStopwatchTime', () => { + const numsToResults: { + [aNumber: number]: string; + } = { + 1: '00:01', + 59: '00:59', + 60: '01:00', + 119: '01:59', + 120: '02:00', + 121: '02:01', + 2701: '45:01', + }; + + const nums = Object.keys(numsToResults); + nums.forEach(aNum => { + const numInt = parseInt(aNum, 10); + it(`should work for ${aNum} seconds`, () => { + const expectedResult = numsToResults[numInt]; + expect(timeUtil.secondsToStopwatchTime(numInt)).toEqual(expectedResult); + }); + }); + }); +}); -- cgit v1.2.3 From 9a5b52036b8765a6de464d8c6294b46ebcfd604e Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 31 Oct 2018 08:14:44 -0700 Subject: Tick less often, and let CSS style the transition --- .../src/components/simulated_progress_bar.tsx | 26 +++++++++++++++++++--- packages/instant/src/constants.ts | 2 +- 2 files changed, 24 insertions(+), 4 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/simulated_progress_bar.tsx b/packages/instant/src/components/simulated_progress_bar.tsx index e4b08db8c..067f4093e 100644 --- a/packages/instant/src/components/simulated_progress_bar.tsx +++ b/packages/instant/src/components/simulated_progress_bar.tsx @@ -2,7 +2,7 @@ import * as _ from 'lodash'; import * as React from 'react'; import { PROGRESS_STALL_AT_PERCENTAGE, PROGRESS_TICK_INTERVAL_MS } from '../constants'; -import { ColorOption } from '../style/theme'; +import { ColorOption, styled } from '../style/theme'; import { timeUtil } from '../util/time'; import { Container } from './ui/container'; @@ -109,11 +109,12 @@ export class SimulatedProgressBar extends React.Component - @@ -172,3 +173,22 @@ export class SimulatedProgressBar extends React.Component + ` + width: ${props => props.percentageDone}%; + background-color: ${props => props.theme[props.backgroundColor]}; + border-radius: ${props => props.borderRadius}; + height: ${props => props.height}; + transition: width ${props => props.transitionTimeMs}ms ease-in-out; + `; diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index 12e592ae8..3b320ed36 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -8,5 +8,5 @@ export const DEFAULT_GAS_PRICE = GWEI_IN_WEI.mul(6); export const DEFAULT_ESTIMATED_TRANSACTION_TIME_MS = 2 * 60 * 1000; // 2 minutes export const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info'; export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2'; -export const PROGRESS_TICK_INTERVAL_MS = 100; +export const PROGRESS_TICK_INTERVAL_MS = 250; export const PROGRESS_STALL_AT_PERCENTAGE = 95; -- cgit v1.2.3 From d938ba46061fc8d0682f356ea9aba16535466455 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 31 Oct 2018 08:37:21 -0700 Subject: Remove unused import --- packages/instant/src/redux/reducer.ts | 1 - 1 file changed, 1 deletion(-) (limited to 'packages') diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index 35c0ceee6..dd9403052 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -13,7 +13,6 @@ import { Network, OrderProcessState, OrderState, - SimulatedProgress, } from '../types'; import { assetUtils } from '../util/asset'; import { BigNumberInput } from '../util/big_number_input'; -- cgit v1.2.3 From d6755472087af76982779728db7424b1171a1b47 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 31 Oct 2018 09:14:50 -0700 Subject: Explicit actions for setting different order states This allows us to dispatch updates with less syntax, and allows us to not have to send in progress info when setting failure and success --- packages/instant/src/components/buy_button.tsx | 9 +-- .../src/components/buy_order_state_buttons.tsx | 5 +- .../selected_asset_buy_order_state_buttons.ts | 46 +++------------- .../selected_erc20_asset_amount_input.ts | 2 +- packages/instant/src/redux/actions.ts | 13 ++++- packages/instant/src/redux/reducer.ts | 64 +++++++++++++++++++++- 6 files changed, 88 insertions(+), 51 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index d10936d05..c00b1678d 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -20,8 +20,8 @@ export interface BuyButtonProps { onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void; onSignatureDenied: (buyQuote: BuyQuote) => void; onBuyProcessing: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => void; - onBuySuccess: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => void; - onBuyFailure: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => void; + onBuySuccess: (buyQuote: BuyQuote, txHash: string) => void; + onBuyFailure: (buyQuote: BuyQuote, txHash: string) => void; } export class BuyButton extends React.Component { @@ -80,11 +80,12 @@ export class BuyButton extends React.Component { await web3Wrapper.awaitTransactionSuccessAsync(txHash); } catch (e) { if (e instanceof Error && e.message.startsWith(WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX)) { - this.props.onBuyFailure(buyQuote, txHash, startTimeUnix, expectedEndTimeUnix); + this.props.onBuyFailure(buyQuote, txHash); return; } throw e; } - this.props.onBuySuccess(buyQuote, txHash, startTimeUnix, expectedEndTimeUnix); + + this.props.onBuySuccess(buyQuote, txHash); }; } diff --git a/packages/instant/src/components/buy_order_state_buttons.tsx b/packages/instant/src/components/buy_order_state_buttons.tsx index 4a6b467d2..3f0764062 100644 --- a/packages/instant/src/components/buy_order_state_buttons.tsx +++ b/packages/instant/src/components/buy_order_state_buttons.tsx @@ -6,7 +6,6 @@ import { SecondaryButton } from '../components/secondary_button'; import { Flex } from '../components/ui/flex'; import { PlacingOrderButton } from '../components/placing_order_button'; -import { SimulatedProgressBar } from '../components/simulated_progress_bar'; import { ColorOption } from '../style/theme'; import { OrderProcessState, ZeroExInstantError } from '../types'; @@ -22,8 +21,8 @@ export interface BuyOrderStateButtonProps { onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void; onSignatureDenied: (buyQuote: BuyQuote) => void; onBuyProcessing: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => void; - onBuySuccess: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => void; - onBuyFailure: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => void; + onBuySuccess: (buyQuote: BuyQuote, txHash: string) => void; + onBuyFailure: (buyQuote: BuyQuote, txHash: string) => void; onRetry: () => void; } diff --git a/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts index 247d57938..a94538ffc 100644 --- a/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts +++ b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts @@ -22,8 +22,8 @@ interface ConnectedDispatch { onValidationPending: (buyQuote: BuyQuote) => void; onSignatureDenied: (buyQuote: BuyQuote) => void; onBuyProcessing: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => void; - onBuySuccess: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => void; - onBuyFailure: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => void; + onBuySuccess: (buyQuote: BuyQuote, txHash: string) => void; + onBuyFailure: (buyQuote: BuyQuote, txHash: string) => void; onRetry: () => void; onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void; } @@ -56,52 +56,20 @@ const mapDispatchToProps = ( ownProps: SelectedAssetBuyOrderStateButtons, ): ConnectedDispatch => ({ onValidationPending: (buyQuote: BuyQuote) => { - const newOrderState: OrderState = { processState: OrderProcessState.VALIDATING }; - dispatch(actions.updateBuyOrderState(newOrderState)); + dispatch(actions.setBuyOrderStateValidating()); }, onBuyProcessing: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => { - const newOrderState: OrderState = { - processState: OrderProcessState.PROCESSING, - txHash, - progress: { - startTimeUnix, - expectedEndTimeUnix, - ended: false, - }, - }; - dispatch(actions.updateBuyOrderState(newOrderState)); + dispatch(actions.setBuyOrderStateProcessing(txHash, startTimeUnix, expectedEndTimeUnix)); }, - onBuySuccess: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => - dispatch( - actions.updateBuyOrderState({ - processState: OrderProcessState.SUCCESS, - txHash, - progress: { - startTimeUnix, - expectedEndTimeUnix, - ended: true, - }, - }), - ), - onBuyFailure: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => - dispatch( - actions.updateBuyOrderState({ - processState: OrderProcessState.FAILURE, - txHash, - progress: { - startTimeUnix, - expectedEndTimeUnix, - ended: true, - }, - }), - ), + onBuySuccess: (buyQuote: BuyQuote, txHash: string) => dispatch(actions.setBuyOrderStateSuccess(txHash)), + onBuyFailure: (buyQuote: BuyQuote, txHash: string) => dispatch(actions.setBuyOrderStateFailure(txHash)), onSignatureDenied: () => { dispatch(actions.resetAmount()); const errorMessage = 'You denied this transaction'; errorFlasher.flashNewErrorMessage(dispatch, errorMessage); }, onValidationFail: (buyQuote, error) => { - dispatch(actions.updateBuyOrderState({ processState: OrderProcessState.NONE })); + dispatch(actions.setBuyOrderStateNone()); if (error === ZeroExInstantError.InsufficientETH) { const errorMessage = "You don't have enough ETH"; errorFlasher.flashNewErrorMessage(dispatch, errorMessage); diff --git a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts index 4767b15d4..c0245f721 100644 --- a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts +++ b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts @@ -113,7 +113,7 @@ const mapDispatchToProps = ( // invalidate the last buy quote. dispatch(actions.updateLatestBuyQuote(undefined)); // reset our buy state - dispatch(actions.updateBuyOrderState({ processState: OrderProcessState.NONE })); + dispatch(actions.setBuyOrderStateNone()); 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/redux/actions.ts b/packages/instant/src/redux/actions.ts index 61c273510..627e39ffc 100644 --- a/packages/instant/src/redux/actions.ts +++ b/packages/instant/src/redux/actions.ts @@ -25,7 +25,11 @@ function createAction(type: T, data?: P): PlainAction | export enum ActionTypes { UPDATE_ETH_USD_PRICE = 'UPDATE_ETH_USD_PRICE', UPDATE_SELECTED_ASSET_AMOUNT = 'UPDATE_SELECTED_ASSET_AMOUNT', - UPDATE_BUY_ORDER_STATE = 'UPDATE_BUY_ORDER_STATE', + SET_BUY_ORDER_STATE_NONE = 'SET_BUY_ORDER_STATE_NONE', + SET_BUY_ORDER_STATE_VALIDATING = 'SET_BUY_ORDER_STATE_VALIDATING', + SET_BUY_ORDER_STATE_PROCESSING = 'SET_BUY_ORDER_STATE_PROCESSING', + SET_BUY_ORDER_STATE_FAILURE = 'SET_BUY_ORDER_STATE_FAILURE', + SET_BUY_ORDER_STATE_SUCCESS = 'SET_BUY_ORDER_STATE_SUCCESS', UPDATE_LATEST_BUY_QUOTE = 'UPDATE_LATEST_BUY_QUOTE', UPDATE_SELECTED_ASSET = 'UPDATE_SELECTED_ASSET', SET_QUOTE_REQUEST_STATE_PENDING = 'SET_QUOTE_REQUEST_STATE_PENDING', @@ -40,7 +44,12 @@ export const actions = { updateEthUsdPrice: (price?: BigNumber) => createAction(ActionTypes.UPDATE_ETH_USD_PRICE, price), updateSelectedAssetAmount: (amount?: BigNumberInput) => createAction(ActionTypes.UPDATE_SELECTED_ASSET_AMOUNT, amount), - updateBuyOrderState: (orderState: OrderState) => createAction(ActionTypes.UPDATE_BUY_ORDER_STATE, orderState), + setBuyOrderStateNone: () => createAction(ActionTypes.SET_BUY_ORDER_STATE_NONE), + setBuyOrderStateValidating: () => createAction(ActionTypes.SET_BUY_ORDER_STATE_VALIDATING), + setBuyOrderStateProcessing: (txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => + createAction(ActionTypes.SET_BUY_ORDER_STATE_PROCESSING, { txHash, startTimeUnix, expectedEndTimeUnix }), + setBuyOrderStateFailure: (txHash: string) => createAction(ActionTypes.SET_BUY_ORDER_STATE_FAILURE, txHash), + setBuyOrderStateSuccess: (txHash: string) => createAction(ActionTypes.SET_BUY_ORDER_STATE_SUCCESS, txHash), 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 dd9403052..11980066b 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -83,11 +83,71 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State => latestBuyQuote: undefined, quoteRequestState: AsyncProcessState.FAILURE, }; - case ActionTypes.UPDATE_BUY_ORDER_STATE: + case ActionTypes.SET_BUY_ORDER_STATE_NONE: return { ...state, - buyOrderState: action.data, + buyOrderState: { processState: OrderProcessState.NONE }, + }; + case ActionTypes.SET_BUY_ORDER_STATE_VALIDATING: + return { + ...state, + buyOrderState: { processState: OrderProcessState.VALIDATING }, }; + case ActionTypes.SET_BUY_ORDER_STATE_PROCESSING: + const processingData = action.data; + const { startTimeUnix, expectedEndTimeUnix } = processingData; + return { + ...state, + buyOrderState: { + processState: OrderProcessState.PROCESSING, + txHash: processingData.txHash, + progress: { + startTimeUnix, + expectedEndTimeUnix, + ended: false, + }, + }, + }; + case ActionTypes.SET_BUY_ORDER_STATE_FAILURE: + const failureTxHash = action.data; + if ('txHash' in state.buyOrderState) { + if (state.buyOrderState.txHash === failureTxHash) { + const failureProgress = { + startTimeUnix: state.buyOrderState.progress.startTimeUnix, + expectedEndTimeUnix: state.buyOrderState.progress.expectedEndTimeUnix, + ended: true, + }; + return { + ...state, + buyOrderState: { + processState: OrderProcessState.FAILURE, + txHash: state.buyOrderState.txHash, + progress: failureProgress, + }, + }; + } + } + return state; + case ActionTypes.SET_BUY_ORDER_STATE_SUCCESS: + const successTxHash = action.data; + if ('txHash' in state.buyOrderState) { + if (state.buyOrderState.txHash === successTxHash) { + const successProgress = { + startTimeUnix: state.buyOrderState.progress.startTimeUnix, + expectedEndTimeUnix: state.buyOrderState.progress.expectedEndTimeUnix, + ended: true, + }; + return { + ...state, + buyOrderState: { + processState: OrderProcessState.SUCCESS, + txHash: state.buyOrderState.txHash, + progress: successProgress, + }, + }; + } + } + return state; case ActionTypes.SET_ERROR_MESSAGE: return { ...state, -- cgit v1.2.3 From cc2719492d72602ecd1c503cf0ecee95cd05db33 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 31 Oct 2018 09:25:18 -0700 Subject: Remove default in state reducer This allows us to ensure that we explicitly handle every action type --- packages/instant/src/redux/reducer.ts | 2 -- packages/instant/tslint.json | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index 11980066b..a3f38c880 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -187,8 +187,6 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State => buyOrderState: { processState: OrderProcessState.NONE }, selectedAssetAmount: undefined, }; - default: - return state; } }; diff --git a/packages/instant/tslint.json b/packages/instant/tslint.json index 08b76be97..d43ee8da7 100644 --- a/packages/instant/tslint.json +++ b/packages/instant/tslint.json @@ -3,6 +3,7 @@ "rules": { "custom-no-magic-numbers": false, "semicolon": [true, "always", "ignore-bound-class-methods"], - "max-classes-per-file": false + "max-classes-per-file": false, + "switch-default": false } } -- cgit v1.2.3 From ad0129fa025012a6a8234db69ee4fa1763d5aff8 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 31 Oct 2018 11:31:55 -0700 Subject: Revert "Remove default in state reducer" This reverts commit cc2719492d72602ecd1c503cf0ecee95cd05db33. --- packages/instant/src/redux/reducer.ts | 2 ++ packages/instant/tslint.json | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index a3f38c880..11980066b 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -187,6 +187,8 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State => buyOrderState: { processState: OrderProcessState.NONE }, selectedAssetAmount: undefined, }; + default: + return state; } }; diff --git a/packages/instant/tslint.json b/packages/instant/tslint.json index d43ee8da7..08b76be97 100644 --- a/packages/instant/tslint.json +++ b/packages/instant/tslint.json @@ -3,7 +3,6 @@ "rules": { "custom-no-magic-numbers": false, "semicolon": [true, "always", "ignore-bound-class-methods"], - "max-classes-per-file": false, - "switch-default": false + "max-classes-per-file": false } } -- cgit v1.2.3 From ae84dac46382258e9a59b194f8aed7184d283e6f Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 31 Oct 2018 16:46:24 -0700 Subject: WIP of new timedprogressbar using CSS animations --- packages/instant/src/components/time_counter.tsx | 64 +++++++++++++ .../instant/src/components/timed_progress_bar.tsx | 101 +++++++++++++++++++++ packages/instant/src/constants.ts | 3 +- .../selected_asset_simulated_progress_bar.tsx | 18 +++- packages/instant/src/types.ts | 1 - 5 files changed, 180 insertions(+), 7 deletions(-) create mode 100644 packages/instant/src/components/time_counter.tsx create mode 100644 packages/instant/src/components/timed_progress_bar.tsx (limited to 'packages') diff --git a/packages/instant/src/components/time_counter.tsx b/packages/instant/src/components/time_counter.tsx new file mode 100644 index 000000000..26deb82bd --- /dev/null +++ b/packages/instant/src/components/time_counter.tsx @@ -0,0 +1,64 @@ +import * as React from 'react'; + +import { timeUtil } from '../util/time'; + +import { Flex } from './ui/flex'; +import { Text } from './ui/text'; + +export interface TimeCounterProps { + estimatedTimeMs: number; + ended: boolean; +} +interface TimeCounterState { + elapsedSeconds: number; +} + +export class TimeCounter extends React.Component { + public state = { + elapsedSeconds: 0, + }; + private _timerId?: number; + + public componentDidMount(): void { + this._setupTimerBasedOnProps(); + } + + public componentWillUnmount(): void { + this._clearTimer(); + } + + public componentDidUpdate(prevProps: TimeCounterProps): void { + if (prevProps.ended !== this.props.ended) { + this._setupTimerBasedOnProps(); + } + } + + public render(): React.ReactNode { + const estimatedTimeSeconds = this.props.estimatedTimeMs / 1000; + return ( + + Est. Time ({timeUtil.secondsToHumanDescription(estimatedTimeSeconds)}) + Time: {timeUtil.secondsToStopwatchTime(this.state.elapsedSeconds)} + + ); + } + + private _setupTimerBasedOnProps(): void { + this.props.ended ? this._clearTimer() : this._newTimer(); + } + + private _newTimer(): void { + this._clearTimer(); + this._timerId = window.setInterval(() => { + this.setState({ + elapsedSeconds: this.state.elapsedSeconds + 1, + }); + }, 1000); + } + + private _clearTimer(): void { + if (this._timerId) { + window.clearInterval(this._timerId); + } + } +} diff --git a/packages/instant/src/components/timed_progress_bar.tsx b/packages/instant/src/components/timed_progress_bar.tsx new file mode 100644 index 000000000..7fdfe1a25 --- /dev/null +++ b/packages/instant/src/components/timed_progress_bar.tsx @@ -0,0 +1,101 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import { Keyframes } from 'styled-components'; + +import { PROGRESS_FINISH_ANIMATION_TIME_MS, PROGRESS_STALL_AT_PERCENTAGE } from '../constants'; +import { ColorOption, keyframes, styled } from '../style/theme'; +import { timeUtil } from '../util/time'; + +import { Container } from './ui/container'; +import { Flex } from './ui/flex'; +import { Text } from './ui/text'; + +export interface TimedProgressBarProps { + expectedTimeMs: number; + ended: boolean; +} + +interface TimedProgressBarState { + animationTimeMs: number; + animationStartingWidth: string; + maxWidthPercent: number; +} + +export const beginningState = (props: TimedProgressBarProps): TimedProgressBarState => { + return { + animationTimeMs: props.expectedTimeMs, + animationStartingWidth: '0%', + maxWidthPercent: PROGRESS_STALL_AT_PERCENTAGE, + }; +}; + +export class TimedProgressBar extends React.Component { + private readonly _barRef = React.createRef(); + + public constructor(props: TimedProgressBarProps) { + super(props); + this.state = beginningState(props); + } + + public componentDidUpdate(prevProps: TimedProgressBarProps, prevState: TimedProgressBarState): void { + if (prevProps.ended === false && this.props.ended === true) { + // Show nice animation going to end + // barRef current should always exist, but checking for typesafety + if (this._barRef.current) { + const curProgressWidth = this._barRef.current.offsetWidth; + this.setState({ + animationTimeMs: PROGRESS_FINISH_ANIMATION_TIME_MS, + animationStartingWidth: `${curProgressWidth}px`, + maxWidthPercent: 100, + }); + } + return; + } + + if (prevProps.expectedTimeMs !== this.props.expectedTimeMs || prevProps.ended !== this.props.ended) { + // things changed, get fresh state + this.setState(beginningState(this.props)); + } + } + + public render(): React.ReactNode { + return ( + + + + ); + } +} + +const expandingWidthKeyframes = (fromWidth: string, maxWidthPercent: number) => { + return keyframes` + from { + width: ${fromWidth} + } + to { + width: ${maxWidthPercent}%; + } + `; +}; + +interface TimedProgressProps { + timeMs: number; + fromWidth: string; + maxWidthPercent: number; +} +// TODO use PrimaryColor instead of black +export const TimedProgress = + styled.div < + TimedProgressProps > + ` + background-color: black; + border-radius: 6px; + height: 6px; + animation: ${props => expandingWidthKeyframes(props.fromWidth, props.maxWidthPercent)} + ${props => props.timeMs}ms linear 1 forwards; + `; diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index 3b320ed36..9fdbf2830 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -8,5 +8,6 @@ export const DEFAULT_GAS_PRICE = GWEI_IN_WEI.mul(6); export const DEFAULT_ESTIMATED_TRANSACTION_TIME_MS = 2 * 60 * 1000; // 2 minutes export const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info'; export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2'; -export const PROGRESS_TICK_INTERVAL_MS = 250; +export const PROGRESS_TICK_INTERVAL_MS = 250; // TODO: remove export const PROGRESS_STALL_AT_PERCENTAGE = 95; +export const PROGRESS_FINISH_ANIMATION_TIME_MS = 200; diff --git a/packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx b/packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx index a7acc4cb7..a989407d5 100644 --- a/packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx +++ b/packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx @@ -3,10 +3,15 @@ import * as React from 'react'; import { connect } from 'react-redux'; import { SimulatedProgressBar } from '../components/simulated_progress_bar'; +import { TimedProgressBar } from '../components/timed_progress_bar'; +import { TimeCounter } from '../components/time_counter'; +import { Container } from '../components/ui'; import { State } from '../redux/reducer'; import { OrderProcessState, OrderState, SimulatedProgress } from '../types'; +// TODO: rename this +// TODO: delete SimulatedProgressBar code and anything else remaining interface SelectedAssetProgressComponentProps { buyOrderState: OrderState; } @@ -21,12 +26,15 @@ export const SelectedAssetSimulatedProgressComponent: React.StatelessComponent< buyOrderState.processState === OrderProcessState.FAILURE ) { const progress = buyOrderState.progress; + const ended = buyOrderState.processState !== OrderProcessState.PROCESSING; + const expectedTimeMs = progress.expectedEndTimeUnix - progress.startTimeUnix; return ( - + + + + + + ); } diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts index 34893676d..288a6d111 100644 --- a/packages/instant/src/types.ts +++ b/packages/instant/src/types.ts @@ -19,7 +19,6 @@ export enum OrderProcessState { export interface SimulatedProgress { startTimeUnix: number; expectedEndTimeUnix: number; - ended: boolean; } interface OrderStatePreTx { -- cgit v1.2.3 From 096f9deceedabff7fe90a7781271f55dfa059e1f Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 31 Oct 2018 16:49:41 -0700 Subject: Removing old simulated progress bar, and adding documentation to TimedProgressBar --- .../src/components/simulated_progress_bar.tsx | 194 --------------------- .../instant/src/components/timed_progress_bar.tsx | 9 +- packages/instant/src/constants.ts | 1 - .../selected_asset_simulated_progress_bar.tsx | 2 - 4 files changed, 5 insertions(+), 201 deletions(-) delete mode 100644 packages/instant/src/components/simulated_progress_bar.tsx (limited to 'packages') diff --git a/packages/instant/src/components/simulated_progress_bar.tsx b/packages/instant/src/components/simulated_progress_bar.tsx deleted file mode 100644 index 067f4093e..000000000 --- a/packages/instant/src/components/simulated_progress_bar.tsx +++ /dev/null @@ -1,194 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; - -import { PROGRESS_STALL_AT_PERCENTAGE, PROGRESS_TICK_INTERVAL_MS } from '../constants'; -import { ColorOption, styled } from '../style/theme'; -import { timeUtil } from '../util/time'; - -import { Container } from './ui/container'; -import { Flex } from './ui/flex'; -import { Text } from './ui/text'; - -const TICKS_PER_SECOND = 1000 / PROGRESS_TICK_INTERVAL_MS; - -const curTimeUnix = () => { - return new Date().getTime(); -}; - -export interface SimulatedProgressBarProps { - startTimeUnix: number; - expectedEndTimeUnix: number; - ended: boolean; -} -enum TickingRunState { - None = 'None', - Running = 'Running', - Finishing = 'Finishing', -} -interface TickingNoneStatus { - runState: TickingRunState.None; -} -interface TickingRunningStatus { - runState: TickingRunState.Running; -} -interface TickingFinishingStatus { - runState: TickingRunState.Finishing; - increasePercentageEveryTick: number; -} -type TickingStatus = TickingNoneStatus | TickingRunningStatus | TickingFinishingStatus; - -export interface SimulatedProgressState { - percentageDone: number; - intervalId?: number; - tickingStatus: TickingStatus; - elapsedTimeMs: number; -} -export class SimulatedProgressBar extends React.Component { - public constructor(props: SimulatedProgressBarProps) { - super(props); - - // TODO: look into using assert library here? - if (props.expectedEndTimeUnix <= props.startTimeUnix) { - throw new Error('End time before start time'); - } - - // TODO: use getFreshState here - const intervalId = window.setInterval(this._tick.bind(this), PROGRESS_TICK_INTERVAL_MS); - this.state = { - percentageDone: 0, - intervalId, - tickingStatus: { runState: TickingRunState.Running }, - elapsedTimeMs: 0, - }; - } - - public componentDidUpdate(prevProps: SimulatedProgressBarProps, prevState: SimulatedProgressState): void { - const percentLeft = 100 - this.state.percentageDone; - const increasePercentageEveryTick = percentLeft / TICKS_PER_SECOND; - - // if we just switched to ending, having animate to end - if (prevProps.ended === false && this.props.ended === true) { - this.setState({ - tickingStatus: { - runState: TickingRunState.Finishing, - increasePercentageEveryTick, - }, - }); - return; - } - - // later TODO: the new state could be for the wrong order, attach to order state or add concurrency checking - - // if anything else changes, reset internal state - if ( - prevProps.startTimeUnix !== this.props.startTimeUnix || - prevProps.expectedEndTimeUnix !== this.props.expectedEndTimeUnix || - prevProps.ended !== this.props.ended - ) { - this.setState(this._getFreshState()); - } - } - - public componentWillUnmount(): void { - console.log('unmount'); - this._clearTimer(); - } - - public render(): React.ReactNode { - // TODO: Consider moving to seperate component - - const estimatedTimeSeconds = Math.ceil((this.props.expectedEndTimeUnix - this.props.startTimeUnix) / 1000); - const elapsedTimeSeconds = Math.floor(this.state.elapsedTimeMs / 1000); - return ( - - - {/* TODO: consider moving to separate component */} - - Est. Time ({timeUtil.secondsToHumanDescription(estimatedTimeSeconds)}) - Time: {timeUtil.secondsToStopwatchTime(elapsedTimeSeconds)} - - - - - - - ); - } - - private _getFreshState(): SimulatedProgressState { - this._clearTimer(); - const intervalId = window.setInterval(this._tick.bind(this), PROGRESS_TICK_INTERVAL_MS); - return { - percentageDone: 0, - intervalId, - tickingStatus: { runState: TickingRunState.Running }, - elapsedTimeMs: 0, - }; - } - - private _tick(): void { - const rawPercentageDone = - this.state.tickingStatus.runState === TickingRunState.Finishing - ? this._getNewPercentageFinishing(this.state.tickingStatus) - : this._getNewPercentageNormal(); - const maxPercentage = - this.state.tickingStatus.runState === TickingRunState.Finishing ? 100 : PROGRESS_STALL_AT_PERCENTAGE; - const percentageDone = Math.min(rawPercentageDone, maxPercentage); - - const elapsedTimeMs = Math.max(curTimeUnix() - this.props.startTimeUnix, 0); - - this.setState({ - percentageDone, - elapsedTimeMs, - }); - - if (percentageDone >= 100) { - this._clearTimer(); - } - } - - private _clearTimer(): void { - if (this.state.intervalId) { - window.clearTimeout(this.state.intervalId); - } - } - - // TODO: consider not taking in a parameter here, might be confusing - private _getNewPercentageFinishing(tickingStatus: TickingFinishingStatus): number { - return this.state.percentageDone + tickingStatus.increasePercentageEveryTick; - } - - private _getNewPercentageNormal(): number { - const elapsedTimeMs = curTimeUnix() - this.props.startTimeUnix; - const safeElapsedTimeMs = Math.max(elapsedTimeMs, 1); - - const expectedAmountOfTimeMs = this.props.expectedEndTimeUnix - this.props.startTimeUnix; - const percentageDone = safeElapsedTimeMs / expectedAmountOfTimeMs * 100; - return percentageDone; - } -} - -interface InnerProgressBarElementProps { - percentageDone: number; - backgroundColor: ColorOption; - borderRadius: string; - height: string; - transitionTimeMs: number; -} - -export const InnerProgressBarElement = - styled.div < - InnerProgressBarElementProps > - ` - width: ${props => props.percentageDone}%; - background-color: ${props => props.theme[props.backgroundColor]}; - border-radius: ${props => props.borderRadius}; - height: ${props => props.height}; - transition: width ${props => props.transitionTimeMs}ms ease-in-out; - `; diff --git a/packages/instant/src/components/timed_progress_bar.tsx b/packages/instant/src/components/timed_progress_bar.tsx index 7fdfe1a25..a4bb2eabd 100644 --- a/packages/instant/src/components/timed_progress_bar.tsx +++ b/packages/instant/src/components/timed_progress_bar.tsx @@ -1,14 +1,10 @@ import * as _ from 'lodash'; import * as React from 'react'; -import { Keyframes } from 'styled-components'; import { PROGRESS_FINISH_ANIMATION_TIME_MS, PROGRESS_STALL_AT_PERCENTAGE } from '../constants'; import { ColorOption, keyframes, styled } from '../style/theme'; -import { timeUtil } from '../util/time'; import { Container } from './ui/container'; -import { Flex } from './ui/flex'; -import { Text } from './ui/text'; export interface TimedProgressBarProps { expectedTimeMs: number; @@ -29,6 +25,11 @@ export const beginningState = (props: TimedProgressBarProps): TimedProgressBarSt }; }; +/** + * Timed Progress Bar + * Goes from 0% -> PROGRESS_STALL_AT_PERCENTAGE% over time of expectedTimeMs + * When ended set to true, goes to 100% through animation of PROGRESS_FINISH_ANIMATION_TIME_MS length + */ export class TimedProgressBar extends React.Component { private readonly _barRef = React.createRef(); diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index 9fdbf2830..fcf6e0798 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -8,6 +8,5 @@ export const DEFAULT_GAS_PRICE = GWEI_IN_WEI.mul(6); export const DEFAULT_ESTIMATED_TRANSACTION_TIME_MS = 2 * 60 * 1000; // 2 minutes export const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info'; export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2'; -export const PROGRESS_TICK_INTERVAL_MS = 250; // TODO: remove export const PROGRESS_STALL_AT_PERCENTAGE = 95; export const PROGRESS_FINISH_ANIMATION_TIME_MS = 200; diff --git a/packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx b/packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx index a989407d5..ceab61175 100644 --- a/packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx +++ b/packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx @@ -2,7 +2,6 @@ import * as React from 'react'; import { connect } from 'react-redux'; -import { SimulatedProgressBar } from '../components/simulated_progress_bar'; import { TimedProgressBar } from '../components/timed_progress_bar'; import { TimeCounter } from '../components/time_counter'; @@ -11,7 +10,6 @@ import { State } from '../redux/reducer'; import { OrderProcessState, OrderState, SimulatedProgress } from '../types'; // TODO: rename this -// TODO: delete SimulatedProgressBar code and anything else remaining interface SelectedAssetProgressComponentProps { buyOrderState: OrderState; } -- cgit v1.2.3 From d192a7d466a6bda72ff69360454df547958601e4 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 31 Oct 2018 16:49:52 -0700 Subject: Removing old extra param --- packages/instant/src/redux/reducer.ts | 1 - 1 file changed, 1 deletion(-) (limited to 'packages') diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index 11980066b..68b788be5 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -104,7 +104,6 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State => progress: { startTimeUnix, expectedEndTimeUnix, - ended: false, }, }, }; -- cgit v1.2.3 From 906909e33fe97d49196696c528c131c1a1c66f14 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 31 Oct 2018 16:54:52 -0700 Subject: Rename to SelectedAssetProgress --- .../src/components/zero_ex_instant_container.tsx | 4 +- .../src/containers/selected_asset_progress.tsx | 49 ++++++++++++++++++++++ .../selected_asset_simulated_progress_bar.tsx | 49 ---------------------- 3 files changed, 51 insertions(+), 51 deletions(-) create mode 100644 packages/instant/src/containers/selected_asset_progress.tsx delete mode 100644 packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx (limited to 'packages') diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 6b1042668..87a7cee88 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -5,7 +5,7 @@ import { LatestError } from '../containers/latest_error'; import { SelectedAssetBuyOrderStateButtons } from '../containers/selected_asset_buy_order_state_buttons'; import { SelectedAssetInstantHeading } from '../containers/selected_asset_instant_heading'; -import { SelectedAssetSimulatedProgressBar } from '../containers/selected_asset_simulated_progress_bar'; +import { SelectedAssetProgress } from '../containers/selected_asset_progress'; import { ColorOption } from '../style/theme'; @@ -26,7 +26,7 @@ export const ZeroExInstantContainer: React.StatelessComponent - + diff --git a/packages/instant/src/containers/selected_asset_progress.tsx b/packages/instant/src/containers/selected_asset_progress.tsx new file mode 100644 index 000000000..afbb45dac --- /dev/null +++ b/packages/instant/src/containers/selected_asset_progress.tsx @@ -0,0 +1,49 @@ +import * as React from 'react'; + +import { connect } from 'react-redux'; + +import { TimedProgressBar } from '../components/timed_progress_bar'; + +import { TimeCounter } from '../components/time_counter'; +import { Container } from '../components/ui'; +import { State } from '../redux/reducer'; +import { OrderProcessState, OrderState, SimulatedProgress } from '../types'; + +interface SelectedAssetProgressComponentProps { + buyOrderState: OrderState; +} +// TODO: rename this component and move to seperate file, and get props using mapStateToProps +export const SelectedAssetSimulatedProgressComponent: React.StatelessComponent< + SelectedAssetProgressComponentProps +> = props => { + const { buyOrderState } = props; + + if ( + buyOrderState.processState === OrderProcessState.PROCESSING || + buyOrderState.processState === OrderProcessState.SUCCESS || + buyOrderState.processState === OrderProcessState.FAILURE + ) { + const progress = buyOrderState.progress; + const ended = buyOrderState.processState !== OrderProcessState.PROCESSING; + const expectedTimeMs = progress.expectedEndTimeUnix - progress.startTimeUnix; + return ( + + + + + + + ); + } + + return null; +}; + +interface ConnectedState { + buyOrderState: OrderState; + simulatedProgress?: SimulatedProgress; +} +const mapStateToProps = (state: State, _ownProps: {}): ConnectedState => ({ + buyOrderState: state.buyOrderState, +}); +export const SelectedAssetProgress = connect(mapStateToProps)(SelectedAssetSimulatedProgressComponent); diff --git a/packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx b/packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx deleted file mode 100644 index ceab61175..000000000 --- a/packages/instant/src/containers/selected_asset_simulated_progress_bar.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import * as React from 'react'; - -import { connect } from 'react-redux'; - -import { TimedProgressBar } from '../components/timed_progress_bar'; - -import { TimeCounter } from '../components/time_counter'; -import { Container } from '../components/ui'; -import { State } from '../redux/reducer'; -import { OrderProcessState, OrderState, SimulatedProgress } from '../types'; - -// TODO: rename this -interface SelectedAssetProgressComponentProps { - buyOrderState: OrderState; -} -export const SelectedAssetSimulatedProgressComponent: React.StatelessComponent< - SelectedAssetProgressComponentProps -> = props => { - const { buyOrderState } = props; - - if ( - buyOrderState.processState === OrderProcessState.PROCESSING || - buyOrderState.processState === OrderProcessState.SUCCESS || - buyOrderState.processState === OrderProcessState.FAILURE - ) { - const progress = buyOrderState.progress; - const ended = buyOrderState.processState !== OrderProcessState.PROCESSING; - const expectedTimeMs = progress.expectedEndTimeUnix - progress.startTimeUnix; - return ( - - - - - - - ); - } - - return null; -}; - -interface ConnectedState { - buyOrderState: OrderState; - simulatedProgress?: SimulatedProgress; -} -const mapStateToProps = (state: State, _ownProps: {}): ConnectedState => ({ - buyOrderState: state.buyOrderState, -}); -export const SelectedAssetSimulatedProgressBar = connect(mapStateToProps)(SelectedAssetSimulatedProgressComponent); -- cgit v1.2.3 From f9a38fcb32ee4e755c7f271a1c5a116c29985a10 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 1 Nov 2018 09:51:27 -0700 Subject: ended -> hasEnded --- packages/instant/src/components/time_counter.tsx | 6 +++--- packages/instant/src/components/timed_progress_bar.tsx | 6 +++--- packages/instant/src/containers/selected_asset_progress.tsx | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/time_counter.tsx b/packages/instant/src/components/time_counter.tsx index 26deb82bd..7d9245b5d 100644 --- a/packages/instant/src/components/time_counter.tsx +++ b/packages/instant/src/components/time_counter.tsx @@ -7,7 +7,7 @@ import { Text } from './ui/text'; export interface TimeCounterProps { estimatedTimeMs: number; - ended: boolean; + hasEnded: boolean; } interface TimeCounterState { elapsedSeconds: number; @@ -28,7 +28,7 @@ export class TimeCounter extends React.Component - + - + ); } -- cgit v1.2.3 From a148db5022379cdd8c0009d2f67f451dff376ad8 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 1 Nov 2018 09:52:34 -0700 Subject: Fix test name --- packages/instant/test/util/time.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/instant/test/util/time.test.ts b/packages/instant/test/util/time.test.ts index 7165761de..fcb4e1875 100644 --- a/packages/instant/test/util/time.test.ts +++ b/packages/instant/test/util/time.test.ts @@ -1,6 +1,6 @@ import { timeUtil } from '../../src/util/time'; -describe('assetDataUtil', () => { +describe('timeUtil', () => { describe('secondsToHumanDescription', () => { const numsToResults: { [aNumber: number]: string; -- cgit v1.2.3 From 9ef6f82a95c0faca0e6ba03ddd425271454dcfe3 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 1 Nov 2018 09:59:37 -0700 Subject: Take out old ended variable --- packages/instant/src/redux/reducer.ts | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index 68b788be5..cf24f8488 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -111,17 +111,13 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State => const failureTxHash = action.data; if ('txHash' in state.buyOrderState) { if (state.buyOrderState.txHash === failureTxHash) { - const failureProgress = { - startTimeUnix: state.buyOrderState.progress.startTimeUnix, - expectedEndTimeUnix: state.buyOrderState.progress.expectedEndTimeUnix, - ended: true, - }; + const { txHash, progress } = state.buyOrderState; return { ...state, buyOrderState: { processState: OrderProcessState.FAILURE, - txHash: state.buyOrderState.txHash, - progress: failureProgress, + txHash, + progress, }, }; } @@ -131,17 +127,13 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State => const successTxHash = action.data; if ('txHash' in state.buyOrderState) { if (state.buyOrderState.txHash === successTxHash) { - const successProgress = { - startTimeUnix: state.buyOrderState.progress.startTimeUnix, - expectedEndTimeUnix: state.buyOrderState.progress.expectedEndTimeUnix, - ended: true, - }; + const { txHash, progress } = state.buyOrderState; return { ...state, buyOrderState: { processState: OrderProcessState.SUCCESS, - txHash: state.buyOrderState.txHash, - progress: successProgress, + txHash, + progress, }, }; } -- cgit v1.2.3 From 66b485c7d43df3600c04e1eb565952cc7726dcb1 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 1 Nov 2018 10:04:04 -0700 Subject: Minor cleanup Don't export beginningState, and updating prop name in comment --- packages/instant/src/components/timed_progress_bar.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/timed_progress_bar.tsx b/packages/instant/src/components/timed_progress_bar.tsx index 16781b9d7..8dc95808b 100644 --- a/packages/instant/src/components/timed_progress_bar.tsx +++ b/packages/instant/src/components/timed_progress_bar.tsx @@ -17,7 +17,7 @@ interface TimedProgressBarState { maxWidthPercent: number; } -export const beginningState = (props: TimedProgressBarProps): TimedProgressBarState => { +const beginningState = (props: TimedProgressBarProps): TimedProgressBarState => { return { animationTimeMs: props.expectedTimeMs, animationStartingWidth: '0%', @@ -28,7 +28,7 @@ export const beginningState = (props: TimedProgressBarProps): TimedProgressBarSt /** * Timed Progress Bar * Goes from 0% -> PROGRESS_STALL_AT_PERCENTAGE% over time of expectedTimeMs - * When ended set to true, goes to 100% through animation of PROGRESS_FINISH_ANIMATION_TIME_MS length + * When hasEnded set to true, goes to 100% through animation of PROGRESS_FINISH_ANIMATION_TIME_MS length */ export class TimedProgressBar extends React.Component { private readonly _barRef = React.createRef(); -- cgit v1.2.3 From 544ddd44a00fe7432d6d8cef44c75f9bfbc78150 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 1 Nov 2018 10:46:34 -0700 Subject: Getting rid of TimedProgress state --- .../instant/src/components/timed_progress_bar.tsx | 70 +++++++--------------- 1 file changed, 23 insertions(+), 47 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/timed_progress_bar.tsx b/packages/instant/src/components/timed_progress_bar.tsx index 8dc95808b..694ae7e2f 100644 --- a/packages/instant/src/components/timed_progress_bar.tsx +++ b/packages/instant/src/components/timed_progress_bar.tsx @@ -11,66 +11,42 @@ export interface TimedProgressBarProps { hasEnded: boolean; } -interface TimedProgressBarState { - animationTimeMs: number; - animationStartingWidth: string; - maxWidthPercent: number; -} - -const beginningState = (props: TimedProgressBarProps): TimedProgressBarState => { - return { - animationTimeMs: props.expectedTimeMs, - animationStartingWidth: '0%', - maxWidthPercent: PROGRESS_STALL_AT_PERCENTAGE, - }; -}; - /** * Timed Progress Bar * Goes from 0% -> PROGRESS_STALL_AT_PERCENTAGE% over time of expectedTimeMs * When hasEnded set to true, goes to 100% through animation of PROGRESS_FINISH_ANIMATION_TIME_MS length */ -export class TimedProgressBar extends React.Component { +export class TimedProgressBar extends React.Component { private readonly _barRef = React.createRef(); - public constructor(props: TimedProgressBarProps) { - super(props); - this.state = beginningState(props); - } - - public componentDidUpdate(prevProps: TimedProgressBarProps, prevState: TimedProgressBarState): void { - if (prevProps.hasEnded === false && this.props.hasEnded === true) { - // Show nice animation going to end - // barRef current should always exist, but checking for typesafety - if (this._barRef.current) { - const curProgressWidth = this._barRef.current.offsetWidth; - this.setState({ - animationTimeMs: PROGRESS_FINISH_ANIMATION_TIME_MS, - animationStartingWidth: `${curProgressWidth}px`, - maxWidthPercent: 100, - }); - } - return; - } - - if (prevProps.expectedTimeMs !== this.props.expectedTimeMs || prevProps.hasEnded !== this.props.hasEnded) { - // things changed, get fresh state - this.setState(beginningState(this.props)); - } - } - public render(): React.ReactNode { + const timedProgressProps = this._calculateTimedProgressProps(); return ( - + ); } + + private _calculateTimedProgressProps(): TimedProgressProps { + if (this.props.hasEnded) { + if (!this._barRef.current) { + throw new Error('ended but no reference'); + } + const fromWidth = `${this._barRef.current.offsetWidth}px`; + return { + timeMs: PROGRESS_FINISH_ANIMATION_TIME_MS, + fromWidth, + maxWidthPercent: 100, + }; + } + + return { + timeMs: this.props.expectedTimeMs, + fromWidth: '0px', + maxWidthPercent: PROGRESS_STALL_AT_PERCENTAGE, + }; + } } const expandingWidthKeyframes = (fromWidth: string, maxWidthPercent: number) => { -- cgit v1.2.3 From 9990f8720cbc04bc7a5074d6668f22af80b2a476 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 1 Nov 2018 10:50:37 -0700 Subject: maxWidth -> toWidth, and make from and to width consistent units --- .../instant/src/components/timed_progress_bar.tsx | 20 ++++++++++---------- packages/instant/src/constants.ts | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/timed_progress_bar.tsx b/packages/instant/src/components/timed_progress_bar.tsx index 694ae7e2f..78c7ee849 100644 --- a/packages/instant/src/components/timed_progress_bar.tsx +++ b/packages/instant/src/components/timed_progress_bar.tsx @@ -1,7 +1,7 @@ import * as _ from 'lodash'; import * as React from 'react'; -import { PROGRESS_FINISH_ANIMATION_TIME_MS, PROGRESS_STALL_AT_PERCENTAGE } from '../constants'; +import { PROGRESS_FINISH_ANIMATION_TIME_MS, PROGRESS_STALL_AT_WIDTH } from '../constants'; import { ColorOption, keyframes, styled } from '../style/theme'; import { Container } from './ui/container'; @@ -13,8 +13,8 @@ export interface TimedProgressBarProps { /** * Timed Progress Bar - * Goes from 0% -> PROGRESS_STALL_AT_PERCENTAGE% over time of expectedTimeMs - * When hasEnded set to true, goes to 100% through animation of PROGRESS_FINISH_ANIMATION_TIME_MS length + * Goes from 0% -> PROGRESS_STALL_AT_WIDTH over time of expectedTimeMs + * When hasEnded set to true, goes to 100% through animation of PROGRESS_FINISH_ANIMATION_TIME_MS length of time */ export class TimedProgressBar extends React.Component { private readonly _barRef = React.createRef(); @@ -37,25 +37,25 @@ export class TimedProgressBar extends React.Component return { timeMs: PROGRESS_FINISH_ANIMATION_TIME_MS, fromWidth, - maxWidthPercent: 100, + toWidth: '100%', }; } return { timeMs: this.props.expectedTimeMs, fromWidth: '0px', - maxWidthPercent: PROGRESS_STALL_AT_PERCENTAGE, + toWidth: PROGRESS_STALL_AT_WIDTH, }; } } -const expandingWidthKeyframes = (fromWidth: string, maxWidthPercent: number) => { +const expandingWidthKeyframes = (fromWidth: string, toWidth: string) => { return keyframes` from { - width: ${fromWidth} + width: ${fromWidth}; } to { - width: ${maxWidthPercent}%; + width: ${toWidth}; } `; }; @@ -63,7 +63,7 @@ const expandingWidthKeyframes = (fromWidth: string, maxWidthPercent: number) => interface TimedProgressProps { timeMs: number; fromWidth: string; - maxWidthPercent: number; + toWidth: string; } // TODO use PrimaryColor instead of black export const TimedProgress = @@ -73,6 +73,6 @@ export const TimedProgress = background-color: black; border-radius: 6px; height: 6px; - animation: ${props => expandingWidthKeyframes(props.fromWidth, props.maxWidthPercent)} + animation: ${props => expandingWidthKeyframes(props.fromWidth, props.toWidth)} ${props => props.timeMs}ms linear 1 forwards; `; diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index fcf6e0798..df1e6f53f 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -8,5 +8,5 @@ export const DEFAULT_GAS_PRICE = GWEI_IN_WEI.mul(6); export const DEFAULT_ESTIMATED_TRANSACTION_TIME_MS = 2 * 60 * 1000; // 2 minutes export const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info'; export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2'; -export const PROGRESS_STALL_AT_PERCENTAGE = 95; +export const PROGRESS_STALL_AT_WIDTH = '95%'; export const PROGRESS_FINISH_ANIMATION_TIME_MS = 200; -- cgit v1.2.3 From f82d16a5b06a47f3ede917165ba75dfd73f48137 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 1 Nov 2018 11:15:07 -0700 Subject: Use primary color instead of black --- packages/instant/src/components/timed_progress_bar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/instant/src/components/timed_progress_bar.tsx b/packages/instant/src/components/timed_progress_bar.tsx index 78c7ee849..c6ba4ac19 100644 --- a/packages/instant/src/components/timed_progress_bar.tsx +++ b/packages/instant/src/components/timed_progress_bar.tsx @@ -70,7 +70,7 @@ export const TimedProgress = styled.div < TimedProgressProps > ` - background-color: black; + background-color: ${props => props.theme[ColorOption.primaryColor]}; border-radius: 6px; height: 6px; animation: ${props => expandingWidthKeyframes(props.fromWidth, props.toWidth)} -- cgit v1.2.3 From cd79a2fad1babd1d421c693208cd7de5ae980630 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 1 Nov 2018 11:15:34 -0700 Subject: Use new constants --- packages/instant/src/components/time_counter.tsx | 5 +++-- packages/instant/src/constants.ts | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/time_counter.tsx b/packages/instant/src/components/time_counter.tsx index 7d9245b5d..c98fd2550 100644 --- a/packages/instant/src/components/time_counter.tsx +++ b/packages/instant/src/components/time_counter.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; +import { ONE_SECOND_MS } from '../constants'; import { timeUtil } from '../util/time'; import { Flex } from './ui/flex'; @@ -34,7 +35,7 @@ export class TimeCounter extends React.Component Est. Time ({timeUtil.secondsToHumanDescription(estimatedTimeSeconds)}) @@ -53,7 +54,7 @@ export class TimeCounter extends React.Component Date: Thu, 1 Nov 2018 11:17:41 -0700 Subject: Remove old TODO --- packages/instant/src/components/timed_progress_bar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/instant/src/components/timed_progress_bar.tsx b/packages/instant/src/components/timed_progress_bar.tsx index c6ba4ac19..f2a6f5745 100644 --- a/packages/instant/src/components/timed_progress_bar.tsx +++ b/packages/instant/src/components/timed_progress_bar.tsx @@ -65,7 +65,7 @@ interface TimedProgressProps { fromWidth: string; toWidth: string; } -// TODO use PrimaryColor instead of black + export const TimedProgress = styled.div < TimedProgressProps > -- cgit v1.2.3 From 61a1a0be974c8610623f2bcb9a43797532cc78d9 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 1 Nov 2018 11:29:33 -0700 Subject: Move BuyOrderProgress to its own component --- .../instant/src/components/buy_order_progress.tsx | 35 ++++++++++++++++++ .../src/containers/selected_asset_progress.tsx | 42 +++------------------- 2 files changed, 39 insertions(+), 38 deletions(-) create mode 100644 packages/instant/src/components/buy_order_progress.tsx (limited to 'packages') diff --git a/packages/instant/src/components/buy_order_progress.tsx b/packages/instant/src/components/buy_order_progress.tsx new file mode 100644 index 000000000..e259e5606 --- /dev/null +++ b/packages/instant/src/components/buy_order_progress.tsx @@ -0,0 +1,35 @@ +import * as React from 'react'; + +import { TimedProgressBar } from '../components/timed_progress_bar'; + +import { TimeCounter } from '../components/time_counter'; +import { Container } from '../components/ui'; +import { OrderProcessState, OrderState } from '../types'; + +export interface BuyOrderProgressProps { + buyOrderState: OrderState; +} + +export const BuyOrderProgress: React.StatelessComponent = props => { + const { buyOrderState } = props; + + if ( + buyOrderState.processState === OrderProcessState.PROCESSING || + buyOrderState.processState === OrderProcessState.SUCCESS || + buyOrderState.processState === OrderProcessState.FAILURE + ) { + const progress = buyOrderState.progress; + const hasEnded = buyOrderState.processState !== OrderProcessState.PROCESSING; + const expectedTimeMs = progress.expectedEndTimeUnix - progress.startTimeUnix; + return ( + + + + + + + ); + } + + return null; +}; diff --git a/packages/instant/src/containers/selected_asset_progress.tsx b/packages/instant/src/containers/selected_asset_progress.tsx index a910d8031..354a15bf0 100644 --- a/packages/instant/src/containers/selected_asset_progress.tsx +++ b/packages/instant/src/containers/selected_asset_progress.tsx @@ -1,49 +1,15 @@ -import * as React from 'react'; +// TODO: rename file and props to SelectedAssetBuyOrderProgress and use .ts import { connect } from 'react-redux'; -import { TimedProgressBar } from '../components/timed_progress_bar'; - -import { TimeCounter } from '../components/time_counter'; -import { Container } from '../components/ui'; +import { BuyOrderProgress } from '../components/buy_order_progress'; import { State } from '../redux/reducer'; -import { OrderProcessState, OrderState, SimulatedProgress } from '../types'; - -interface SelectedAssetProgressComponentProps { - buyOrderState: OrderState; -} -// TODO: rename this component and move to seperate file, and get props using mapStateToProps -export const SelectedAssetSimulatedProgressComponent: React.StatelessComponent< - SelectedAssetProgressComponentProps -> = props => { - const { buyOrderState } = props; - - if ( - buyOrderState.processState === OrderProcessState.PROCESSING || - buyOrderState.processState === OrderProcessState.SUCCESS || - buyOrderState.processState === OrderProcessState.FAILURE - ) { - const progress = buyOrderState.progress; - const hasEnded = buyOrderState.processState !== OrderProcessState.PROCESSING; - const expectedTimeMs = progress.expectedEndTimeUnix - progress.startTimeUnix; - return ( - - - - - - - ); - } - - return null; -}; +import { OrderState } from '../types'; interface ConnectedState { buyOrderState: OrderState; - simulatedProgress?: SimulatedProgress; } const mapStateToProps = (state: State, _ownProps: {}): ConnectedState => ({ buyOrderState: state.buyOrderState, }); -export const SelectedAssetProgress = connect(mapStateToProps)(SelectedAssetSimulatedProgressComponent); +export const SelectedAssetProgress = connect(mapStateToProps)(BuyOrderProgress); -- cgit v1.2.3 From 771e01162d2c1f8543d5561872fb82af9e8e7b62 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 1 Nov 2018 11:30:13 -0700 Subject: Rename export --- packages/instant/src/components/zero_ex_instant_container.tsx | 4 ++-- packages/instant/src/containers/selected_asset_progress.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 87a7cee88..efebf264c 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -5,7 +5,7 @@ import { LatestError } from '../containers/latest_error'; import { SelectedAssetBuyOrderStateButtons } from '../containers/selected_asset_buy_order_state_buttons'; import { SelectedAssetInstantHeading } from '../containers/selected_asset_instant_heading'; -import { SelectedAssetProgress } from '../containers/selected_asset_progress'; +import { SelectedAssetBuyOrderProgress } from '../containers/selected_asset_progress'; import { ColorOption } from '../style/theme'; @@ -26,7 +26,7 @@ export const ZeroExInstantContainer: React.StatelessComponent - + diff --git a/packages/instant/src/containers/selected_asset_progress.tsx b/packages/instant/src/containers/selected_asset_progress.tsx index 354a15bf0..726967bc7 100644 --- a/packages/instant/src/containers/selected_asset_progress.tsx +++ b/packages/instant/src/containers/selected_asset_progress.tsx @@ -12,4 +12,4 @@ interface ConnectedState { const mapStateToProps = (state: State, _ownProps: {}): ConnectedState => ({ buyOrderState: state.buyOrderState, }); -export const SelectedAssetProgress = connect(mapStateToProps)(BuyOrderProgress); +export const SelectedAssetBuyOrderProgress = connect(mapStateToProps)(BuyOrderProgress); -- cgit v1.2.3 From f9d13cd43ae43c05558538ac3d108552c7854fee Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 1 Nov 2018 11:32:18 -0700 Subject: Move file to new file to reflect the new export name --- .../instant/src/components/zero_ex_instant_container.tsx | 2 +- .../src/containers/selected_asset_buy_order_progress.ts | 13 +++++++++++++ .../instant/src/containers/selected_asset_progress.tsx | 15 --------------- 3 files changed, 14 insertions(+), 16 deletions(-) create mode 100644 packages/instant/src/containers/selected_asset_buy_order_progress.ts delete mode 100644 packages/instant/src/containers/selected_asset_progress.tsx (limited to 'packages') diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index efebf264c..c47f3af73 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -5,7 +5,7 @@ import { LatestError } from '../containers/latest_error'; import { SelectedAssetBuyOrderStateButtons } from '../containers/selected_asset_buy_order_state_buttons'; import { SelectedAssetInstantHeading } from '../containers/selected_asset_instant_heading'; -import { SelectedAssetBuyOrderProgress } from '../containers/selected_asset_progress'; +import { SelectedAssetBuyOrderProgress } from '../containers/selected_asset_buy_order_progress'; import { ColorOption } from '../style/theme'; diff --git a/packages/instant/src/containers/selected_asset_buy_order_progress.ts b/packages/instant/src/containers/selected_asset_buy_order_progress.ts new file mode 100644 index 000000000..7c8c24676 --- /dev/null +++ b/packages/instant/src/containers/selected_asset_buy_order_progress.ts @@ -0,0 +1,13 @@ +import { connect } from 'react-redux'; + +import { BuyOrderProgress } from '../components/buy_order_progress'; +import { State } from '../redux/reducer'; +import { OrderState } from '../types'; + +interface ConnectedState { + buyOrderState: OrderState; +} +const mapStateToProps = (state: State, _ownProps: {}): ConnectedState => ({ + buyOrderState: state.buyOrderState, +}); +export const SelectedAssetBuyOrderProgress = connect(mapStateToProps)(BuyOrderProgress); diff --git a/packages/instant/src/containers/selected_asset_progress.tsx b/packages/instant/src/containers/selected_asset_progress.tsx deleted file mode 100644 index 726967bc7..000000000 --- a/packages/instant/src/containers/selected_asset_progress.tsx +++ /dev/null @@ -1,15 +0,0 @@ -// TODO: rename file and props to SelectedAssetBuyOrderProgress and use .ts - -import { connect } from 'react-redux'; - -import { BuyOrderProgress } from '../components/buy_order_progress'; -import { State } from '../redux/reducer'; -import { OrderState } from '../types'; - -interface ConnectedState { - buyOrderState: OrderState; -} -const mapStateToProps = (state: State, _ownProps: {}): ConnectedState => ({ - buyOrderState: state.buyOrderState, -}); -export const SelectedAssetBuyOrderProgress = connect(mapStateToProps)(BuyOrderProgress); -- cgit v1.2.3 From 82b6a81a223a75040054b4578a16f88be6271440 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 1 Nov 2018 11:35:53 -0700 Subject: removing unused imports --- .../instant/src/containers/selected_asset_buy_order_state_buttons.ts | 2 +- packages/instant/src/redux/actions.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts index a94538ffc..7c36fa4d0 100644 --- a/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts +++ b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts @@ -7,7 +7,7 @@ import { Dispatch } from 'redux'; import { BuyOrderStateButtons } from '../components/buy_order_state_buttons'; import { Action, actions } from '../redux/actions'; import { State } from '../redux/reducer'; -import { OrderProcessState, OrderState, ZeroExInstantError } from '../types'; +import { OrderProcessState, ZeroExInstantError } from '../types'; import { errorFlasher } from '../util/error_flasher'; import { etherscanUtil } from '../util/etherscan'; diff --git a/packages/instant/src/redux/actions.ts b/packages/instant/src/redux/actions.ts index 627e39ffc..885f09c7c 100644 --- a/packages/instant/src/redux/actions.ts +++ b/packages/instant/src/redux/actions.ts @@ -4,7 +4,7 @@ import * as _ from 'lodash'; import { BigNumberInput } from '../util/big_number_input'; -import { ActionsUnion, OrderState, SimulatedProgress } from '../types'; +import { ActionsUnion } from '../types'; export interface PlainAction { type: T; -- cgit v1.2.3 From dc655fd903c5b35ea9280c5afd10b78b25fa7ca3 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 1 Nov 2018 12:08:48 -0700 Subject: Better styling of estimated time --- packages/instant/src/components/time_counter.tsx | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/time_counter.tsx b/packages/instant/src/components/time_counter.tsx index c98fd2550..22dc634d9 100644 --- a/packages/instant/src/components/time_counter.tsx +++ b/packages/instant/src/components/time_counter.tsx @@ -3,8 +3,10 @@ import * as React from 'react'; import { ONE_SECOND_MS } from '../constants'; import { timeUtil } from '../util/time'; +import { Container } from './ui/container'; import { Flex } from './ui/flex'; import { Text } from './ui/text'; +import { ColorOption } from '../style/theme'; export interface TimeCounterProps { estimatedTimeMs: number; @@ -38,8 +40,19 @@ export class TimeCounter extends React.Component - Est. Time ({timeUtil.secondsToHumanDescription(estimatedTimeSeconds)}) - Time: {timeUtil.secondsToStopwatchTime(this.state.elapsedSeconds)} + + + + Est. Time + + + + ({timeUtil.secondsToHumanDescription(estimatedTimeSeconds)}) + + + + Time: {timeUtil.secondsToStopwatchTime(this.state.elapsedSeconds)} + ); } -- cgit v1.2.3 From 7858dafce4c9441c8205fa6ed607ca50851cc4ba Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 1 Nov 2018 14:14:00 -0700 Subject: linting: moving order of imports --- packages/instant/src/components/time_counter.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/instant/src/components/time_counter.tsx b/packages/instant/src/components/time_counter.tsx index 22dc634d9..f9b68163c 100644 --- a/packages/instant/src/components/time_counter.tsx +++ b/packages/instant/src/components/time_counter.tsx @@ -1,12 +1,12 @@ import * as React from 'react'; import { ONE_SECOND_MS } from '../constants'; +import { ColorOption } from '../style/theme'; import { timeUtil } from '../util/time'; import { Container } from './ui/container'; import { Flex } from './ui/flex'; import { Text } from './ui/text'; -import { ColorOption } from '../style/theme'; export interface TimeCounterProps { estimatedTimeMs: number; -- cgit v1.2.3 From 4fda2a2d049843db7f87b930321c11c910e40ea3 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 1 Nov 2018 18:01:06 -0700 Subject: fix(asset-buyer): fix default values being overriden and incorrect fee rounding --- packages/asset-buyer/CHANGELOG.json | 10 +++++++ packages/asset-buyer/src/asset_buyer.ts | 33 ++++++++++++++-------- .../asset-buyer/src/utils/buy_quote_calculator.ts | 2 +- 3 files changed, 32 insertions(+), 13 deletions(-) (limited to 'packages') diff --git a/packages/asset-buyer/CHANGELOG.json b/packages/asset-buyer/CHANGELOG.json index 6ba2a0fd9..0d71bb84d 100644 --- a/packages/asset-buyer/CHANGELOG.json +++ b/packages/asset-buyer/CHANGELOG.json @@ -14,6 +14,16 @@ { "note": "No longer require that provided orders all have the same maker and taker asset data", "pr": 1197 + }, + { + "note": + "Fix bug where `BuyQuoteInfo` objects could return `totalEthAmount` and `feeEthAmount` that were not whole numbers", + "pr": 1207 + }, + { + "note": + "Fix bug where default values for `AssetBuyer` public facing methods could get overriden by `undefined` values", + "pr": 1207 } ] }, diff --git a/packages/asset-buyer/src/asset_buyer.ts b/packages/asset-buyer/src/asset_buyer.ts index 49743404f..934410c55 100644 --- a/packages/asset-buyer/src/asset_buyer.ts +++ b/packages/asset-buyer/src/asset_buyer.ts @@ -90,10 +90,11 @@ export class AssetBuyer { * @return An instance of AssetBuyer */ constructor(provider: Provider, orderProvider: OrderProvider, options: Partial = {}) { - const { networkId, orderRefreshIntervalMs, expiryBufferSeconds } = { - ...constants.DEFAULT_ASSET_BUYER_OPTS, - ...options, - }; + const { networkId, orderRefreshIntervalMs, expiryBufferSeconds } = _.merge( + {}, + constants.DEFAULT_ASSET_BUYER_OPTS, + options, + ); assert.isWeb3Provider('provider', provider); assert.isValidOrderProvider('orderProvider', orderProvider); assert.isNumber('networkId', networkId); @@ -122,10 +123,11 @@ export class AssetBuyer { assetBuyAmount: BigNumber, options: Partial = {}, ): Promise { - const { feePercentage, shouldForceOrderRefresh, slippagePercentage } = { - ...constants.DEFAULT_BUY_QUOTE_REQUEST_OPTS, - ...options, - }; + const { feePercentage, shouldForceOrderRefresh, slippagePercentage } = _.merge( + {}, + constants.DEFAULT_BUY_QUOTE_REQUEST_OPTS, + options, + ); assert.isString('assetData', assetData); assert.isBigNumber('assetBuyAmount', assetBuyAmount); assert.isValidPercentage('feePercentage', feePercentage); @@ -186,10 +188,11 @@ export class AssetBuyer { buyQuote: BuyQuote, options: Partial = {}, ): Promise { - const { ethAmount, takerAddress, feeRecipient, gasLimit, gasPrice } = { - ...constants.DEFAULT_BUY_QUOTE_EXECUTION_OPTS, - ...options, - }; + const { ethAmount, takerAddress, feeRecipient, gasLimit, gasPrice } = _.merge( + {}, + constants.DEFAULT_BUY_QUOTE_EXECUTION_OPTS, + options, + ); assert.isValidBuyQuote('buyQuote', buyQuote); if (!_.isUndefined(ethAmount)) { assert.isBigNumber('ethAmount', ethAmount); @@ -198,6 +201,12 @@ export class AssetBuyer { assert.isETHAddressHex('takerAddress', takerAddress); } assert.isETHAddressHex('feeRecipient', feeRecipient); + if (!_.isUndefined(gasLimit)) { + assert.isNumber('gasLimit', gasLimit); + } + if (!_.isUndefined(gasPrice)) { + assert.isBigNumber('gasPrice', gasPrice); + } const { orders, feeOrders, feePercentage, assetBuyAmount, worstCaseQuoteInfo } = buyQuote; // if no takerAddress is provided, try to get one from the provider let finalTakerAddress; diff --git a/packages/asset-buyer/src/utils/buy_quote_calculator.ts b/packages/asset-buyer/src/utils/buy_quote_calculator.ts index f94ab3fa4..6a67ed1ed 100644 --- a/packages/asset-buyer/src/utils/buy_quote_calculator.ts +++ b/packages/asset-buyer/src/utils/buy_quote_calculator.ts @@ -119,7 +119,7 @@ function calculateQuoteInfo( ethAmountToBuyZrx = findEthAmountNeededToBuyZrx(feeOrdersAndFillableAmounts, zrxAmountToBuyAsset); } /// find the eth amount needed to buy the affiliate fee - const ethAmountToBuyAffiliateFee = ethAmountToBuyAsset.mul(feePercentage); + const ethAmountToBuyAffiliateFee = ethAmountToBuyAsset.mul(feePercentage).ceil(); const totalEthAmountWithoutAffiliateFee = ethAmountToBuyAsset.plus(ethAmountToBuyZrx); const ethAmountTotal = totalEthAmountWithoutAffiliateFee.plus(ethAmountToBuyAffiliateFee); // divide into the assetBuyAmount in order to find rate of makerAsset / WETH -- cgit v1.2.3 From 5e66cc8a40759658a8763f85996163e5ae013fcd Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 1 Nov 2018 18:24:32 -0700 Subject: feat(instant): implement affiliateFeeInfo prop --- packages/instant/src/components/buy_button.tsx | 13 +++++++--- .../src/components/buy_order_state_buttons.tsx | 4 +++- .../src/components/zero_ex_instant_provider.tsx | 6 +++-- .../selected_asset_buy_order_state_buttons.ts | 4 +++- .../selected_erc20_asset_amount_input.ts | 28 ++++++++++++++++------ packages/instant/src/index.umd.ts | 3 +++ packages/instant/src/redux/reducer.ts | 3 +++ packages/instant/src/types.ts | 5 ++++ packages/instant/src/util/assert.ts | 10 +++++++- 9 files changed, 61 insertions(+), 15 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index c00b1678d..12ac62601 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -1,10 +1,11 @@ import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer'; import * as _ from 'lodash'; import * as React from 'react'; +import { oc } from 'ts-optchain'; import { WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX } from '../constants'; import { ColorOption } from '../style/theme'; -import { ZeroExInstantError } from '../types'; +import { AffiliateInfo, ZeroExInstantError } from '../types'; import { getBestAddress } from '../util/address'; import { balanceUtil } from '../util/balance'; import { gasPriceEstimator } from '../util/gas_price_estimator'; @@ -16,6 +17,7 @@ import { Button, Text } from './ui'; export interface BuyButtonProps { buyQuote?: BuyQuote; assetBuyer?: AssetBuyer; + affiliateInfo?: AffiliateInfo; onValidationPending: (buyQuote: BuyQuote) => void; onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void; onSignatureDenied: (buyQuote: BuyQuote) => void; @@ -42,7 +44,7 @@ export class BuyButton extends React.Component { } private readonly _handleClick = async () => { // The button is disabled when there is no buy quote anyway. - const { buyQuote, assetBuyer } = this.props; + const { buyQuote, assetBuyer, affiliateInfo } = this.props; if (_.isUndefined(buyQuote) || _.isUndefined(assetBuyer)) { return; } @@ -58,8 +60,13 @@ export class BuyButton extends React.Component { let txHash: string | undefined; const gasInfo = await gasPriceEstimator.getGasInfoAsync(); + const feeRecipient = oc(affiliateInfo).feeRecipient(); try { - txHash = await assetBuyer.executeBuyQuoteAsync(buyQuote, { takerAddress, gasPrice: gasInfo.gasPriceInWei }); + txHash = await assetBuyer.executeBuyQuoteAsync(buyQuote, { + feeRecipient, + takerAddress, + gasPrice: gasInfo.gasPriceInWei, + }); } catch (e) { if (e instanceof Error) { if (e.message === AssetBuyerError.SignatureRequestDenied) { diff --git a/packages/instant/src/components/buy_order_state_buttons.tsx b/packages/instant/src/components/buy_order_state_buttons.tsx index 1d02f8cd9..5c074a67a 100644 --- a/packages/instant/src/components/buy_order_state_buttons.tsx +++ b/packages/instant/src/components/buy_order_state_buttons.tsx @@ -2,7 +2,7 @@ import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer'; import * as React from 'react'; import { ColorOption } from '../style/theme'; -import { OrderProcessState, ZeroExInstantError } from '../types'; +import { AffiliateInfo, OrderProcessState, ZeroExInstantError } from '../types'; import { BuyButton } from './buy_button'; import { PlacingOrderButton } from './placing_order_button'; @@ -13,6 +13,7 @@ export interface BuyOrderStateButtonProps { buyQuote?: BuyQuote; buyOrderProcessingState: OrderProcessState; assetBuyer?: AssetBuyer; + affiliateInfo?: AffiliateInfo; onViewTransaction: () => void; onValidationPending: (buyQuote: BuyQuote) => void; onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void; @@ -50,6 +51,7 @@ export const BuyOrderStateButtons: React.StatelessComponent; networkId: Network; + affiliateInfo: AffiliateInfo; } export class ZeroExInstantProvider extends React.Component { @@ -66,6 +67,7 @@ export class ZeroExInstantProvider extends React.Component void; } @@ -32,6 +33,7 @@ const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyOrderStateButt buyOrderProcessingState: state.buyOrderState.processState, assetBuyer: state.assetBuyer, buyQuote: state.latestBuyQuote, + affiliateInfo: state.affiliateInfo, onViewTransaction: () => { if ( state.assetBuyer && diff --git a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts index f0e792e2f..7859261dd 100644 --- a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts +++ b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts @@ -6,12 +6,13 @@ import * as _ from 'lodash'; import * as React from 'react'; import { connect } from 'react-redux'; import { Dispatch } from 'redux'; +import { oc } from 'ts-optchain'; import { ERC20AssetAmountInput } from '../components/erc20_asset_amount_input'; import { Action, actions } from '../redux/actions'; import { State } from '../redux/reducer'; import { ColorOption } from '../style/theme'; -import { ERC20Asset, OrderProcessState } from '../types'; +import { AffiliateInfo, ERC20Asset, OrderProcessState } from '../types'; import { assetUtils } from '../util/asset'; import { BigNumberInput } from '../util/big_number_input'; import { errorFlasher } from '../util/error_flasher'; @@ -27,10 +28,16 @@ interface ConnectedState { value?: BigNumberInput; asset?: ERC20Asset; isDisabled: boolean; + affiliateInfo?: AffiliateInfo; } interface ConnectedDispatch { - updateBuyQuote: (assetBuyer?: AssetBuyer, value?: BigNumberInput, asset?: ERC20Asset) => void; + updateBuyQuote: ( + assetBuyer?: AssetBuyer, + value?: BigNumberInput, + asset?: ERC20Asset, + affiliateInfo?: AffiliateInfo, + ) => void; } interface ConnectedProps { @@ -60,6 +67,7 @@ const mapStateToProps = (state: State, _ownProps: SelectedERC20AssetAmountInputP value: state.selectedAssetAmount, asset: selectedAsset as ERC20Asset, isDisabled, + affiliateInfo: state.affiliateInfo, }; }; @@ -68,6 +76,7 @@ const updateBuyQuoteAsync = async ( dispatch: Dispatch, asset: ERC20Asset, assetAmount: BigNumber, + affiliateInfo?: AffiliateInfo, ): Promise => { // get a new buy quote. const baseUnitValue = Web3Wrapper.toBaseUnitAmount(assetAmount, asset.metaData.decimals); @@ -75,9 +84,10 @@ const updateBuyQuoteAsync = async ( // mark quote as pending dispatch(actions.setQuoteRequestStatePending()); + const feePercentage = oc(affiliateInfo).feePercentage(); let newBuyQuote: BuyQuote | undefined; try { - newBuyQuote = await assetBuyer.getBuyQuoteAsync(asset.assetData, baseUnitValue); + newBuyQuote = await assetBuyer.getBuyQuoteAsync(asset.assetData, baseUnitValue, { feePercentage }); } catch (error) { dispatch(actions.setQuoteRequestStateFailure()); let errorMessage; @@ -93,7 +103,11 @@ const updateBuyQuoteAsync = async ( const assetName = assetUtils.bestNameForAsset(asset, 'This asset'); errorMessage = `${assetName} is currently unavailable`; } - errorFlasher.flashNewErrorMessage(dispatch, errorMessage); + if (!_.isUndefined(errorMessage)) { + errorFlasher.flashNewErrorMessage(dispatch, errorMessage); + } else { + throw error; + } return; } // We have a successful new buy quote @@ -108,7 +122,7 @@ const mapDispatchToProps = ( dispatch: Dispatch, _ownProps: SelectedERC20AssetAmountInputProps, ): ConnectedDispatch => ({ - updateBuyQuote: (assetBuyer, value, asset) => { + updateBuyQuote: (assetBuyer, value, asset, affiliateInfo) => { // Update the input dispatch(actions.updateSelectedAssetAmount(value)); // invalidate the last buy quote. @@ -120,7 +134,7 @@ const mapDispatchToProps = ( // even if it's debounced, give them the illusion it's loading dispatch(actions.setQuoteRequestStatePending()); // tslint:disable-next-line:no-floating-promises - debouncedUpdateBuyQuoteAsync(assetBuyer, dispatch, asset, value); + debouncedUpdateBuyQuoteAsync(assetBuyer, dispatch, asset, value, affiliateInfo); } }, }); @@ -135,7 +149,7 @@ const mergeProps = ( asset: connectedState.asset, value: connectedState.value, onChange: (value, asset) => { - connectedDispatch.updateBuyQuote(connectedState.assetBuyer, value, asset); + connectedDispatch.updateBuyQuote(connectedState.assetBuyer, value, asset, connectedState.affiliateInfo); }, isDisabled: connectedState.isDisabled, }; diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index b12e65485..806187a16 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -24,6 +24,9 @@ export const render = (props: ZeroExInstantOverlayProps, selector: string = DEFA if (!_.isUndefined(props.zIndex)) { assert.isNumber('props.zIndex', props.zIndex); } + if (!_.isUndefined(props.affiliateInfo)) { + assert.isValidaffiliateInfo('props.affiliateInfo', props.affiliateInfo); + } const appendToIfExists = document.querySelector(selector); assert.assert(!_.isNull(appendToIfExists), `Could not find div with selector: ${selector}`); const appendTo = appendToIfExists as Element; diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index cf24f8488..d1537b49b 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -6,6 +6,7 @@ import * as _ from 'lodash'; import { assetMetaDataMap } from '../data/asset_meta_data_map'; import { + AffiliateInfo, Asset, AssetMetaData, AsyncProcessState, @@ -31,6 +32,7 @@ export interface State { quoteRequestState: AsyncProcessState; latestErrorMessage?: string; latestErrorDisplayStatus: DisplayStatus; + affiliateInfo?: AffiliateInfo; } export const INITIAL_STATE: State = { @@ -43,6 +45,7 @@ export const INITIAL_STATE: State = { latestErrorMessage: undefined, latestErrorDisplayStatus: DisplayStatus.Hidden, quoteRequestState: AsyncProcessState.NONE, + affiliateInfo: undefined, }; export const reducer = (state: State = INITIAL_STATE, action: Action): State => { diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts index 288a6d111..82dc77d2e 100644 --- a/packages/instant/src/types.ts +++ b/packages/instant/src/types.ts @@ -80,3 +80,8 @@ export enum ZeroExInstantError { AssetMetaDataNotAvailable = 'ASSET_META_DATA_NOT_AVAILABLE', InsufficientETH = 'INSUFFICIENT_ETH', } + +export interface AffiliateInfo { + feeRecipient: string; + feePercentage: number; +} diff --git a/packages/instant/src/util/assert.ts b/packages/instant/src/util/assert.ts index 584d3d4b1..20f8ddaee 100644 --- a/packages/instant/src/util/assert.ts +++ b/packages/instant/src/util/assert.ts @@ -4,7 +4,7 @@ import { assetDataUtils } from '@0x/order-utils'; import { AssetProxyId, ObjectMap, SignedOrder } from '@0x/types'; import * as _ from 'lodash'; -import { AssetMetaData } from '../types'; +import { AffiliateInfo, AssetMetaData } from '../types'; export const assert = { ...sharedAssert, @@ -41,4 +41,12 @@ export const assert = { assert.isUri(`${variableName}.imageUrl`, metaData.imageUrl); } }, + isValidaffiliateInfo(variableName: string, affiliateInfo: AffiliateInfo): void { + assert.isETHAddressHex(`${variableName}.recipientAddress`, affiliateInfo.feeRecipient); + assert.isNumber(`${variableName}.percentage`, affiliateInfo.feePercentage); + assert.assert( + affiliateInfo.feePercentage >= 0 && affiliateInfo.feePercentage <= 0.05, + `Expected ${variableName}.percentage to be between 0 and 0.05, but is ${affiliateInfo.feePercentage}`, + ); + }, }; -- cgit v1.2.3 From a770ea56eae47c4ec840d28d1f363a017a89c69c Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 2 Nov 2018 11:48:59 -0700 Subject: fix(instant): dont get buy quote for zero value --- packages/instant/src/containers/selected_erc20_asset_amount_input.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts index f0e792e2f..0ba0bd31f 100644 --- a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts +++ b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts @@ -116,7 +116,7 @@ const mapDispatchToProps = ( // reset our buy state dispatch(actions.setBuyOrderStateNone()); - if (!_.isUndefined(value) && !_.isUndefined(asset) && !_.isUndefined(assetBuyer)) { + if (!_.isUndefined(value) && value.greaterThan(0) && !_.isUndefined(asset) && !_.isUndefined(assetBuyer)) { // even if it's debounced, give them the illusion it's loading dispatch(actions.setQuoteRequestStatePending()); // tslint:disable-next-line:no-floating-promises -- cgit v1.2.3 From b895b855cbb555736be838e2630890ab6a69d884 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Fri, 2 Nov 2018 12:03:15 -0700 Subject: feat(instant): add affiliateInfo overrides to dev url --- packages/instant/public/index.html | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'packages') diff --git a/packages/instant/public/index.html b/packages/instant/public/index.html index 7580ab132..96a703224 100644 --- a/packages/instant/public/index.html +++ b/packages/instant/public/index.html @@ -77,11 +77,21 @@ onClose: () => { console.log('0x Instant Closed') } } const liquiditySourceOverride = queryParams.getQueryParamValue('liquiditySource'); + const feeRecipientOverride = queryParams.getQueryParamValue('feeRecipient'); + const feePercentageOverride = +queryParams.getQueryParamValue('feePercentage'); + let affiliateInfoOverride; + if (feeRecipientOverride !== undefined && feePercentageOverride !== undefined) { + affiliateInfoOverride = { + feeRecipient: feeRecipientOverride, + feePercentage: feePercentageOverride + }; + } const renderOptionsOverrides = { liquiditySource: liquiditySourceOverride === 'provided' ? providedOrders : liquiditySourceOverride, assetData: queryParams.getQueryParamValue('assetData'), networkId: +queryParams.getQueryParamValue('networkId') || undefined, defaultAssetBuyAmount: +queryParams.getQueryParamValue('defaultAssetBuyAmount') || undefined, + affiliateInfo: affiliateInfoOverride, } const renderOptions = Object.assign({}, renderOptionsDefaults, removeUndefined(renderOptionsOverrides)); zeroExInstant.render(renderOptions); -- cgit v1.2.3