diff options
author | Chi Kei Chan <chikeichan@gmail.com> | 2017-09-26 05:51:49 +0800 |
---|---|---|
committer | Chi Kei Chan <chikeichan@gmail.com> | 2017-10-21 12:51:37 +0800 |
commit | 5cbbb476b3eb7a5fd70b014b2a1a83fea7092b58 (patch) | |
tree | 17e4223f56f3a73944b60be5ec28e8bc98c8eefd /mascara | |
parent | 5aaa2d679b00a7a78338b9b72fa72397ad945b35 (diff) | |
download | tangerine-wallet-browser-5cbbb476b3eb7a5fd70b014b2a1a83fea7092b58.tar tangerine-wallet-browser-5cbbb476b3eb7a5fd70b014b2a1a83fea7092b58.tar.gz tangerine-wallet-browser-5cbbb476b3eb7a5fd70b014b2a1a83fea7092b58.tar.bz2 tangerine-wallet-browser-5cbbb476b3eb7a5fd70b014b2a1a83fea7092b58.tar.lz tangerine-wallet-browser-5cbbb476b3eb7a5fd70b014b2a1a83fea7092b58.tar.xz tangerine-wallet-browser-5cbbb476b3eb7a5fd70b014b2a1a83fea7092b58.tar.zst tangerine-wallet-browser-5cbbb476b3eb7a5fd70b014b2a1a83fea7092b58.zip |
ShapeShift Integration
Diffstat (limited to 'mascara')
-rw-r--r-- | mascara/src/app/first-time/buy-ether-screen.js | 83 | ||||
-rw-r--r-- | mascara/src/app/first-time/index.css | 31 | ||||
-rw-r--r-- | mascara/src/app/shapeshift-form/index.js | 217 |
3 files changed, 245 insertions, 86 deletions
diff --git a/mascara/src/app/first-time/buy-ether-screen.js b/mascara/src/app/first-time/buy-ether-screen.js index 44141db64..45b2df1c8 100644 --- a/mascara/src/app/first-time/buy-ether-screen.js +++ b/mascara/src/app/first-time/buy-ether-screen.js @@ -3,6 +3,7 @@ import classnames from 'classnames' import {connect} from 'react-redux' import {qrcode} from 'qrcode-npm' import copyToClipboard from 'copy-to-clipboard' +import ShapeShiftForm from '../shapeshift-form' import Identicon from '../../../../ui/app/components/identicon' import {buyEth, showAccountDetail} from '../../../../ui/app/actions' @@ -79,12 +80,6 @@ class BuyEtherScreen extends Component { ) } - renderShapeShiftLogo () { - return ( - <div className='shapeshift-logo' /> - ) - } - renderCoinbaseForm () { const {goToCoinbase, address} = this.props @@ -119,83 +114,13 @@ class BuyEtherScreen extends Component { case OPTION_VALUES.SHAPESHIFT: return ( <div className='buy-ether__action-content-wrapper'> - <div>{this.renderShapeShiftLogo()}</div> + <div className='shapeshift-logo' /> <div className='buy-ether__body-text'> Trade any leading blockchain asset for any other. Protection by Design. No Account Needed. </div> - <div className='shapeshift-form'> - <div className='shapeshift-form__selectors'> - <div className='shapeshift-form__selector'> - <div className='shapeshift-form__selector-label'> - Deposit - </div> - <select className='shapeshift-form__selector-input'> - <option value='btc'>BTC</option> - </select> - </div> - <div - className='icon shapeshift-form__caret' - style={{ backgroundImage: 'url(images/caret-right.svg)'}} - /> - <div className='shapeshift-form__selector'> - <div className='shapeshift-form__selector-label'> - Receive - </div> - <select className='shapeshift-form__selector-input'> - <option value='btc'>BTC</option> - </select> - </div> - </div> - <div className='shapeshift-form__address-input-wrapper'> - <div className='shapeshift-form__address-input-label'> - Your Refund Address - </div> - <input type='text' className='shapeshift-form__address-input' /> - </div> - <div className='shapeshift-form__metadata'> - <div className='shapeshift-form__metadata-wrapper'> - <div className='shapeshift-form__metadata-label'> - Status: - </div> - <div className='shapeshift-form__metadata-value'> - Available - </div> - </div> - <div className='shapeshift-form__metadata-wrapper'> - <div className='shapeshift-form__metadata-label'> - Limit: - </div> - <div className='shapeshift-form__metadata-value'> - 2.06856464 - </div> - </div> - <div className='shapeshift-form__metadata-wrapper'> - <div className='shapeshift-form__metadata-label'> - Exchange Rate: - </div> - <div className='shapeshift-form__metadata-value'> - 12.21840214 - </div> - </div> - <div className='shapeshift-form__metadata-wrapper'> - <div className='shapeshift-form__metadata-label'> - Minimum: - </div> - <div className='shapeshift-form__metadata-value'> - 0.000163 - </div> - </div> - </div> - </div> - <div className='buy-ether__buttons'> - <button - className='first-time-flow__button' - > - Buy - </button> - </div> + <ShapeShiftForm btnClass='first-time-flow__button' /> </div> - ) + ) case OPTION_VALUES.QR_CODE: return ( <div className='buy-ether__action-content-wrapper'> diff --git a/mascara/src/app/first-time/index.css b/mascara/src/app/first-time/index.css index 50d0d2fb7..c9c3f6380 100644 --- a/mascara/src/app/first-time/index.css +++ b/mascara/src/app/first-time/index.css @@ -578,7 +578,8 @@ button.first-time-flow__button--tertiary:hover { flex: 1 0 auto; } -.shapeshift-form__selector-label { +.shapeshift-form__selector-label, +.shapeshift-form__deposit-instruction { color: #757575; color: rgba(0, 0, 0, 0.45); font-family: Montserrat Light; @@ -597,10 +598,8 @@ button.first-time-flow__button--tertiary:hover { text-align: center; width: 100%; height: 45px; -} - -.shapeshift-form__address-input-wrapper { - padding-bottom: 24px; + line-height: 44px; + font-family: Montserrat Light; } .shapeshift-form__address-input-label { @@ -622,6 +621,18 @@ button.first-time-flow__button--tertiary:hover { width: 100%; } +.shapeshift-form__address-input-wrapper--error .shapeshift-form__address-input { + border-color: #FF001F; +} + +.shapeshift-form__address-input-error-message { + color: #FF001F; + font-family: Montserrat Light; + font-size: 12px; + height: 24px; + line-height: 18px; +} + .shapeshift-form__metadata { display: flex; flex-flow: row wrap; @@ -640,11 +651,11 @@ button.first-time-flow__button--tertiary:hover { } .shapeshift-form__metadata-wrapper:nth-child(odd) { - padding-right: 24px; + padding-right: 14px; } .shapeshift-form__metadata-label { - flex: 1 0 65%; + flex: 1 0 60%; } .shapeshift-form__metadata-value { @@ -654,3 +665,9 @@ button.first-time-flow__button--tertiary:hover { text-overflow: ellipsis; white-space: nowrap; } + +.shapeshift-form__qr-code { + display: flex; + flex-flow: row nowrap; + justify-content: center; +} diff --git a/mascara/src/app/shapeshift-form/index.js b/mascara/src/app/shapeshift-form/index.js new file mode 100644 index 000000000..15c7e95e1 --- /dev/null +++ b/mascara/src/app/shapeshift-form/index.js @@ -0,0 +1,217 @@ +import React, {Component, PropTypes} from 'react' +import classnames from 'classnames' +import {qrcode} from 'qrcode-npm' +import {connect} from 'react-redux' +import {shapeShiftSubview, pairUpdate, buyWithShapeShift} from '../../../../ui/app/actions' +import {isValidAddress} from '../../../../ui/app/util' + +export class ShapeShiftForm extends Component { + static propTypes = { + selectedAddress: PropTypes.string.isRequired, + btnClass: PropTypes.string.isRequired, + tokenExchangeRates: PropTypes.object.isRequired, + coinOptions: PropTypes.object.isRequired, + shapeShiftSubview: PropTypes.func.isRequired, + pairUpdate: PropTypes.func.isRequired, + buyWithShapeShift: PropTypes.func.isRequired, + }; + + state = { + depositCoin: 'btc', + refundAddress: '', + showQrCode: false, + depositAddress: '', + errorMessage: '', + isLoading: false, + }; + + componentWillMount () { + this.props.shapeShiftSubview() + } + + onCoinChange = e => { + const coin = e.target.value + this.setState({ + depositCoin: coin, + errorMessage: '', + }) + this.props.pairUpdate(coin) + } + + onBuyWithShapeShift = () => { + this.setState({ + isLoading: true, + showQrCode: true, + }) + + const { + buyWithShapeShift, + selectedAddress: withdrawal, + } = this.props + const { + refundAddress: returnAddress, + depositCoin, + } = this.state + const pair = `${depositCoin}_eth` + const data = { + withdrawal, + pair, + returnAddress, + // Public api key + 'apiKey': '803d1f5df2ed1b1476e4b9e6bcd089e34d8874595dda6a23b67d93c56ea9cc2445e98a6748b219b2b6ad654d9f075f1f1db139abfa93158c04e825db122c14b6', + } + + if (isValidAddress(withdrawal)) { + buyWithShapeShift(data) + .then(d => this.setState({ + showQrCode: true, + depositAddress: d.deposit, + isLoading: false, + })) + .catch(() => this.setState({ + showQrCode: false, + errorMessage: 'Invalid Request', + isLoading: false, + })) + } + } + + renderMetadata (label, value) { + return ( + <div className='shapeshift-form__metadata-wrapper'> + <div className='shapeshift-form__metadata-label'> + {label}: + </div> + <div className='shapeshift-form__metadata-value'> + {value} + </div> + </div> + ) + } + + renderMarketInfo () { + const { depositCoin } = this.state + const coinPair = `${depositCoin}_eth` + const { tokenExchangeRates } = this.props + const { + limit, + rate, + minimum, + } = tokenExchangeRates[coinPair] || {} + + return ( + <div className='shapeshift-form__metadata'> + {this.renderMetadata('Status', limit ? 'Available' : 'Unavailable')} + {this.renderMetadata('Limit', limit)} + {this.renderMetadata('Exchange Rate', rate)} + {this.renderMetadata('Minimum', minimum)} + </div> + ) + } + + renderQrCode () { + const { depositAddress, isLoading } = this.state + const qrImage = qrcode(4, 'M') + qrImage.addData(depositAddress) + qrImage.make() + + return ( + <div className='shapeshift-form'> + <div className='shapeshift-form__deposit-instruction'> + Deposit your BTC to the address bellow: + </div> + <div className='shapeshift-form__qr-code'> + {isLoading + ? <img src='images/loading.svg' style={{ width: '60px' }} /> + : <div dangerouslySetInnerHTML={{ __html: qrImage.createTableTag(4) }} /> + } + </div> + {this.renderMarketInfo()} + </div> + ) + } + + render () { + const { coinOptions, btnClass } = this.props + const { depositCoin, errorMessage, showQrCode } = this.state + const coinPair = `${depositCoin}_eth` + const { tokenExchangeRates } = this.props + const token = tokenExchangeRates[coinPair] + + return showQrCode ? this.renderQrCode() : ( + <div> + <div className='shapeshift-form'> + <div className='shapeshift-form__selectors'> + <div className='shapeshift-form__selector'> + <div className='shapeshift-form__selector-label'> + Deposit + </div> + <select + className='shapeshift-form__selector-input' + value={this.state.depositCoin} + onChange={this.onCoinChange} + > + {Object.entries(coinOptions).map(([coin]) => ( + <option key={coin} value={coin.toLowerCase()}> + {coin} + </option> + ))} + </select> + </div> + <div + className='icon shapeshift-form__caret' + style={{ backgroundImage: 'url(images/caret-right.svg)'}} + /> + <div className='shapeshift-form__selector'> + <div className='shapeshift-form__selector-label'> + Receive + </div> + <div className='shapeshift-form__selector-input'> + ETH + </div> + </div> + </div> + <div + className={classnames('shapeshift-form__address-input-wrapper', { + 'shapeshift-form__address-input-wrapper--error': errorMessage, + })} + > + <div className='shapeshift-form__address-input-label'> + Your Refund Address + </div> + <input + type='text' + className='shapeshift-form__address-input' + onChange={e => this.setState({ + refundAddress: e.target.value, + errorMessage: '', + })} + /> + <div className='shapeshift-form__address-input-error-message'> + {errorMessage} + </div> + </div> + {this.renderMarketInfo()} + </div> + <button + className={btnClass} + disabled={!token} + onClick={this.onBuyWithShapeShift} + > + Buy + </button> + </div> + ) + } +} + +export default connect( + ({ metamask: { coinOptions, tokenExchangeRates, selectedAddress } }) => ({ + coinOptions, tokenExchangeRates, selectedAddress, + }), + dispatch => ({ + shapeShiftSubview: () => dispatch(shapeShiftSubview()), + pairUpdate: coin => dispatch(pairUpdate(coin)), + buyWithShapeShift: data => dispatch(buyWithShapeShift(data)), + }) +)(ShapeShiftForm) |