aboutsummaryrefslogtreecommitdiffstats
path: root/ui/app/components
diff options
context:
space:
mode:
authorKevin Serrano <kevgagser@gmail.com>2016-08-16 01:50:53 +0800
committerKevin Serrano <kevgagser@gmail.com>2016-08-16 01:50:53 +0800
commit6895d330ffdf0f071e4df3fb9da47f2ea6fc7491 (patch)
tree64e170d2bd39434674e0c92bb637fd1d2c57debc /ui/app/components
parentcb0c1f25bacab5f6ee9348dbc3dc112f4d77560f (diff)
parent271e3c4fdf1a86a989d642c18815d7f6537ed951 (diff)
downloadtangerine-wallet-browser-6895d330ffdf0f071e4df3fb9da47f2ea6fc7491.tar.gz
tangerine-wallet-browser-6895d330ffdf0f071e4df3fb9da47f2ea6fc7491.tar.zst
tangerine-wallet-browser-6895d330ffdf0f071e4df3fb9da47f2ea6fc7491.zip
Merge master.
Diffstat (limited to 'ui/app/components')
-rw-r--r--ui/app/components/buy-button-subview.js123
-rw-r--r--ui/app/components/coinbase-form.js162
-rw-r--r--ui/app/components/drop-menu-item.js3
-rw-r--r--ui/app/components/network.js14
-rw-r--r--ui/app/components/qr-code.js60
-rw-r--r--ui/app/components/shapeshift-form.js311
6 files changed, 657 insertions, 16 deletions
diff --git a/ui/app/components/buy-button-subview.js b/ui/app/components/buy-button-subview.js
new file mode 100644
index 000000000..cebb8f3f6
--- /dev/null
+++ b/ui/app/components/buy-button-subview.js
@@ -0,0 +1,123 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+const connect = require('react-redux').connect
+const actions = require('../actions')
+const CoinbaseForm = require('./coinbase-form')
+const ShapeshiftForm = require('./shapeshift-form')
+const extension = require('../../../app/scripts/lib/extension')
+
+module.exports = connect(mapStateToProps)(BuyButtonSubview)
+
+function mapStateToProps (state) {
+ return {
+ selectedAccount: state.selectedAccount,
+ warning: state.appState.warning,
+ buyView: state.appState.buyView,
+ network: state.metamask.network,
+ provider: state.metamask.provider,
+ }
+}
+
+inherits(BuyButtonSubview, Component)
+function BuyButtonSubview () {
+ Component.call(this)
+}
+
+BuyButtonSubview.prototype.render = function () {
+ const props = this.props
+ const currentForm = props.buyView.formView
+
+ return (
+ h('.buy-eth-section', [
+ // back button
+ h('.flex-row', {
+ style: {
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ }, [
+ h('i.fa.fa-arrow-left.fa-lg.cursor-pointer.color-orange', {
+ onClick: () => props.dispatch(actions.backToAccountDetail(props.selectedAccount)),
+ style: {
+ position: 'absolute',
+ left: '10px',
+ },
+ }),
+ h('h2.page-subtitle', 'Buy Eth'),
+ ]),
+ h('h3.flex-row.text-transform-uppercase', {
+ style: {
+ background: '#EBEBEB',
+ color: '#AEAEAE',
+ paddingTop: '4px',
+ justifyContent: 'space-around',
+ },
+ }, [
+ h(currentForm.coinbase ? '.activeForm' : '.inactiveForm', {
+ onClick: () => props.dispatch(actions.coinBaseSubview()),
+ }, 'Coinbase'),
+ h('a', {
+ onClick: (event) => this.navigateTo('https://github.com/MetaMask/faq/blob/master/COINBASE.md'),
+ }, [
+ h('i.fa.fa-question-circle', {
+ style: {
+ position: 'relative',
+ right: '33px',
+ },
+ }),
+ ]),
+ h(currentForm.shapeshift ? '.activeForm' : '.inactiveForm', {
+ onClick: () => props.dispatch(actions.shapeShiftSubview(props.provider.type)),
+ }, 'Shapeshift'),
+
+ h('a', {
+ href: 'https://github.com/MetaMask/faq/blob/master/COINBASE.md',
+ onClick: (event) => this.navigateTo('https://info.shapeshift.io/about'),
+ }, [
+ h('i.fa.fa-question-circle', {
+ style: {
+ position: 'relative',
+ right: '28px',
+ },
+ }),
+ ]),
+ ]),
+ this.formVersionSubview(),
+ ])
+ )
+}
+
+BuyButtonSubview.prototype.formVersionSubview = function () {
+ if (this.props.network === '1') {
+ if (this.props.buyView.formView.coinbase) {
+ return h(CoinbaseForm, this.props)
+ } else if (this.props.buyView.formView.shapeshift) {
+ return h(ShapeshiftForm, this.props)
+ }
+ } else {
+ return h('div.flex-column', {
+ style: {
+ alignItems: 'center',
+ margin: '50px',
+ },
+ }, [
+ h('h3.text-transform-uppercase', {
+ style: {
+ width: '225px',
+ },
+ }, 'In order to access this feature please switch too the Main Network'),
+ h('h3.text-transform-uppercase', 'or:'),
+ this.props.network === '2' ? h('button.text-transform-uppercase', {
+ onClick: () => this.props.dispatch(actions.buyEth()),
+ style: {
+ marginTop: '15px',
+ },
+ }, 'Go To Test Faucet') : null,
+ ])
+ }
+}
+
+BuyButtonSubview.prototype.navigateTo = function (url) {
+ extension.tabs.create({ url })
+}
diff --git a/ui/app/components/coinbase-form.js b/ui/app/components/coinbase-form.js
new file mode 100644
index 000000000..efd05ec96
--- /dev/null
+++ b/ui/app/components/coinbase-form.js
@@ -0,0 +1,162 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+const connect = require('react-redux').connect
+const actions = require('../actions')
+
+const isValidAddress = require('../util').isValidAddress
+module.exports = connect(mapStateToProps)(CoinbaseForm)
+
+function mapStateToProps(state) {
+ return {
+ selectedAccount: state.selectedAccount,
+ warning: state.appState.warning,
+ }
+}
+
+inherits(CoinbaseForm, Component)
+
+function CoinbaseForm() {
+ Component.call(this)
+}
+
+CoinbaseForm.prototype.render = function () {
+ var props = this.props
+ var amount = props.buyView.amount
+ var address = props.buyView.buyAddress
+
+ return h('.flex-column', {
+ style: {
+ // margin: '10px',
+ padding: '25px',
+ },
+ }, [
+ h('.flex-column', {
+ style: {
+ alignItems: 'flex-start',
+ },
+ }, [
+ h('.flex-row', [
+ h('div', 'Address:'),
+ h('.ellip-address', address),
+ ]),
+ h('.flex-row', [
+ h('div', 'Amount: $'),
+ h('.input-container', [
+ h('input.buy-inputs', {
+ style: {
+ width: '3em',
+ boxSizing: 'border-box',
+ },
+ defaultValue: amount,
+ onChange: this.handleAmount.bind(this),
+ }),
+ h('i.fa.fa-pencil-square-o.edit-text', {
+ style: {
+ fontSize: '12px',
+ color: '#F7861C',
+ position: 'relative',
+ bottom: '5px',
+ right: '11px',
+ },
+ }),
+ ]),
+ ]),
+ ]),
+
+ h('.info-gray', {
+ style: {
+ fontSize: '10px',
+ fontFamily: 'Montserrat Light',
+ margin: '15px',
+ lineHeight: '13px',
+ },
+ },
+ `there is a USD$ 5 a day max and a USD$ 50
+ dollar limit per the life time of an account without a
+ coinbase account. A fee of 3.75% will be aplied to debit/credit cards.`),
+
+ !props.warning ? h('div', {
+ style: {
+ width: '340px',
+ height: '22px',
+ },
+ }) : props.warning && h('span.error.flex-center', props.warning),
+
+
+ h('.flex-row', {
+ style: {
+ justifyContent: 'space-around',
+ margin: '33px',
+ },
+ }, [
+ h('button', {
+ onClick: this.toCoinbase.bind(this),
+ }, 'Continue to Coinbase'),
+
+ h('button', {
+ onClick: () => props.dispatch(actions.backTobuyView(props.accounts.address)),
+ }, 'Cancel'),
+ ]),
+ ])
+}
+CoinbaseForm.prototype.handleAmount = function (event) {
+ this.props.dispatch(actions.updateCoinBaseAmount(event.target.value))
+}
+CoinbaseForm.prototype.handleAddress = function (event) {
+ this.props.dispatch(actions.updateBuyAddress(event.target.value))
+}
+CoinbaseForm.prototype.toCoinbase = function () {
+ var props = this.props
+ var amount = props.buyView.amount
+ var address = props.buyView.buyAddress
+ var message
+
+ if (isValidAddress(address) && isValidAmountforCoinBase(amount).valid) {
+ props.dispatch(actions.buyEth(address, props.buyView.amount))
+ } else if (!isValidAmountforCoinBase(amount).valid) {
+ message = isValidAmountforCoinBase(amount).message
+ return props.dispatch(actions.showWarning(message))
+ } else {
+ message = 'Receiving address is invalid.'
+ return props.dispatch(actions.showWarning(message))
+ }
+}
+
+CoinbaseForm.prototype.renderLoading = function () {
+
+ return h('img', {
+ style: {
+ width: '27px',
+ marginRight: '-27px',
+ },
+ src: 'images/loading.svg',
+ })
+}
+
+function isValidAmountforCoinBase(amount) {
+ amount = parseFloat(amount)
+
+ if (amount) {
+ if (amount <= 5 && amount > 0) {
+ return {
+ valid: true,
+ }
+ } else if (amount > 5) {
+ return {
+ valid: false,
+ message: 'The amount can not be greater then $5',
+ }
+ } else {
+ return {
+ valid: false,
+ message: 'Can not buy amounts less then $0',
+ }
+ }
+ } else {
+ return {
+ valid: false,
+ message: 'The amount entered is not a number',
+ }
+ }
+}
diff --git a/ui/app/components/drop-menu-item.js b/ui/app/components/drop-menu-item.js
index 1a0d6cbd5..0ca1988c6 100644
--- a/ui/app/components/drop-menu-item.js
+++ b/ui/app/components/drop-menu-item.js
@@ -41,9 +41,6 @@ DropMenuItem.prototype.activeNetworkRender = function () {
case 'Main Ethereum Network':
if (providerType === 'mainnet') return h('.check', '✓')
break
- case 'Ethereum Classic Network':
- if (providerType === 'classic') return h('.check', '✓')
- break
case 'Morden Test Network':
if (activeNetwork === '2') return h('.check', '✓')
break
diff --git a/ui/app/components/network.js b/ui/app/components/network.js
index 95901fe70..2f1bf639a 100644
--- a/ui/app/components/network.js
+++ b/ui/app/components/network.js
@@ -23,7 +23,7 @@ Network.prototype.render = function () {
if (networkNumber === 'loading') {
- return h('img', {
+ return h('img.network-indicator', {
title: 'Attempting to connect to blockchain.',
onClick: (event) => this.props.onClick(event),
style: {
@@ -36,9 +36,6 @@ Network.prototype.render = function () {
} else if (providerName === 'mainnet') {
hoverText = 'Main Ethereum Network'
iconName = 'ethereum-network'
- } else if (providerName === 'classic') {
- hoverText = 'Ethereum Classic Network'
- iconName = 'classic-network'
} else if (parseInt(networkNumber) === 2) {
hoverText = 'Morden Test Network'
iconName = 'morden-test-network'
@@ -66,15 +63,6 @@ Network.prototype.render = function () {
}},
'Etherum Main Net'),
])
- case 'classic-network':
- return h('.network-indicator', [
- h('.menu-icon.hollow-diamond'),
- h('.network-name', {
- style: {
- color: '#039396',
- }},
- 'Etherum Classic'),
- ])
case 'morden-test-network':
return h('.network-indicator', [
h('.menu-icon.red-dot'),
diff --git a/ui/app/components/qr-code.js b/ui/app/components/qr-code.js
new file mode 100644
index 000000000..f8cace4e0
--- /dev/null
+++ b/ui/app/components/qr-code.js
@@ -0,0 +1,60 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+const connect = require('react-redux').connect
+const CopyButton = require('./copyButton')
+
+module.exports = connect(mapStateToProps)(QrCodeView)
+
+function mapStateToProps (state) {
+ return {
+ Qr: state.appState.Qr,
+ buyView: state.appState.buyView,
+ }
+}
+
+inherits(QrCodeView, Component)
+
+function QrCodeView () {
+ Component.call(this)
+}
+
+QrCodeView.prototype.render = function () {
+ var props = this.props
+ var Qr = props.Qr
+ return h('.main-container.flex-column', {
+ style: {
+ justifyContent: 'center',
+ padding: '45px',
+ alignItems: 'center',
+ },
+ }, [
+ Array.isArray(Qr.message) ? h('.message-container', this.renderMultiMessage()) : h('h3', Qr.message),
+ h('#qr-container.flex-column', {
+ key: 'qr',
+ style: {
+ marginTop: '25px',
+ marginBottom: '15px',
+ },
+ dangerouslySetInnerHTML: {
+ __html: Qr.image,
+ },
+ }),
+ h('.flex-row', [
+ h('h3.ellip-address', {
+ style: {
+ width: '247px',
+ },
+ }, Qr.data),
+ h(CopyButton, {
+ value: Qr.data,
+ }),
+ ]),
+ ])
+}
+
+QrCodeView.prototype.renderMultiMessage = function () {
+ var Qr = this.props.Qr
+ var multiMessage = Qr.message.map((message) => h('.qr-message', message))
+ return multiMessage
+}
diff --git a/ui/app/components/shapeshift-form.js b/ui/app/components/shapeshift-form.js
new file mode 100644
index 000000000..48d220693
--- /dev/null
+++ b/ui/app/components/shapeshift-form.js
@@ -0,0 +1,311 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+const connect = require('react-redux').connect
+const ReactCSSTransitionGroup = require('react-addons-css-transition-group')
+const actions = require('../actions')
+const Qr = require('./qr-code')
+const isValidAddress = require('../util').isValidAddress
+module.exports = connect(mapStateToProps)(ShapeshiftForm)
+
+function mapStateToProps(state) {
+ return {
+ selectedAccount: state.selectedAccount,
+ warning: state.appState.warning,
+ isSubLoading: state.appState.isSubLoading,
+ qrRequested: state.appState.qrRequested,
+ }
+}
+
+inherits(ShapeshiftForm, Component)
+
+function ShapeshiftForm () {
+ Component.call(this)
+}
+ShapeshiftForm.prototype.render = function () {
+ return h(ReactCSSTransitionGroup, {
+ className: 'css-transition-group',
+ transitionName: 'main',
+ transitionEnterTimeout: 300,
+ transitionLeaveTimeout: 300,
+ }, [
+ this.props.qrRequested ? h(Qr, {key: 'qr'}) : this.renderMain(),
+ ])
+
+}
+
+ShapeshiftForm.prototype.renderMain = function () {
+ const marketinfo = this.props.buyView.formView.marketinfo
+ const coinOptions = this.props.buyView.formView.coinOptions
+ var coin = marketinfo.pair.split('_')[0].toUpperCase()
+
+ return h('.flex-column', {
+ style: {
+ // marginTop: '10px',
+ padding: '25px',
+ width: '100%',
+ alignItems: 'center',
+ },
+ }, [
+ h('.flex-row', {
+ style: {
+ justifyContent: 'center',
+ alignItems: 'baseline',
+ },
+ }, [
+ h('img', {
+ src: coinOptions[coin].image,
+ width: '25px',
+ height: '25px',
+ style: {
+ marginRight: '5px',
+ },
+ }),
+
+ h('.input-container', [
+ h('input#fromCoin.buy-inputs.ex-coins', {
+ type: 'text',
+ list: 'coinList',
+ style: {
+ boxSizing: 'border-box',
+ },
+ onChange: this.handleLiveInput.bind(this),
+ defaultValue: 'BTC',
+ }),
+
+ this.renderCoinList(),
+
+ h('i.fa.fa-pencil-square-o.edit-text', {
+ style: {
+ fontSize: '12px',
+ color: '#F7861C',
+ position: 'relative',
+ bottom: '48px',
+ left: '106px',
+ },
+ }),
+ ]),
+
+ h('.icon-control', [
+ h('i.fa.fa-refresh.fa-4.orange', {
+ style: {
+ position: 'relative',
+ bottom: '5px',
+ left: '5px',
+ color: '#F7861C',
+ },
+ onClick: this.updateCoin.bind(this),
+ }),
+ h('i.fa.fa-chevron-right.fa-4.orange', {
+ style: {
+ position: 'relative',
+ bottom: '26px',
+ left: '10px',
+ color: '#F7861C',
+ },
+ onClick: this.updateCoin.bind(this),
+ }),
+ ]),
+
+ h('#toCoin.ex-coins', marketinfo.pair.split('_')[1].toUpperCase()),
+
+ h('img', {
+ src: coinOptions[marketinfo.pair.split('_')[1].toUpperCase()].image,
+ width: '25px',
+ height: '25px',
+ style: {
+ marginLeft: '5px',
+ },
+ }),
+ ]),
+
+ this.props.isSubLoading ? this.renderLoading() : null,
+ h('.flex-column', {
+ style: {
+ width: '235px',
+ alignItems: 'flex-start',
+ },
+ }, [
+ this.props.warning ? this.props.warning && h('span.error.flex-center', {
+ style: {
+ textAlign: 'center',
+ width: '229px',
+ height: '82px',
+ },
+ },
+ this.props.warning) : this.renderInfo(),
+ ]),
+
+ h('.flex-row', {
+ style: {
+ padding: '10px',
+ paddingBottom: '2px',
+ width: '100%',
+ },
+ }, [
+ h('div', 'Receiving address:'),
+ h('.ellip-address', this.props.buyView.buyAddress),
+ ]),
+
+ h(this.activeToggle('.input-container'), {
+ style: {
+ padding: '10px',
+ paddingTop: '0px',
+ width: '100%',
+ },
+ }, [
+ h('div', `${coin} Address:`),
+
+ h('input#fromCoinAddress.buy-inputs', {
+ type: 'text',
+ placeholder: `Your ${coin} Refund Address`,
+ style: {
+ boxSizing: 'border-box',
+ width: '278px',
+ height: '20px',
+ padding: ' 5px ',
+ },
+ }),
+
+ h('i.fa.fa-pencil-square-o.edit-text', {
+ style: {
+ fontSize: '12px',
+ color: '#F7861C',
+ position: 'relative',
+ bottom: '5px',
+ right: '11px',
+ },
+ }),
+ h('.flex-row', {
+ style: {
+ justifyContent: 'flex-end',
+ },
+ }, [
+ h('button', {
+ onClick: this.shift.bind(this),
+ style: {
+ marginTop: '10px',
+ },
+ },
+ 'Submit'),
+ ]),
+ ]),
+ ])
+}
+
+ShapeshiftForm.prototype.shift = function () {
+ var props = this.props
+ var withdrawal = this.props.buyView.buyAddress
+ var returnAddress = document.getElementById('fromCoinAddress').value
+ var pair = this.props.buyView.formView.marketinfo.pair
+ var data = {
+ 'withdrawal': withdrawal,
+ 'pair': pair,
+ 'returnAddress': returnAddress,
+ }
+ var message = [
+ `Deposit Limit: ${props.buyView.formView.marketinfo.limit}`,
+ `Deposit Minimum:${props.buyView.formView.marketinfo.minimum}`,
+ ]
+ if (isValidAddress(withdrawal)) {
+ this.props.dispatch(actions.coinShiftRquest(data, message))
+ }
+}
+
+ShapeshiftForm.prototype.renderCoinList = function () {
+ var list = Object.keys(this.props.buyView.formView.coinOptions).map((item) => {
+ return h('option', {
+ value: item,
+ }, item)
+ })
+
+ return h('datalist#coinList', {
+ onClick: (event) => {
+ event.preventDefault()
+ },
+ }, list)
+}
+
+ShapeshiftForm.prototype.updateCoin = function (event) {
+ event.preventDefault()
+ const props = this.props
+ var coinOptions = this.props.buyView.formView.coinOptions
+ var coin = document.getElementById('fromCoin').value
+
+ if (!coinOptions[coin.toUpperCase()] || coin.toUpperCase() === 'ETH') {
+ var message = 'Not a valid coin'
+ return props.dispatch(actions.showWarning(message))
+ } else {
+ return props.dispatch(actions.pairUpdate(coin))
+ }
+}
+
+ShapeshiftForm.prototype.handleLiveInput = function () {
+ const props = this.props
+ var coinOptions = this.props.buyView.formView.coinOptions
+ var coin = document.getElementById('fromCoin').value
+
+ if (!coinOptions[coin.toUpperCase()] || coin.toUpperCase() === 'ETH') {
+ return null
+ } else {
+ return props.dispatch(actions.pairUpdate(coin))
+ }
+}
+
+ShapeshiftForm.prototype.renderInfo = function () {
+ const marketinfo = this.props.buyView.formView.marketinfo
+ const coinOptions = this.props.buyView.formView.coinOptions
+ var coin = marketinfo.pair.split('_')[0].toUpperCase()
+
+ return h('span', {
+ style: {
+ marginTop: '15px',
+ marginBottom: '15px',
+ },
+ }, [
+ h('h3.flex-row.text-transform-uppercase', {
+ style: {
+ color: '#AEAEAE',
+ paddingTop: '4px',
+ justifyContent: 'space-around',
+ textAlign: 'center',
+ fontSize: '14px',
+ },
+ }, `Market Info for ${marketinfo.pair.replace('_', ' to ').toUpperCase()}:`),
+ h('.marketinfo', ['Status : ', `${coinOptions[coin].status}`]),
+ h('.marketinfo', ['Exchange Rate: ', `${marketinfo.rate}`]),
+ h('.marketinfo', ['Limit: ', `${marketinfo.limit}`]),
+ h('.marketinfo', ['Minimum : ', `${marketinfo.minimum}`]),
+ ])
+}
+
+ShapeshiftForm.prototype.handleAddress = function (event) {
+ this.props.dispatch(actions.updateBuyAddress(event.target.value))
+}
+
+ShapeshiftForm.prototype.activeToggle = function (elementType) {
+ if (!this.props.buyView.formView.response || this.props.warning) return elementType
+ return `${elementType}.inactive`
+}
+
+ShapeshiftForm.prototype.renderLoading = function () {
+ return h('span', {
+ style: {
+ position: 'absolute',
+ left: '70px',
+ bottom: '194px',
+ background: 'transparent',
+ width: '229px',
+ height: '82px',
+ display: 'flex',
+ justifyContent: 'center',
+ },
+ }, [
+ h('img', {
+ style: {
+ width: '60px',
+ },
+ src: 'images/loading.svg',
+ }),
+ ])
+}