diff options
author | Francesco Agosti <francesco.agosti93@gmail.com> | 2018-05-18 04:15:24 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-05-18 04:15:24 +0800 |
commit | 72503c068931d644e65e1b4a78fdc940a11fb4e1 (patch) | |
tree | def4514311e9a16b5ca96c58beba5028a13b8d2e | |
parent | c9d304146008eb621397657865a184767bc6df7e (diff) | |
parent | e9e570db4f158119dc86141201b695f52b3a5ca2 (diff) | |
download | dexon-sol-tools-72503c068931d644e65e1b4a78fdc940a11fb4e1.tar dexon-sol-tools-72503c068931d644e65e1b4a78fdc940a11fb4e1.tar.gz dexon-sol-tools-72503c068931d644e65e1b4a78fdc940a11fb4e1.tar.bz2 dexon-sol-tools-72503c068931d644e65e1b4a78fdc940a11fb4e1.tar.lz dexon-sol-tools-72503c068931d644e65e1b4a78fdc940a11fb4e1.tar.xz dexon-sol-tools-72503c068931d644e65e1b4a78fdc940a11fb4e1.tar.zst dexon-sol-tools-72503c068931d644e65e1b4a78fdc940a11fb4e1.zip |
Merge pull request #596 from 0xProject/feature/website/weth-eth-conversion-errors
Show error messages in the wrapped ether item
6 files changed, 104 insertions, 43 deletions
diff --git a/packages/website/ts/components/inputs/balance_bounded_input.tsx b/packages/website/ts/components/inputs/balance_bounded_input.tsx index 68b77cfc3..f91a99355 100644 --- a/packages/website/ts/components/inputs/balance_bounded_input.tsx +++ b/packages/website/ts/components/inputs/balance_bounded_input.tsx @@ -5,7 +5,7 @@ import TextField from 'material-ui/TextField'; import * as React from 'react'; import { Link } from 'react-router-dom'; import { RequiredLabel } from 'ts/components/ui/required_label'; -import { InputErrMsg, ValidatedBigNumberCallback, WebsitePaths } from 'ts/types'; +import { ValidatedBigNumberCallback, WebsitePaths } from 'ts/types'; import { utils } from 'ts/utils/utils'; interface BalanceBoundedInputProps { @@ -14,18 +14,21 @@ interface BalanceBoundedInputProps { amount?: BigNumber; hintText?: string; onChange: ValidatedBigNumberCallback; + onErrorMsgChange?: (errorMsg: React.ReactNode) => void; shouldShowIncompleteErrs?: boolean; shouldCheckBalance: boolean; - validate?: (amount: BigNumber) => InputErrMsg; + validate?: (amount: BigNumber) => React.ReactNode; onVisitBalancesPageClick?: () => void; shouldHideVisitBalancesLink?: boolean; isDisabled?: boolean; shouldShowErrs?: boolean; shouldShowUnderline?: boolean; + inputStyle?: React.CSSProperties; + inputHintStyle?: React.CSSProperties; } interface BalanceBoundedInputState { - errMsg: InputErrMsg; + errMsg: React.ReactNode; amountString: string; } @@ -36,6 +39,7 @@ export class BalanceBoundedInput extends React.Component<BalanceBoundedInputProp isDisabled: false, shouldShowErrs: true, hintText: 'amount', + onErrorMsgChange: _.noop, shouldShowUnderline: true, }; constructor(props: BalanceBoundedInputProps) { @@ -63,17 +67,11 @@ export class BalanceBoundedInput extends React.Component<BalanceBoundedInputProp } if (shouldResetState) { const amountString = nextProps.amount.toString(); - this.setState({ - errMsg: this._validate(amountString, nextProps.balance), - amountString, - }); + this._setAmountState(amountString, nextProps.balance); } } else if (isCurrentAmountNumeric) { const amountString = ''; - this.setState({ - errMsg: this._validate(amountString, nextProps.balance), - amountString, - }); + this._setAmountState(amountString, nextProps.balance); } } public render(): React.ReactNode { @@ -99,21 +97,21 @@ export class BalanceBoundedInput extends React.Component<BalanceBoundedInputProp hintText={<span style={{ textTransform: 'capitalize' }}>{this.props.hintText}</span>} onChange={this._onValueChange.bind(this)} underlineStyle={{ width: 'calc(100% + 50px)' }} + inputStyle={this.props.inputStyle} + hintStyle={this.props.inputHintStyle} underlineShow={this.props.shouldShowUnderline} disabled={this.props.isDisabled} /> ); } private _onValueChange(e: any, amountString: string): void { - const errMsg = this._validate(amountString, this.props.balance); - this.setState( - { - amountString, - errMsg, - }, + this._setAmountState( + amountString, + this.props.balance, () => { - const isValid = _.isUndefined(errMsg); - if (utils.isNumeric(amountString) && !_.includes(amountString, '-')) { + const isValid = _.isUndefined(this._validate(amountString, this.props.balance)); + const isPositiveNumber = utils.isNumeric(amountString) && !_.includes(amountString, '-'); + if (isPositiveNumber) { this.props.onChange(isValid, new BigNumber(amountString)); } else { this.props.onChange(isValid); @@ -121,7 +119,7 @@ export class BalanceBoundedInput extends React.Component<BalanceBoundedInputProp }, ); } - private _validate(amountString: string, balance: BigNumber): InputErrMsg { + private _validate(amountString: string, balance: BigNumber): React.ReactNode { if (!utils.isNumeric(amountString)) { return amountString !== '' ? 'Must be a number' : ''; } @@ -161,4 +159,13 @@ export class BalanceBoundedInput extends React.Component<BalanceBoundedInputProp ); } } + + private _setAmountState(amount: string, balance: BigNumber, callback: () => void = _.noop): void { + const errorMsg = this._validate(amount, balance); + this.props.onErrorMsgChange(errorMsg); + this.setState({ + amountString: amount, + errMsg: errorMsg, + }, callback); + } } diff --git a/packages/website/ts/components/inputs/eth_amount_input.tsx b/packages/website/ts/components/inputs/eth_amount_input.tsx index c3822a80b..fa684d85c 100644 --- a/packages/website/ts/components/inputs/eth_amount_input.tsx +++ b/packages/website/ts/components/inputs/eth_amount_input.tsx @@ -12,6 +12,7 @@ interface EthAmountInputProps { amount?: BigNumber; hintText?: string; onChange: ValidatedBigNumberCallback; + onErrorMsgChange?: (errorMsg: React.ReactNode) => void; shouldShowIncompleteErrs: boolean; onVisitBalancesPageClick?: () => void; shouldCheckBalance: boolean; @@ -19,6 +20,8 @@ interface EthAmountInputProps { shouldShowErrs?: boolean; shouldShowUnderline?: boolean; style?: React.CSSProperties; + labelStyle?: React.CSSProperties; + inputHintStyle?: React.CSSProperties; } interface EthAmountInputState {} @@ -40,6 +43,7 @@ export class EthAmountInput extends React.Component<EthAmountInputProps, EthAmou balance={this.props.balance} amount={amount} onChange={this._onChange.bind(this)} + onErrorMsgChange={this.props.onErrorMsgChange} shouldCheckBalance={this.props.shouldCheckBalance} shouldShowIncompleteErrs={this.props.shouldShowIncompleteErrs} onVisitBalancesPageClick={this.props.onVisitBalancesPageClick} @@ -47,8 +51,10 @@ export class EthAmountInput extends React.Component<EthAmountInputProps, EthAmou hintText={this.props.hintText} shouldShowErrs={this.props.shouldShowErrs} shouldShowUnderline={this.props.shouldShowUnderline} + inputStyle={this.props.style} + inputHintStyle={this.props.inputHintStyle} /> - <div style={{ paddingTop: _.isUndefined(this.props.label) ? 15 : 40 }}>ETH</div> + <div style={this._getLabelStyle()}>ETH</div> </div> ); } @@ -58,4 +64,7 @@ export class EthAmountInput extends React.Component<EthAmountInputProps, EthAmou : ZeroEx.toBaseUnitAmount(amount, constants.DECIMAL_PLACES_ETH); this.props.onChange(isValid, baseUnitAmountIfExists); } + private _getLabelStyle(): React.CSSProperties { + return this.props.labelStyle || { paddingTop: _.isUndefined(this.props.label) ? 15 : 40 }; + } } diff --git a/packages/website/ts/components/inputs/token_amount_input.tsx b/packages/website/ts/components/inputs/token_amount_input.tsx index 9a74bdd51..f040928f1 100644 --- a/packages/website/ts/components/inputs/token_amount_input.tsx +++ b/packages/website/ts/components/inputs/token_amount_input.tsx @@ -6,7 +6,7 @@ import * as React from 'react'; import { Link } from 'react-router-dom'; import { Blockchain } from 'ts/blockchain'; import { BalanceBoundedInput } from 'ts/components/inputs/balance_bounded_input'; -import { InputErrMsg, Token, ValidatedBigNumberCallback, WebsitePaths } from 'ts/types'; +import { Token, ValidatedBigNumberCallback, WebsitePaths } from 'ts/types'; interface TokenAmountInputProps { userAddress: string; @@ -20,11 +20,14 @@ interface TokenAmountInputProps { shouldCheckBalance: boolean; shouldCheckAllowance: boolean; onChange: ValidatedBigNumberCallback; + onErrorMsgChange?: (errorMsg: React.ReactNode) => void; onVisitBalancesPageClick?: () => void; lastForceTokenStateRefetch: number; shouldShowErrs?: boolean; shouldShowUnderline?: boolean; style?: React.CSSProperties; + labelStyle?: React.CSSProperties; + inputHintStyle?: React.CSSProperties; } interface TokenAmountInputState { @@ -74,17 +77,14 @@ export class TokenAmountInput extends React.Component<TokenAmountInputProps, Tok const amount = this.props.amount ? ZeroEx.toUnitAmount(this.props.amount, this.props.token.decimals) : undefined; - const hasLabel = !_.isUndefined(this.props.label); - const style = !_.isUndefined(this.props.style) - ? this.props.style - : { height: hasLabel ? HEIGHT_WITH_LABEL : HEIGHT_WITHOUT_LABEL }; return ( - <div className="flex overflow-hidden" style={style}> + <div className="flex overflow-hidden" style={this._getStyle()}> <BalanceBoundedInput label={this.props.label} amount={amount} balance={ZeroEx.toUnitAmount(this.state.balance, this.props.token.decimals)} onChange={this._onChange.bind(this)} + onErrorMsgChange={this.props.onErrorMsgChange} validate={this._validate.bind(this)} shouldCheckBalance={this.props.shouldCheckBalance} shouldShowIncompleteErrs={this.props.shouldShowIncompleteErrs} @@ -93,8 +93,10 @@ export class TokenAmountInput extends React.Component<TokenAmountInputProps, Tok hintText={this.props.hintText} shouldShowErrs={this.props.shouldShowErrs} shouldShowUnderline={this.props.shouldShowUnderline} + inputStyle={this.props.style} + inputHintStyle={this.props.inputHintStyle} /> - <div style={{ paddingTop: hasLabel ? 39 : 14 }}>{this.props.token.symbol}</div> + <div style={this._getLabelStyle()}>{this.props.token.symbol}</div> </div> ); } @@ -105,7 +107,7 @@ export class TokenAmountInput extends React.Component<TokenAmountInputProps, Tok } this.props.onChange(isValid, baseUnitAmount); } - private _validate(amount: BigNumber): InputErrMsg { + private _validate(amount: BigNumber): React.ReactNode { if (this.props.shouldCheckAllowance && amount.gt(this.state.allowance)) { return ( <span> @@ -139,4 +141,14 @@ export class TokenAmountInput extends React.Component<TokenAmountInputProps, Tok }); } } + private _getStyle(): React.CSSProperties { + const hasLabel = !_.isUndefined(this.props.label); + return !_.isUndefined(this.props.style) + ? this.props.style + : { height: hasLabel ? HEIGHT_WITH_LABEL : HEIGHT_WITHOUT_LABEL }; + } + private _getLabelStyle(): React.CSSProperties { + const hasLabel = !_.isUndefined(this.props.label); + return this.props.labelStyle || { paddingTop: hasLabel ? 39 : 14 }; + } } diff --git a/packages/website/ts/components/wallet/wrap_ether_item.tsx b/packages/website/ts/components/wallet/wrap_ether_item.tsx index 2ed924bcd..581d2ba97 100644 --- a/packages/website/ts/components/wallet/wrap_ether_item.tsx +++ b/packages/website/ts/components/wallet/wrap_ether_item.tsx @@ -31,8 +31,8 @@ export interface WrapEtherItemProps { interface WrapEtherItemState { currentInputAmount?: BigNumber; - currentInputHasErrors: boolean; isEthConversionHappening: boolean; + errorMsg: React.ReactNode; } const styles: Styles = { @@ -46,13 +46,29 @@ const styles: Styles = { padding: 4, width: 125, }, - ethAmountInput: { height: 32 }, - innerDiv: { paddingLeft: 60, paddingTop: 0 }, - wrapEtherConfirmationButtonContainer: { width: 128, top: 16 }, + amountInput: { height: 34 }, + amountInputLabel: { + paddingTop: 10, + paddingRight: 10, + paddingLeft: 5, + color: colors.grey, + fontSize: 14, + }, + amountInputHint: { + bottom: 18, + }, + innerDiv: { paddingLeft: 60, paddingTop: 0, paddingBottom: 10 }, + wrapEtherConfirmationButtonContainer: { width: 128, top: 19 }, wrapEtherConfirmationButtonLabel: { - fontSize: 10, + fontSize: 12, color: colors.white, }, + errorMsg: { + fontSize: 12, + marginTop: 4, + color: colors.red, + minHeight: 20, + }, }; export class WrapEtherItem extends React.Component<WrapEtherItemProps, WrapEtherItemState> { @@ -60,8 +76,8 @@ export class WrapEtherItem extends React.Component<WrapEtherItemProps, WrapEther super(props); this.state = { currentInputAmount: undefined, - currentInputHasErrors: false, isEthConversionHappening: false, + errorMsg: null, }; } public render(): React.ReactNode { @@ -84,7 +100,10 @@ export class WrapEtherItem extends React.Component<WrapEtherItemProps, WrapEther shouldShowIncompleteErrs={false} shouldShowErrs={false} shouldShowUnderline={false} - style={styles.ethAmountInput} + style={styles.amountInput} + labelStyle={styles.amountInputLabel} + inputHintStyle={styles.amountInputHint} + onErrorMsgChange={this._onErrorMsgChange.bind(this)} /> ) : ( <TokenAmountInput @@ -99,12 +118,16 @@ export class WrapEtherItem extends React.Component<WrapEtherItemProps, WrapEther onChange={this._onValueChange.bind(this)} amount={this.state.currentInputAmount} hintText="0.00" - shouldShowErrs={false} // TODO: error handling + shouldShowErrs={false} shouldShowUnderline={false} - style={styles.ethAmountInput} + style={styles.amountInput} + labelStyle={styles.amountInputLabel} + inputHintStyle={styles.amountInputHint} + onErrorMsgChange={this._onErrorMsgChange.bind(this)} /> )} </div> + {this._renderErrorMsg()} </div> } secondaryTextLines={2} @@ -119,7 +142,11 @@ export class WrapEtherItem extends React.Component<WrapEtherItemProps, WrapEther private _onValueChange(isValid: boolean, amount?: BigNumber): void { this.setState({ currentInputAmount: amount, - currentInputHasErrors: !isValid, + }); + } + private _onErrorMsgChange(errorMsg: React.ReactNode): void { + this.setState({ + errorMsg, }); } private _renderIsEthConversionHappeningSpinner(): React.ReactElement<{}> { @@ -144,6 +171,13 @@ export class WrapEtherItem extends React.Component<WrapEtherItemProps, WrapEther </div> ); } + private _renderErrorMsg(): React.ReactNode { + return ( + <div style={styles.errorMsg}> + {this.state.errorMsg} + </div> + ); + } private async _wrapEtherConfirmationActionAsync(): Promise<void> { this.setState({ isEthConversionHappening: true, diff --git a/packages/website/ts/pages/about/about.tsx b/packages/website/ts/pages/about/about.tsx index 360cbb136..ac67ca968 100644 --- a/packages/website/ts/pages/about/about.tsx +++ b/packages/website/ts/pages/about/about.tsx @@ -37,7 +37,7 @@ const teamRow1: ProfileInfo[] = [ name: 'Fabio Berger', title: 'Senior Engineer', description: `Full-stack blockchain engineer. Previously software engineer \ - at Airtable and founder of WealthLift. Computer science at Duke.`, + at Airtable and founder of WealthLift. Computer Science at Duke.`, image: '/images/team/fabio.jpg', linkedIn: 'https://www.linkedin.com/in/fabio-berger-03ab261a/', github: 'https://github.com/fabioberger', @@ -60,7 +60,7 @@ const teamRow2: ProfileInfo[] = [ name: 'Leonid Logvinov', title: 'Engineer', description: `Full-stack blockchain engineer. Previously blockchain engineer \ - at Neufund. Computer science at University of Warsaw.`, + at Neufund. Computer Science at University of Warsaw.`, image: '/images/team/leonid.png', linkedIn: 'https://www.linkedin.com/in/leonidlogvinov/', github: 'https://github.com/LogvinovLeon', @@ -152,7 +152,7 @@ const teamRow5: ProfileInfo[] = [ { name: 'Francesco Agosti', title: 'Senior Frontend Engineer', - description: `Full-stack engineer. Previously senior software engineer at Yelp. Computer science Duke.`, + description: `Full-stack engineer. Previously senior software engineer at Yelp. Computer Science at Duke.`, image: 'images/team/fragosti.png', linkedIn: 'https://www.linkedin.com/in/fragosti/', github: 'http://github.com/fragosti', diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts index 5caf5e73c..33e4d6c30 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -207,7 +207,6 @@ export interface ContractEvent { args: any; } -export type InputErrMsg = React.ReactNode | string | undefined; export type ValidatedBigNumberCallback = (isValid: boolean, amount?: BigNumber) => void; export enum ScreenWidths { Sm = 'SM', |