From d5d99b9d2e3c793a95c68c1035246644b3ae80c6 Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 25 Oct 2018 18:35:06 -0700 Subject: chore: dont override toString of BigNumber and other PR feedback --- .../src/components/animations/slide_animations.tsx | 5 +- .../instant/src/components/asset_amount_input.tsx | 81 -------------- .../src/components/erc20_asset_amount_input.tsx | 84 ++++++++++++++ .../instant/src/components/instant_heading.tsx | 4 +- .../src/components/scaling_amount_input.tsx | 11 +- .../src/containers/selected_asset_amount_input.ts | 123 -------------------- .../selected_erc20_asset_amount_input.ts | 124 +++++++++++++++++++++ packages/instant/src/redux/actions.ts | 5 +- packages/instant/src/redux/reducer.ts | 3 +- packages/instant/src/style/theme.ts | 2 + packages/instant/src/util/asset.ts | 2 +- packages/instant/src/util/big_number.ts | 29 ----- packages/instant/src/util/big_number_input.ts | 29 +++++ 13 files changed, 257 insertions(+), 245 deletions(-) delete mode 100644 packages/instant/src/components/asset_amount_input.tsx create mode 100644 packages/instant/src/components/erc20_asset_amount_input.tsx delete mode 100644 packages/instant/src/containers/selected_asset_amount_input.ts create mode 100644 packages/instant/src/containers/selected_erc20_asset_amount_input.ts delete mode 100644 packages/instant/src/util/big_number.ts create mode 100644 packages/instant/src/util/big_number_input.ts diff --git a/packages/instant/src/components/animations/slide_animations.tsx b/packages/instant/src/components/animations/slide_animations.tsx index 7c8666861..84280372b 100644 --- a/packages/instant/src/components/animations/slide_animations.tsx +++ b/packages/instant/src/components/animations/slide_animations.tsx @@ -21,7 +21,10 @@ export interface SlideAnimationProps { animationDirection?: string; } -export const SlideAnimation = styled('div')` +export const SlideAnimation = + styled.div < + SlideAnimationProps > + ` animation-name: ${props => css` ${props.keyframes}; diff --git a/packages/instant/src/components/asset_amount_input.tsx b/packages/instant/src/components/asset_amount_input.tsx deleted file mode 100644 index 4d2dc0bd8..000000000 --- a/packages/instant/src/components/asset_amount_input.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; -import * as React from 'react'; - -import { ColorOption } from '../style/theme'; -import { ERC20Asset } from '../types'; -import { assetUtils } from '../util/asset'; -import { util } from '../util/util'; - -import { ScalingAmountInput } from './scaling_amount_input'; -import { Container, Text } from './ui'; - -// Asset amounts only apply to ERC20 assets -export interface AssetAmountInputProps { - asset?: ERC20Asset; - onChange: (value?: BigNumber, asset?: ERC20Asset) => void; - startingFontSizePx: number; - fontColor?: ColorOption; -} - -export interface AssetAmountInputState { - currentFontSizePx: number; -} - -export class AssetAmountInput extends React.Component { - public static defaultProps = { - onChange: util.boundNoop, - }; - constructor(props: AssetAmountInputProps) { - super(props); - this.state = { - currentFontSizePx: props.startingFontSizePx, - }; - } - public render(): React.ReactNode { - const { asset, onChange, ...rest } = this.props; - return ( - - - - - - - {assetUtils.formattedSymbolForAsset(asset)} - - - - ); - } - private readonly _handleChange = (value?: BigNumber): void => { - this.props.onChange(value, this.props.asset); - }; - private readonly _handleFontSizeChange = (fontSizePx: number): void => { - this.setState({ - currentFontSizePx: fontSizePx, - }); - }; - private readonly _textLengthThresholdForAsset = (asset?: ERC20Asset): number => { - if (_.isUndefined(asset)) { - return 3; - } - const symbol = asset.metaData.symbol; - if (symbol.length <= 3) { - return 5; - } - if (symbol.length === 5) { - return 3; - } - return 4; - }; -} diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx new file mode 100644 index 000000000..583fad28b --- /dev/null +++ b/packages/instant/src/components/erc20_asset_amount_input.tsx @@ -0,0 +1,84 @@ +import * as _ from 'lodash'; +import * as React from 'react'; + +import { ColorOption, transparentWhite } from '../style/theme'; +import { ERC20Asset } from '../types'; +import { assetUtils } from '../util/asset'; +import { BigNumberInput } from '../util/big_number_input'; +import { util } from '../util/util'; + +import { ScalingAmountInput } from './scaling_amount_input'; +import { Container, Text } from './ui'; + +// Asset amounts only apply to ERC20 assets +export interface ERC20AssetAmountInputProps { + asset?: ERC20Asset; + value?: BigNumberInput; + onChange: (value?: BigNumberInput, asset?: ERC20Asset) => void; + startingFontSizePx: number; + fontColor?: ColorOption; +} + +export interface ERC20AssetAmountInputState { + currentFontSizePx: number; +} + +export class ERC20AssetAmountInput extends React.Component { + public static defaultProps = { + onChange: util.boundNoop, + }; + constructor(props: ERC20AssetAmountInputProps) { + super(props); + this.state = { + currentFontSizePx: props.startingFontSizePx, + }; + } + public render(): React.ReactNode { + const { asset, onChange, ...rest } = this.props; + return ( + + + + + + + {assetUtils.formattedSymbolForAsset(asset)} + + + + ); + } + private readonly _handleChange = (value?: BigNumberInput): void => { + this.props.onChange(value, this.props.asset); + }; + private readonly _handleFontSizeChange = (fontSizePx: number): void => { + this.setState({ + currentFontSizePx: fontSizePx, + }); + }; + // For assets with symbols of different length, + // start scaling the input at different character lengths + private readonly _textLengthThresholdForAsset = (asset?: ERC20Asset): number => { + if (_.isUndefined(asset)) { + return 3; + } + const symbol = asset.metaData.symbol; + if (symbol.length <= 3) { + return 5; + } + if (symbol.length === 5) { + return 3; + } + return 4; + }; +} diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index f0a22bccb..df9856277 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -2,7 +2,7 @@ import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; import * as React from 'react'; -import { SelectedAssetAmountInput } from '../containers/selected_asset_amount_input'; +import { SelectedERC20AssetAmountInput } from '../containers/selected_erc20_asset_amount_input'; import { ColorOption } from '../style/theme'; import { AsyncProcessState, OrderState } from '../types'; import { format } from '../util/format'; @@ -48,7 +48,7 @@ export class InstantHeading extends React.Component { - + {iconOrAmounts} diff --git a/packages/instant/src/components/scaling_amount_input.tsx b/packages/instant/src/components/scaling_amount_input.tsx index 23a15305a..655ae2b74 100644 --- a/packages/instant/src/components/scaling_amount_input.tsx +++ b/packages/instant/src/components/scaling_amount_input.tsx @@ -1,9 +1,8 @@ -import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; import * as React from 'react'; import { ColorOption } from '../style/theme'; -import { BigNumberInput } from '../util/big_number'; +import { BigNumberInput } from '../util/big_number_input'; import { util } from '../util/util'; import { ScalingInput } from './scaling_input'; @@ -12,8 +11,8 @@ export interface ScalingAmountInputProps { maxFontSizePx: number; textLengthThreshold: number; fontColor?: ColorOption; - value?: BigNumber; - onChange: (value?: BigNumber) => void; + value?: BigNumberInput; + onChange: (value?: BigNumberInput) => void; onFontSizeChange: (fontSizePx: number) => void; } @@ -31,7 +30,7 @@ export class ScalingAmountInput extends React.Component onFontSizeChange={onFontSizeChange} fontColor={fontColor} onChange={this._handleChange} - value={!_.isUndefined(value) ? value.toString() : ''} + value={!_.isUndefined(value) ? value.toDisplayString() : ''} placeholder="0.00" emptyInputWidthCh={3.5} /> @@ -42,7 +41,7 @@ export class ScalingAmountInput extends React.Component let bigNumberValue; if (!_.isEmpty(value)) { try { - bigNumberValue = new BigNumberInput(event.target.value); + bigNumberValue = new BigNumberInput(value); } catch { // We don't want to allow values that can't be a BigNumber, so don't even call onChange. return; diff --git a/packages/instant/src/containers/selected_asset_amount_input.ts b/packages/instant/src/containers/selected_asset_amount_input.ts deleted file mode 100644 index f836c6967..000000000 --- a/packages/instant/src/containers/selected_asset_amount_input.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { AssetBuyer, BuyQuote } from '@0x/asset-buyer'; -import { AssetProxyId } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as _ from 'lodash'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { Dispatch } from 'redux'; - -import { Action, actions } from '../redux/actions'; -import { State } from '../redux/reducer'; -import { ColorOption } from '../style/theme'; -import { AsyncProcessState, ERC20Asset } from '../types'; -import { errorUtil } from '../util/error'; - -import { AssetAmountInput } from '../components/asset_amount_input'; - -export interface SelectedAssetAmountInputProps { - fontColor?: ColorOption; - startingFontSizePx: number; -} - -interface ConnectedState { - assetBuyer?: AssetBuyer; - value?: BigNumber; - asset?: ERC20Asset; -} - -interface ConnectedDispatch { - updateBuyQuote: (assetBuyer?: AssetBuyer, value?: BigNumber, asset?: ERC20Asset) => void; -} - -interface ConnectedProps { - value?: BigNumber; - asset?: ERC20Asset; - onChange: (value?: BigNumber, asset?: ERC20Asset) => void; -} - -type FinalProps = ConnectedProps & SelectedAssetAmountInputProps; - -const mapStateToProps = (state: State, _ownProps: SelectedAssetAmountInputProps): ConnectedState => { - const selectedAsset = state.selectedAsset; - if (_.isUndefined(selectedAsset) || selectedAsset.metaData.assetProxyId !== AssetProxyId.ERC20) { - return { - value: state.selectedAssetAmount, - }; - } - return { - assetBuyer: state.assetBuyer, - value: state.selectedAssetAmount, - asset: selectedAsset as ERC20Asset, - }; -}; - -const updateBuyQuoteAsync = async ( - assetBuyer: AssetBuyer, - dispatch: Dispatch, - asset: ERC20Asset, - assetAmount: BigNumber, -): Promise => { - // get a new buy quote. - const baseUnitValue = Web3Wrapper.toBaseUnitAmount(assetAmount, asset.metaData.decimals); - - // mark quote as pending - dispatch(actions.setQuoteRequestStatePending()); - - let newBuyQuote: BuyQuote | undefined; - try { - newBuyQuote = await assetBuyer.getBuyQuoteAsync(asset.assetData, baseUnitValue); - } catch (error) { - dispatch(actions.setQuoteRequestStateFailure()); - errorUtil.errorFlasher.flashNewError(dispatch, error); - return; - } - // We have a successful new buy quote - errorUtil.errorFlasher.clearError(dispatch); - // invalidate the last buy quote. - dispatch(actions.updateLatestBuyQuote(newBuyQuote)); -}; - -const debouncedUpdateBuyQuoteAsync = _.debounce(updateBuyQuoteAsync, 200, { trailing: true }); - -const mapDispatchToProps = ( - dispatch: Dispatch, - _ownProps: SelectedAssetAmountInputProps, -): ConnectedDispatch => ({ - updateBuyQuote: (assetBuyer, value, asset) => { - // Update the input - dispatch(actions.updateSelectedAssetAmount(value)); - // invalidate the last buy quote. - dispatch(actions.updateLatestBuyQuote(undefined)); - // reset our buy state - dispatch(actions.updateBuyOrderState({ processState: AsyncProcessState.NONE })); - - if (!_.isUndefined(value) && !_.isUndefined(asset) && !_.isUndefined(assetBuyer)) { - // even if it's debounced, give them the illusion it's loading - dispatch(actions.setQuoteRequestStatePending()); - // tslint:disable-next-line:no-floating-promises - debouncedUpdateBuyQuoteAsync(assetBuyer, dispatch, asset, value); - } - }, -}); - -const mergeProps = ( - connectedState: ConnectedState, - connectedDispatch: ConnectedDispatch, - ownProps: SelectedAssetAmountInputProps, -): FinalProps => { - return { - ...ownProps, - asset: connectedState.asset, - value: connectedState.value, - onChange: (value, asset) => { - connectedDispatch.updateBuyQuote(connectedState.assetBuyer, value, asset); - }, - }; -}; - -export const SelectedAssetAmountInput: React.ComponentClass = connect( - mapStateToProps, - mapDispatchToProps, - mergeProps, -)(AssetAmountInput); diff --git a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts new file mode 100644 index 000000000..078f96cd4 --- /dev/null +++ b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts @@ -0,0 +1,124 @@ +import { AssetBuyer, BuyQuote } from '@0x/asset-buyer'; +import { AssetProxyId } from '@0x/types'; +import { BigNumber } from '@0x/utils'; +import { Web3Wrapper } from '@0x/web3-wrapper'; +import * as _ from 'lodash'; +import * as React from 'react'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; + +import { Action, actions } from '../redux/actions'; +import { State } from '../redux/reducer'; +import { ColorOption } from '../style/theme'; +import { AsyncProcessState, ERC20Asset } from '../types'; +import { BigNumberInput } from '../util/big_number_input'; +import { errorUtil } from '../util/error'; + +import { ERC20AssetAmountInput } from '../components/erc20_asset_amount_input'; + +export interface SelectedERC20AssetAmountInputProps { + fontColor?: ColorOption; + startingFontSizePx: number; +} + +interface ConnectedState { + assetBuyer?: AssetBuyer; + value?: BigNumberInput; + asset?: ERC20Asset; +} + +interface ConnectedDispatch { + updateBuyQuote: (assetBuyer?: AssetBuyer, value?: BigNumberInput, asset?: ERC20Asset) => void; +} + +interface ConnectedProps { + value?: BigNumberInput; + asset?: ERC20Asset; + onChange: (value?: BigNumberInput, asset?: ERC20Asset) => void; +} + +type FinalProps = ConnectedProps & SelectedERC20AssetAmountInputProps; + +const mapStateToProps = (state: State, _ownProps: SelectedERC20AssetAmountInputProps): ConnectedState => { + const selectedAsset = state.selectedAsset; + if (_.isUndefined(selectedAsset) || selectedAsset.metaData.assetProxyId !== AssetProxyId.ERC20) { + return { + value: state.selectedAssetAmount, + }; + } + return { + assetBuyer: state.assetBuyer, + value: state.selectedAssetAmount, + asset: selectedAsset as ERC20Asset, + }; +}; + +const updateBuyQuoteAsync = async ( + assetBuyer: AssetBuyer, + dispatch: Dispatch, + asset: ERC20Asset, + assetAmount: BigNumber, +): Promise => { + // get a new buy quote. + const baseUnitValue = Web3Wrapper.toBaseUnitAmount(assetAmount, asset.metaData.decimals); + + // mark quote as pending + dispatch(actions.setQuoteRequestStatePending()); + + let newBuyQuote: BuyQuote | undefined; + try { + newBuyQuote = await assetBuyer.getBuyQuoteAsync(asset.assetData, baseUnitValue); + } catch (error) { + dispatch(actions.setQuoteRequestStateFailure()); + errorUtil.errorFlasher.flashNewError(dispatch, error); + return; + } + // We have a successful new buy quote + errorUtil.errorFlasher.clearError(dispatch); + // invalidate the last buy quote. + dispatch(actions.updateLatestBuyQuote(newBuyQuote)); +}; + +const debouncedUpdateBuyQuoteAsync = _.debounce(updateBuyQuoteAsync, 200, { trailing: true }); + +const mapDispatchToProps = ( + dispatch: Dispatch, + _ownProps: SelectedERC20AssetAmountInputProps, +): ConnectedDispatch => ({ + updateBuyQuote: (assetBuyer, value, asset) => { + // Update the input + dispatch(actions.updateSelectedAssetAmount(value)); + // invalidate the last buy quote. + dispatch(actions.updateLatestBuyQuote(undefined)); + // reset our buy state + dispatch(actions.updateBuyOrderState({ processState: AsyncProcessState.NONE })); + + if (!_.isUndefined(value) && !_.isUndefined(asset) && !_.isUndefined(assetBuyer)) { + // even if it's debounced, give them the illusion it's loading + dispatch(actions.setQuoteRequestStatePending()); + // tslint:disable-next-line:no-floating-promises + debouncedUpdateBuyQuoteAsync(assetBuyer, dispatch, asset, value); + } + }, +}); + +const mergeProps = ( + connectedState: ConnectedState, + connectedDispatch: ConnectedDispatch, + ownProps: SelectedERC20AssetAmountInputProps, +): FinalProps => { + return { + ...ownProps, + asset: connectedState.asset, + value: connectedState.value, + onChange: (value, asset) => { + connectedDispatch.updateBuyQuote(connectedState.assetBuyer, value, asset); + }, + }; +}; + +export const SelectedERC20AssetAmountInput: React.ComponentClass = connect( + mapStateToProps, + mapDispatchToProps, + mergeProps, +)(ERC20AssetAmountInput); diff --git a/packages/instant/src/redux/actions.ts b/packages/instant/src/redux/actions.ts index 5a4099f15..46045024b 100644 --- a/packages/instant/src/redux/actions.ts +++ b/packages/instant/src/redux/actions.ts @@ -2,6 +2,8 @@ import { BuyQuote } from '@0x/asset-buyer'; import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; +import { BigNumberInput } from '../util/big_number_input'; + import { ActionsUnion, OrderState } from '../types'; export interface PlainAction { @@ -36,7 +38,8 @@ export enum ActionTypes { export const actions = { updateEthUsdPrice: (price?: BigNumber) => createAction(ActionTypes.UPDATE_ETH_USD_PRICE, price), - updateSelectedAssetAmount: (amount?: BigNumber) => createAction(ActionTypes.UPDATE_SELECTED_ASSET_AMOUNT, amount), + updateSelectedAssetAmount: (amount?: BigNumberInput) => + createAction(ActionTypes.UPDATE_SELECTED_ASSET_AMOUNT, amount), 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), diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index c6a05ac52..665cba257 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 { Asset, AssetMetaData, AsyncProcessState, DisplayStatus, Network, OrderState } from '../types'; import { assetUtils } from '../util/asset'; +import { BigNumberInput } from '../util/big_number_input'; import { Action, ActionTypes } from './actions'; @@ -14,7 +15,7 @@ export interface State { assetBuyer?: AssetBuyer; assetMetaDataMap: ObjectMap; selectedAsset?: Asset; - selectedAssetAmount?: BigNumber; + selectedAssetAmount?: BigNumberInput; buyOrderState: OrderState; ethUsdPrice?: BigNumber; latestBuyQuote?: BuyQuote; diff --git a/packages/instant/src/style/theme.ts b/packages/instant/src/style/theme.ts index be527a12c..6575ff9f4 100644 --- a/packages/instant/src/style/theme.ts +++ b/packages/instant/src/style/theme.ts @@ -28,4 +28,6 @@ export const theme: Theme = { darkOrange: '#F2994C', }; +export const transparentWhite = 'rgba(255,255,255,0.3)'; + export { styled, css, keyframes, ThemeProvider }; diff --git a/packages/instant/src/util/asset.ts b/packages/instant/src/util/asset.ts index e42727d84..2c5b6325d 100644 --- a/packages/instant/src/util/asset.ts +++ b/packages/instant/src/util/asset.ts @@ -51,7 +51,7 @@ export const assetUtils = { if (symbol.length <= 5) { return symbol; } - return `${symbol.slice(0, 3)}...`; + return `${symbol.slice(0, 3)}…`; }, getAssociatedAssetDataIfExists: (assetData: string, network: Network): string | undefined => { const assetDataGroupIfExists = _.find(assetDataNetworkMapping, value => value[network] === assetData); diff --git a/packages/instant/src/util/big_number.ts b/packages/instant/src/util/big_number.ts deleted file mode 100644 index a34d22d76..000000000 --- a/packages/instant/src/util/big_number.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; - -/** - * A BigNumber extension that is more flexible about decimal strings. - * Such as allowing: - * new BigNumberInput(0.) => 0 - * new BigNumberInput(1.) => 1 - * new BigNumberInput(1..) => still throws - */ -export class BigNumberInput extends BigNumber { - private readonly _hasDecimalPeriod: boolean; - constructor(bigNumberString: string) { - const hasDecimalPeriod = _.endsWith(bigNumberString, '.'); - let internalString = bigNumberString; - if (hasDecimalPeriod) { - internalString = bigNumberString.slice(0, bigNumberString.length - 1); - } - super(internalString); - this._hasDecimalPeriod = hasDecimalPeriod; - } - public toString(): string { - const internalString = super.toString(); - if (this._hasDecimalPeriod) { - return `${internalString}.`; - } - return internalString; - } -} diff --git a/packages/instant/src/util/big_number_input.ts b/packages/instant/src/util/big_number_input.ts new file mode 100644 index 000000000..d2a9a8dc5 --- /dev/null +++ b/packages/instant/src/util/big_number_input.ts @@ -0,0 +1,29 @@ +import { BigNumber } from '@0x/utils'; +import * as _ from 'lodash'; + +/** + * A BigNumber extension that is more flexible about decimal strings. + * Such as allowing: + * new BigNumberInput('0.') => 0 + * new BigNumberInput('1.') => 1 + * new BigNumberInput('1..') => still throws + */ +export class BigNumberInput extends BigNumber { + private readonly _isEndingWithDecimal: boolean; + constructor(bigNumberString: string) { + const hasDecimalPeriod = _.endsWith(bigNumberString, '.'); + let internalString = bigNumberString; + if (hasDecimalPeriod) { + internalString = bigNumberString.slice(0, -1); + } + super(internalString); + this._isEndingWithDecimal = hasDecimalPeriod; + } + public toDisplayString(): string { + const internalString = super.toString(); + if (this._isEndingWithDecimal) { + return `${internalString}.`; + } + return internalString; + } +} -- cgit v1.2.3