From 5cbbb476b3eb7a5fd70b014b2a1a83fea7092b58 Mon Sep 17 00:00:00 2001 From: Chi Kei Chan Date: Mon, 25 Sep 2017 14:51:49 -0700 Subject: ShapeShift Integration --- mascara/src/app/first-time/buy-ether-screen.js | 83 +--------- mascara/src/app/first-time/index.css | 31 +++- mascara/src/app/shapeshift-form/index.js | 217 +++++++++++++++++++++++++ 3 files changed, 245 insertions(+), 86 deletions(-) create mode 100644 mascara/src/app/shapeshift-form/index.js (limited to 'mascara/src') 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 ( -
- ) - } - renderCoinbaseForm () { const {goToCoinbase, address} = this.props @@ -119,83 +114,13 @@ class BuyEtherScreen extends Component { case OPTION_VALUES.SHAPESHIFT: return (
-
{this.renderShapeShiftLogo()}
+
Trade any leading blockchain asset for any other. Protection by Design. No Account Needed.
-
-
-
-
- Deposit -
- -
-
-
-
- Receive -
- -
-
-
-
- Your Refund Address -
- -
-
-
-
- Status: -
-
- Available -
-
-
-
- Limit: -
-
- 2.06856464 -
-
-
-
- Exchange Rate: -
-
- 12.21840214 -
-
-
-
- Minimum: -
-
- 0.000163 -
-
-
-
-
- -
+
- ) + ) case OPTION_VALUES.QR_CODE: return (
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 ( +
+
+ {label}: +
+
+ {value} +
+
+ ) + } + + renderMarketInfo () { + const { depositCoin } = this.state + const coinPair = `${depositCoin}_eth` + const { tokenExchangeRates } = this.props + const { + limit, + rate, + minimum, + } = tokenExchangeRates[coinPair] || {} + + return ( +
+ {this.renderMetadata('Status', limit ? 'Available' : 'Unavailable')} + {this.renderMetadata('Limit', limit)} + {this.renderMetadata('Exchange Rate', rate)} + {this.renderMetadata('Minimum', minimum)} +
+ ) + } + + renderQrCode () { + const { depositAddress, isLoading } = this.state + const qrImage = qrcode(4, 'M') + qrImage.addData(depositAddress) + qrImage.make() + + return ( +
+
+ Deposit your BTC to the address bellow: +
+
+ {isLoading + ? + :
+ } +
+ {this.renderMarketInfo()} +
+ ) + } + + 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() : ( +
+
+
+
+
+ Deposit +
+ +
+
+
+
+ Receive +
+
+ ETH +
+
+
+
+
+ Your Refund Address +
+ this.setState({ + refundAddress: e.target.value, + errorMessage: '', + })} + /> +
+ {errorMessage} +
+
+ {this.renderMarketInfo()} +
+ +
+ ) + } +} + +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) -- cgit v1.2.3