aboutsummaryrefslogtreecommitdiffstats
path: root/mascara
diff options
context:
space:
mode:
authorChi Kei Chan <chikeichan@gmail.com>2017-09-26 05:51:49 +0800
committerChi Kei Chan <chikeichan@gmail.com>2017-10-21 12:51:37 +0800
commit5cbbb476b3eb7a5fd70b014b2a1a83fea7092b58 (patch)
tree17e4223f56f3a73944b60be5ec28e8bc98c8eefd /mascara
parent5aaa2d679b00a7a78338b9b72fa72397ad945b35 (diff)
downloadtangerine-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.js83
-rw-r--r--mascara/src/app/first-time/index.css31
-rw-r--r--mascara/src/app/shapeshift-form/index.js217
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)