commit
f7a5a4e170
@ -0,0 +1,120 @@ |
||||
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()), |
||||
}, 'Go To Test Faucet') : null, |
||||
]) |
||||
} |
||||
} |
||||
|
||||
BuyButtonSubview.prototype.navigateTo = function (url) { |
||||
extension.tabs.create({ url }) |
||||
} |
@ -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', |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,56 @@ |
||||
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', 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 |
||||
} |
@ -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', |
||||
}), |
||||
]) |
||||
} |
Loading…
Reference in new issue