1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-10-22 19:26:13 +02:00

Create "buy form" add shape shift

This commit is contained in:
Frankie 2016-08-10 13:43:01 -07:00
parent 667483ac20
commit 9c6dd9ef49
10 changed files with 966 additions and 9 deletions

View File

@ -6,6 +6,7 @@ const messageManager = require('./lib/message-manager')
const HostStore = require('./lib/remote-store.js').HostStore const HostStore = require('./lib/remote-store.js').HostStore
const Web3 = require('web3') const Web3 = require('web3')
const ConfigManager = require('./lib/config-manager') const ConfigManager = require('./lib/config-manager')
const extension = require('./lib/extension')
module.exports = class MetamaskController { module.exports = class MetamaskController {
@ -39,6 +40,7 @@ module.exports = class MetamaskController {
setProviderType: this.setProviderType.bind(this), setProviderType: this.setProviderType.bind(this),
useEtherscanProvider: this.useEtherscanProvider.bind(this), useEtherscanProvider: this.useEtherscanProvider.bind(this),
agreeToDisclaimer: this.agreeToDisclaimer.bind(this), agreeToDisclaimer: this.agreeToDisclaimer.bind(this),
agreeToEthWarning: this.agreeToEthWarning.bind(this),
// forward directly to idStore // forward directly to idStore
createNewVault: idStore.createNewVault.bind(idStore), createNewVault: idStore.createNewVault.bind(idStore),
recoverFromSeed: idStore.recoverFromSeed.bind(idStore), recoverFromSeed: idStore.recoverFromSeed.bind(idStore),
@ -55,6 +57,8 @@ module.exports = class MetamaskController {
saveAccountLabel: idStore.saveAccountLabel.bind(idStore), saveAccountLabel: idStore.saveAccountLabel.bind(idStore),
tryPassword: idStore.tryPassword.bind(idStore), tryPassword: idStore.tryPassword.bind(idStore),
recoverSeed: idStore.recoverSeed.bind(idStore), recoverSeed: idStore.recoverSeed.bind(idStore),
// coinbase
buyEth: this.buyEth.bind(this),
} }
} }
@ -161,6 +165,7 @@ module.exports = class MetamaskController {
function configToPublic (state) { function configToPublic (state) {
return { return {
provider: state.provider, provider: state.provider,
selectedAddress: state.selectedAccount,
} }
} }
// dump obj into store // dump obj into store
@ -236,23 +241,48 @@ module.exports = class MetamaskController {
} }
} }
agreeToEthWarning (cb) {
try {
this.configManager.setShouldntShowWarning(true)
cb()
} catch (e) {
cb(e)
}
}
// called from popup // called from popup
setRpcTarget (rpcTarget) { setRpcTarget (rpcTarget) {
this.configManager.setRpcTarget(rpcTarget) this.configManager.setRpcTarget(rpcTarget)
chrome.runtime.reload() extension.runtime.reload()
this.idStore.getNetwork() this.idStore.getNetwork()
} }
setProviderType (type) { setProviderType (type) {
this.configManager.setProviderType(type) this.configManager.setProviderType(type)
chrome.runtime.reload() extension.runtime.reload()
this.idStore.getNetwork() this.idStore.getNetwork()
} }
useEtherscanProvider () { useEtherscanProvider () {
this.configManager.useEtherscanProvider() this.configManager.useEtherscanProvider()
chrome.runtime.reload() extension.runtime.reload()
} }
buyEth (address, amount) {
if (!amount) amount = '5'
var network = this.idStore._currentState.network
var url = `https://buy.coinbase.com/?code=9ec56d01-7e81-5017-930c-513daa27bb6a&amount=${amount}&address=${address}&crypto_currency=ETH`
if (network === '2') {
url = 'https://testfaucet.metamask.io/'
}
extension.tabs.create({
url,
})
}
} }
function noop () {} function noop () {}

View File

@ -15,7 +15,7 @@ const ExportAccountView = require('./components/account-export')
const ethUtil = require('ethereumjs-util') const ethUtil = require('ethereumjs-util')
const EditableLabel = require('./components/editable-label') const EditableLabel = require('./components/editable-label')
const Tooltip = require('./components/tooltip') const Tooltip = require('./components/tooltip')
const BuyButtonSubview = require('./components/buy-button-subview')
module.exports = connect(mapStateToProps)(AccountDetailScreen) module.exports = connect(mapStateToProps)(AccountDetailScreen)
function mapStateToProps (state) { function mapStateToProps (state) {
@ -28,6 +28,7 @@ function mapStateToProps (state) {
network: state.metamask.network, network: state.metamask.network,
unconfTxs: valuesFor(state.metamask.unconfTxs), unconfTxs: valuesFor(state.metamask.unconfTxs),
unconfMsgs: valuesFor(state.metamask.unconfMsgs), unconfMsgs: valuesFor(state.metamask.unconfMsgs),
isEthWarningConfirmed: state.metamask.isEthConfirmed,
} }
} }
@ -170,6 +171,21 @@ AccountDetailScreen.prototype.render = function () {
}, },
}), }),
h('button', {
onClick: this.buyButtonDeligator.bind(this),
style: {
marginBottom: '20px',
marginRight: '8px',
position: 'absolute',
left: '219px',
},
}, props.accountDetail.subview === 'buyForm' ? [h('i.fa.fa-arrow-left', {
style: {
width: '22.641px',
height: '14px',
},
})] : 'BUY'),
h('button', { h('button', {
onClick: () => props.dispatch(actions.showSendPage()), onClick: () => props.dispatch(actions.showSendPage()),
style: { style: {
@ -181,7 +197,7 @@ AccountDetailScreen.prototype.render = function () {
]), ]),
]), ]),
// subview (tx history, pk export confirm) // subview (tx history, pk export confirm, buy eth warning)
h(ReactCSSTransitionGroup, { h(ReactCSSTransitionGroup, {
className: 'css-transition-group', className: 'css-transition-group',
transitionName: 'main', transitionName: 'main',
@ -209,6 +225,8 @@ AccountDetailScreen.prototype.subview = function () {
case 'export': case 'export':
var state = extend({key: 'export'}, this.props) var state = extend({key: 'export'}, this.props)
return h(ExportAccountView, state) return h(ExportAccountView, state)
case 'buyForm':
return h(BuyButtonSubview, extend({key: 'buyForm'}, this.props))
default: default:
return this.transactionList() return this.transactionList()
} }
@ -239,3 +257,13 @@ AccountDetailScreen.prototype.transactionList = function () {
AccountDetailScreen.prototype.requestAccountExport = function () { AccountDetailScreen.prototype.requestAccountExport = function () {
this.props.dispatch(actions.requestExportAccount()) this.props.dispatch(actions.requestExportAccount())
} }
AccountDetailScreen.prototype.buyButtonDeligator = function () {
var props = this.props
if (this.props.accountDetail.subview === 'buyForm') {
props.dispatch(actions.backToAccountDetail(props.address))
} else {
props.dispatch(actions.buyEthSubview())
}
}

View File

@ -66,6 +66,10 @@ var actions = {
showPrivateKey: showPrivateKey, showPrivateKey: showPrivateKey,
SAVE_ACCOUNT_LABEL: 'SAVE_ACCOUNT_LABEL', SAVE_ACCOUNT_LABEL: 'SAVE_ACCOUNT_LABEL',
saveAccountLabel: saveAccountLabel, saveAccountLabel: saveAccountLabel,
AGREE_TO_ETH_WARNING: 'AGREE_TO_ETH_WARNING',
agreeToEthWarning: agreeToEthWarning,
SHOW_ETH_WARNING: 'SHOW_ETH_WARNING',
showEthWarning: showEthWarning,
// tx conf screen // tx conf screen
COMPLETED_TX: 'COMPLETED_TX', COMPLETED_TX: 'COMPLETED_TX',
TRANSACTION_ERROR: 'TRANSACTION_ERROR', TRANSACTION_ERROR: 'TRANSACTION_ERROR',
@ -106,6 +110,28 @@ var actions = {
HIDE_LOADING: 'HIDE_LOADING_INDICATION', HIDE_LOADING: 'HIDE_LOADING_INDICATION',
showLoadingIndication: showLoadingIndication, showLoadingIndication: showLoadingIndication,
hideLoadingIndication: hideLoadingIndication, hideLoadingIndication: hideLoadingIndication,
// buy Eth with coinbase
BUY_ETH: 'BUY_ETH',
buyEth: buyEth,
buyEthSubview: buyEthSubview,
BUY_ETH_SUBVIEW: 'BUY_ETH_SUBVIEW',
UPDATE_COINBASE_AMOUNT: 'UPDATE_COIBASE_AMOUNT',
updateCoinBaseAmount: updateCoinBaseAmount,
UPDATE_BUY_ADDRESS: 'UPDATE_BUY_ADDRESS',
updateBuyAddress: updateBuyAddress,
COINBASE_SUBVIEW: 'COINBASE_SUBVIEW',
coinBaseSubview: coinBaseSubview,
SHAPESHIFT_SUBVIEW: 'SHAPESHIFT_SUBVIEW',
shapeShiftSubview: shapeShiftSubview,
PAIR_UPDATE: 'PAIR_UPDATE',
pairUpdate: pairUpdate,
COIN_SHIFT_REQUEST: 'COIN_SHIFT_REQUEST',
coinShiftRquest: coinShiftRquest,
SHOW_SUB_LOADING_INDICATION: 'SHOW_SUB_LOADING_INDICATION',
showSubLoadingIndication: showSubLoadingIndication,
HIDE_SUB_LOADING_INDICATION: 'HIDE_SUB_LOADING_INDICATION',
hideSubLoadingIndication: hideSubLoadingIndication,
} }
module.exports = actions module.exports = actions
@ -489,6 +515,18 @@ function hideLoadingIndication () {
} }
} }
function showSubLoadingIndication () {
return {
type: actions.SHOW_SUB_LOADING_INDICATION,
}
}
function hideSubLoadingIndication () {
return {
type: actions.HIDE_SUB_LOADING_INDICATION,
}
}
function showWarning (text) { function showWarning (text) {
return this.displayWarning(text) return this.displayWarning(text)
} }
@ -559,3 +597,134 @@ function showSendPage () {
type: actions.SHOW_SEND_PAGE, type: actions.SHOW_SEND_PAGE,
} }
} }
function agreeToEthWarning () {
return (dispatch) => {
_accountManager.agreeToEthWarning((err) => {
if (err) {
return dispatch(actions.showEthWarning(err.message))
}
dispatch({
type: actions.AGREE_TO_ETH_WARNING,
})
})
}
}
function showEthWarning () {
return {
type: actions.SHOW_ETH_WARNING,
}
}
function buyEth (address, amount) {
return (dispatch) => {
_accountManager.buyEth(address, amount)
dispatch({
type: actions.BUY_ETH,
})
}
}
function buyEthSubview () {
return {
type: actions.BUY_ETH_SUBVIEW,
}
}
function updateCoinBaseAmount (value) {
return {
type: actions.UPDATE_COINBASE_AMOUNT,
value,
}
}
function updateBuyAddress (value) {
return {
type: actions.UPDATE_BUY_ADDRESS,
value,
}
}
function coinBaseSubview () {
return {
type: actions.COINBASE_SUBVIEW,
}
}
function pairUpdate (coin) {
return (dispatch) => {
dispatch(actions.showSubLoadingIndication())
dispatch(actions.hideWarning())
shapeShiftRequest('marketinfo', {pair: `${coin.toLowerCase()}_eth`}, (mktResponse) => {
dispatch(actions.hideSubLoadingIndication())
dispatch({
type: actions.PAIR_UPDATE,
value: {
marketinfo: mktResponse,
},
})
})
}
}
function shapeShiftSubview (network) {
var pair
network === 'classic' ? pair = 'btc_etc' : pair = 'btc_eth'
return (dispatch) => {
dispatch(actions.showSubLoadingIndication())
shapeShiftRequest('marketinfo', {pair}, (mktResponse) => {
shapeShiftRequest('getcoins', {}, (response) => {
dispatch(actions.hideSubLoadingIndication())
if (mktResponse.error) return dispatch(actions.showWarning(mktResponse.error))
dispatch({
type: actions.SHAPESHIFT_SUBVIEW,
value: {
marketinfo: mktResponse,
coinOptions: response,
},
})
})
})
}
}
function coinShiftRquest (data) {
return (dispatch) => {
dispatch(actions.showSubLoadingIndication())
shapeShiftRequest('shift', { method: 'POST', data}, (response) => {
dispatch(actions.hideSubLoadingIndication())
if (response.error) return dispatch(actions.showWarning(response.error))
dispatch({
type: actions.COIN_SHIFT_REQUEST,
value: {
response: response,
},
})
})
}
}
function shapeShiftRequest (query, options, cb) {
var queryResponse, method
!options ? options = {} : null
options.method ? method = options.method : method = 'GET'
var requestListner = function (request) {
queryResponse = JSON.parse(this.responseText)
cb ? cb(queryResponse) : null
return queryResponse
}
var shapShiftReq = new XMLHttpRequest()
shapShiftReq.addEventListener('load', requestListner)
shapShiftReq.open(method, `https://shapeshift.io/${query}/${options.pair ? options.pair : ''}`, true)
if (options.method === 'POST') {
var jsonObj = JSON.stringify(options.data)
shapShiftReq.setRequestHeader('Content-Type', 'application/json')
return shapShiftReq.send(jsonObj)
} else {
return shapShiftReq.send()
}
}

View File

@ -27,6 +27,7 @@ const MenuDroppo = require('menu-droppo')
const DropMenuItem = require('./components/drop-menu-item') const DropMenuItem = require('./components/drop-menu-item')
const NetworkIndicator = require('./components/network') const NetworkIndicator = require('./components/network')
const Tooltip = require('./components/tooltip') const Tooltip = require('./components/tooltip')
const EthStoreWarning = require('./eth-store-warning')
module.exports = connect(mapStateToProps)(App) module.exports = connect(mapStateToProps)(App)
@ -37,6 +38,7 @@ function mapStateToProps (state) {
return { return {
// state from plugin // state from plugin
isConfirmed: state.metamask.isConfirmed, isConfirmed: state.metamask.isConfirmed,
isEthConfirmed: state.metamask.isEthConfirmed,
isInitialized: state.metamask.isInitialized, isInitialized: state.metamask.isInitialized,
isUnlocked: state.metamask.isUnlocked, isUnlocked: state.metamask.isUnlocked,
currentView: state.appState.currentView, currentView: state.appState.currentView,
@ -129,6 +131,7 @@ App.prototype.renderAppBar = function () {
h(NetworkIndicator, { h(NetworkIndicator, {
network: this.props.network, network: this.props.network,
provider: this.props.provider,
onClick: (event) => { onClick: (event) => {
event.preventDefault() event.preventDefault()
event.stopPropagation() event.stopPropagation()
@ -201,6 +204,7 @@ App.prototype.renderNetworkDropdown = function () {
style: { style: {
position: 'absolute', position: 'absolute',
left: 0, left: 0,
top: '36px',
}, },
innerStyle: { innerStyle: {
background: 'white', background: 'white',
@ -218,6 +222,16 @@ App.prototype.renderNetworkDropdown = function () {
action: () => props.dispatch(actions.setProviderType('mainnet')), action: () => props.dispatch(actions.setProviderType('mainnet')),
icon: h('.menu-icon.diamond'), icon: h('.menu-icon.diamond'),
activeNetworkRender: props.network, activeNetworkRender: props.network,
provider: props.provider,
}),
h(DropMenuItem, {
label: 'Ethereum Classic Network',
closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
action: () => props.dispatch(actions.setProviderType('classic')),
icon: h('.menu-icon.hollow-diamond'),
activeNetworkRender: props.network,
provider: props.provider,
}), }),
h(DropMenuItem, { h(DropMenuItem, {
@ -235,6 +249,7 @@ App.prototype.renderNetworkDropdown = function () {
icon: h('i.fa.fa-question-circle.fa-lg', { ariaHidden: true }), icon: h('i.fa.fa-question-circle.fa-lg', { ariaHidden: true }),
activeNetworkRender: props.provider.rpcTarget, activeNetworkRender: props.provider.rpcTarget,
}), }),
this.renderCustomOption(props.provider.rpcTarget), this.renderCustomOption(props.provider.rpcTarget),
]) ])
} }
@ -324,6 +339,8 @@ App.prototype.renderPrimary = function () {
// show current view // show current view
switch (props.currentView.name) { switch (props.currentView.name) {
case 'EthStoreWarning':
return h(EthStoreWarning, {key: 'ethWarning'})
case 'accounts': case 'accounts':
return h(AccountsScreen, {key: 'accounts'}) return h(AccountsScreen, {key: 'accounts'})

View File

@ -0,0 +1,74 @@
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')
module.exports = connect(mapStateToProps)(BuyButtonSubview)
function mapStateToProps (state) {
return {
selectedAccount: state.selectedAccount,
warning: state.appState.warning,
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.accountDetail.formView
return (
h('span', {key: 'buyForm'}, [
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(currentForm.shapeshift ? '.activeForm' : '.inactiveForm', {
onClick: () => props.dispatch(actions.shapeShiftSubview(props.provider.type)),
}, 'Shapeshift'),
]),
this.formVersionSubview(),
])
)
}
BuyButtonSubview.prototype.formVersionSubview = function () {
if (this.props.network === '1') {
if (this.props.accountDetail.formView.coinbase) {
return h(CoinbaseForm, this.props)
} else if (this.props.accountDetail.formView.shapeshift) {
return h(ShapeshiftForm, this.props)
}
} else {
console.log(this.props.network)
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'),
])
}
}

View File

@ -0,0 +1,186 @@
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.accountDetail.amount
var address = props.accountDetail.buyAddress
return h('.flex-column', {
style: {
margin: '10px',
},
}, [
h('.flex-column', {
style: {
alignItems: 'flex-start',
},
}, [
h('.flex-column', [
h('div', 'Address:'),
h('.input-container', {
style: {},
}, [
h('input.buy-inputs', {
type: 'text',
style: {
boxSizing: 'border-box',
width: '317px',
height: '20px',
padding: ' 12px 0px 12px 1px ',
},
defaultValue: address,
onChange: this.handleAddress.bind(this),
}),
h('i.fa.fa-pencil-square-o.edit-text', {
style: {
fontSize: '12px',
color: '#F7861C',
position: 'relative',
bottom: '8px',
right: '11px',
},
}),
]),
]),
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.backToAccountDetail(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.accountDetail.amount
var address = props.accountDetail.buyAddress
var message
if (isValidAddress(address) && isValidAmountforCoinBase(amount).valid) {
props.dispatch(actions.buyEth(address, props.accountDetail.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',
}
}
}

View File

@ -0,0 +1,335 @@
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 CopyButton = require('./CopyButton')
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,
}
}
inherits(ShapeshiftForm, Component)
function ShapeshiftForm() {
Component.call(this)
}
ShapeshiftForm.prototype.render = function () {
const marketinfo = this.props.accountDetail.formView.marketinfo
const coinOptions = this.props.accountDetail.formView.coinOptions
var coin = marketinfo.pair.split('_')[0].toUpperCase()
return h('.flex-column', {
style: {
margin: '10px',
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: '23px',
right: '11px',
},
}),
]),
h('.icon-control', [
h('i.fa.fa-refresh.fa-4.orange', {
style: {
position: 'relative',
bottom: '5px',
right: '5px',
color: '#F7861C',
},
onClick: this.updateCoin.bind(this),
}),
h('i.fa.fa-chevron-right.fa-4.orange', {
style: {
position: 'relative',
bottom: '5px',
right: '15px',
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(this.activeToggle('.input-container'), {
style: {
width: '100%',
marginTop: '19px',
},
}, [
h('div', 'Receiving address:'),
h('input.buy-inputs', {
type: 'text',
value: this.props.accountDetail.buyAddress,
onChange: this.handleAddress.bind(this),
style: {
boxSizing: 'border-box',
width: '325px',
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(this.activeToggle('.input-container'), {
style: {
width: '100%',
},
}, [
h('div', `${coin} Address:`),
h('input#fromCoinAddress.buy-inputs', {
type: 'text',
placeholder: `Your ${coin} Refund Address`,
style: {
boxSizing: 'border-box',
width: '235px',
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('button', {
onClick: this.shift.bind(this),
},
'Submit'),
]),
])
}
ShapeshiftForm.prototype.shift = function () {
var withdrawal = this.props.accountDetail.buyAddress
var returnAddress = document.getElementById('fromCoinAddress').value
var pair = this.props.accountDetail.formView.marketinfo.pair
var data = {
'withdrawal': withdrawal,
'pair': pair,
'returnAddress': returnAddress,
}
if (isValidAddress(withdrawal)) {
this.props.dispatch(actions.coinShiftRquest(data))
}
}
ShapeshiftForm.prototype.renderCoinList = function () {
var list = Object.keys(this.props.accountDetail.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.accountDetail.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.accountDetail.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.accountDetail.formView.marketinfo
const coinOptions = this.props.accountDetail.formView.coinOptions
var coin = marketinfo.pair.split('_')[0].toUpperCase()
const request = this.props.accountDetail.formView.response
if (!request) {
return h('span', [
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}`]),
])
} else {
return h('.flex-column', {
style: {
width: '229px',
height: '82px',
},
}, [
h('.marketinfo', ['Limit: ', `${marketinfo.limit}`]),
h('.marketinfo', ['Minimum : ', `${marketinfo.minimum}`]),
h('div', {
style: {
fontSize: '12px',
lineHeight: '16px',
marginTop: '4px',
color: '#F7861C',
},
}, `Deposit your ${request.depositType} to the address bellow:`),
h('.flex-row', {
style: {
position: 'relative',
right: '38px',
},
}, [
h('div', {
style: {
fontSize: '13px',
},
}, request.deposit),
h(CopyButton, {
value: request.deposit,
}),
]),
])
}
}
ShapeshiftForm.prototype.handleAddress = function (event) {
this.props.dispatch(actions.updateBuyAddress(event.target.value))
}
ShapeshiftForm.prototype.activeToggle = function (elementType) {
if (!this.props.accountDetail.formView.response || this.props.warning) return elementType
return `${elementType}.inactive`
}
ShapeshiftForm.prototype.renderLoading = function () {
return h('span', {
style: {
position: 'absolute',
left: '70px',
bottom: '138px',
background: 'transparent',
width: '229px',
height: '82px',
display: 'flex',
justifyContent: 'center',
},
}, [
h('img', {
style: {
width: '60px',
},
src: 'images/loading.svg',
}),
])
}

View File

@ -151,12 +151,14 @@ textarea.twelve-word-phrase {
.network-name { .network-name {
position: absolute; position: absolute;
top: 8px; top: 8px;
left: 60px;
width: 5.2em; width: 5.2em;
line-height: 9px; line-height: 9px;
text-rendering: geometricPrecision; text-rendering: geometricPrecision;
} }
.check { .check {
margin-left: 7px;
color: #F7861C; color: #F7861C;
flex: 1 0 auto; flex: 1 0 auto;
display: flex; display: flex;
@ -463,3 +465,111 @@ input.large-input {
display: inline-block; display: inline-block;
padding-left: 5px; padding-left: 5px;
} }
/* buy eth warning screen */
.eth-warning{
transition: opacity 400ms ease-in, transform 400ms ease-in;
}
.buy-subview{
transition: opacity 400ms ease-in, transform 400ms ease-in;
}
.input-container:hover .edit-text{
visibility: visible;
}
.buy-inputs{
font-family: 'Montserrat Light';
font-size: 13px;
height: 20px;
background: transparent;
box-sizing: border-box;
border: solid;
border-color: transparent;
border-width: 0.5px;
border-radius: 2px;
}
.input-container:hover .buy-inputs{
box-sizing: inherit;
border: solid;
border-color: #F7861C;
border-width: 0.5px;
border-radius: 2px;
}
.buy-inputs:focus{
border: solid;
border-color: #F7861C;
border-width: 0.5px;
border-radius: 2px;
}
.activeForm {
background: #F7F7F7;
border: none;
border-radius: 8px 8px 0px 0px;
width: 50%;
text-align: center;
padding-bottom: 4px;
}
.inactiveForm {
border: none;
border-radius: 8px 8px 0px 0px;
width: 50%;
text-align: center;
padding-bottom: 4px;
}
.ex-coins {
font-family: 'Montserrat Regular';
text-transform: uppercase;
text-align: center;
font-size: 33px;
width: 118px;
height: 42px;
padding: 1px;
color: #4D4D4D;
}
.marketinfo{
font-family: 'Montserrat light';
color: #AEAEAE;
font-size: 12px;
line-height: 14px;
}
#fromCoin::-webkit-calendar-picker-indicator {
display: none;
}
#coinList {
width: 400px;
height: 500px;
overflow: scroll;
}
.icon-control .fa-refresh{
visibility: hidden;
}
.icon-control:hover .fa-refresh{
visibility: visible;
}
.icon-control:hover .fa-chevron-right{
visibility: hidden;
}
.inactive {
color: #AEAEAE;
}
.inactive button{
background: #AEAEAE;
color: white;
}

View File

@ -7,6 +7,8 @@ const reduceIdentities = require('./reducers/identities')
const reduceMetamask = require('./reducers/metamask') const reduceMetamask = require('./reducers/metamask')
const reduceApp = require('./reducers/app') const reduceApp = require('./reducers/app')
window.METAMASK_CACHED_LOG_STATE = null
module.exports = rootReducer module.exports = rootReducer
function rootReducer (state, action) { function rootReducer (state, action) {
@ -35,5 +37,11 @@ function rootReducer (state, action) {
state.appState = reduceApp(state, action) state.appState = reduceApp(state, action)
window.METAMASK_CACHED_LOG_STATE = state
return state return state
} }
window.logState = function() {
var stateString = JSON.stringify(window.METAMASK_CACHED_LOG_STATE, null, 2)
console.log(stateString)
}

View File

@ -1,16 +1,16 @@
const createStore = require('redux').createStore const createStore = require('redux').createStore
const applyMiddleware = require('redux').applyMiddleware const applyMiddleware = require('redux').applyMiddleware
const thunkMiddleware = require('redux-thunk') const thunkMiddleware = require('redux-thunk')
const createLogger = require('redux-logger') // const createLogger = require('redux-logger')
const rootReducer = require('./reducers') const rootReducer = require('./reducers')
module.exports = configureStore module.exports = configureStore
const loggerMiddleware = createLogger() // const loggerMiddleware = createLogger()
const createStoreWithMiddleware = applyMiddleware( const createStoreWithMiddleware = applyMiddleware(
thunkMiddleware, thunkMiddleware
loggerMiddleware // // loggerMiddleware
)(createStore) )(createStore)
function configureStore (initialState) { function configureStore (initialState) {