Merge pull request #529 from MetaMask/buyForm

Buy form
This commit is contained in:
kumavis 2016-08-14 08:18:20 -07:00 committed by GitHub
commit f7a5a4e170
11 changed files with 1060 additions and 12 deletions

View File

@ -1,7 +1,8 @@
# Changelog
## Current Master
- Integrate ShapeShift
- Add a for for Coinbase to specify amount to buy
- Fix various typos.
- Make dapp-metamask connection more reliable

View File

@ -15,7 +15,7 @@ const ExportAccountView = require('./components/account-export')
const ethUtil = require('ethereumjs-util')
const EditableLabel = require('./components/editable-label')
const Tooltip = require('./components/tooltip')
const BuyButtonSubview = require('./components/buy-button-subview')
module.exports = connect(mapStateToProps)(AccountDetailScreen)
function mapStateToProps (state) {
@ -172,14 +172,19 @@ AccountDetailScreen.prototype.render = function () {
}),
h('button', {
onClick: () => props.dispatch(actions.buyEth(selected)),
onClick: () => props.dispatch(actions.buyEthView(selected)),
style: {
marginBottom: '20px',
marginRight: '8px',
position: 'absolute',
left: '219px',
},
}, 'BUY'),
}, props.accountDetail.subview === 'buyForm' ? [h('i.fa.fa-arrow-left', {
style: {
width: '22.641px',
height: '14px',
},
})] : 'BUY'),
h('button', {
onClick: () => props.dispatch(actions.showSendPage()),
@ -220,6 +225,8 @@ AccountDetailScreen.prototype.subview = function () {
case 'export':
var state = extend({key: 'export'}, this.props)
return h(ExportAccountView, state)
case 'buyForm':
return h(BuyButtonSubview, extend({key: 'buyForm'}, this.props))
default:
return this.transactionList()
}
@ -251,3 +258,12 @@ AccountDetailScreen.prototype.requestAccountExport = function () {
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.buyEthView())
}
}

View File

@ -113,6 +113,26 @@ var actions = {
// buy Eth with coinbase
BUY_ETH: 'BUY_ETH',
buyEth: buyEth,
buyEthView: buyEthView,
BUY_ETH_VIEW: 'BUY_ETH_VIEW',
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,
coinShiftRquest: coinShiftRquest,
SHOW_SUB_LOADING_INDICATION: 'SHOW_SUB_LOADING_INDICATION',
showSubLoadingIndication: showSubLoadingIndication,
HIDE_SUB_LOADING_INDICATION: 'HIDE_SUB_LOADING_INDICATION',
hideSubLoadingIndication: hideSubLoadingIndication,
// QR STUFF:
SHOW_QR: 'SHOW_QR',
getQr: getQr,
}
module.exports = actions
@ -496,6 +516,18 @@ function hideLoadingIndication () {
}
}
function showSubLoadingIndication () {
return {
type: actions.SHOW_SUB_LOADING_INDICATION,
}
}
function hideSubLoadingIndication () {
return {
type: actions.HIDE_SUB_LOADING_INDICATION,
}
}
function showWarning (text) {
return this.displayWarning(text)
}
@ -594,3 +626,133 @@ function buyEth (address, amount) {
})
}
}
function buyEthView (address) {
return {
type: actions.BUY_ETH_VIEW,
value: address,
}
}
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, marketData) {
return (dispatch) => {
dispatch(actions.showLoadingIndication())
shapeShiftRequest('shift', { method: 'POST', data}, (response) => {
if (response.error) return dispatch(actions.showWarning(response.error))
var message = `
Deposit your ${response.depositType} to the address bellow:`
dispatch(actions.getQr(response.deposit, '125x125', [message].concat(marketData)))
})
}
}
function getQr (data, size, message) {
return (dispatch) => {
qrRequest(data, size, (response) => {
dispatch(actions.hideLoadingIndication())
if (response.error) return dispatch(actions.showWarning(response.error))
dispatch({
type: actions.SHOW_QR,
value: {
qr: response,
message: message,
data: data,
},
})
})
}
}
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()
}
}
function qrRequest (data, size, cb) {
var requestListner = function (request) {
cb ? cb(this.responseText) : null
return this.responseText
}
var qrReq = new XMLHttpRequest()
qrReq.addEventListener('load', requestListner)
qrReq.open('GET', `https://api.qrserver.com/v1/create-qr-code/?size=${size}&format=svg&data=${data}`, true)
qrReq.send()
}

View File

@ -28,7 +28,7 @@ const DropMenuItem = require('./components/drop-menu-item')
const NetworkIndicator = require('./components/network')
const Tooltip = require('./components/tooltip')
const EthStoreWarning = require('./eth-store-warning')
const BuyView = require('./components/buy-button-subview')
module.exports = connect(mapStateToProps)(App)
inherits(App, Component)
@ -366,6 +366,8 @@ App.prototype.renderPrimary = function () {
case 'createVault':
return h(CreateVaultScreen, {key: 'createVault'})
case 'buyEth':
return h(BuyView, {key: 'buyEthView'})
default:
return h(AccountDetailScreen, {key: 'account-detail'})

View File

@ -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 })
}

View File

@ -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',
}
}
}

View File

@ -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
}

View File

@ -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',
}),
])
}

View File

@ -471,3 +471,124 @@ input.large-input {
.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;
}
.ellip-address {
overflow: hidden;
text-overflow: ellipsis;
width: 5em;
font-size: 14px;
font-family: "Montserrat Light";
margin-left: 5px;
}
.qr-message {
font-size: 12px;
color: #F7861C;
}
div.message-container > div:first-child {
font-size: 15px;
color: #4D4D4D;
}

View File

@ -35,9 +35,10 @@ EthStoreWarning.prototype.render = function () {
margin: '10px 10px 10px 10px',
},
},
`MetaMask is currently in beta -
exercise caution while handling
and storing your ether.
`The MetaMask team would like to
remind you that MetaMask is currently in beta - so
don't store large
amounts of ether in MetaMask.
`),
h('i.fa.fa-exclamation-triangle.fa-4', {

View File

@ -317,6 +317,15 @@ function reduceApp (state, action) {
isLoading: false,
})
case actions.SHOW_SUB_LOADING_INDICATION:
return extend(appState, {
isSubLoading: true,
})
case actions.HIDE_SUB_LOADING_INDICATION:
return extend(appState, {
isSubLoading: false,
})
case actions.CLEAR_SEED_WORD_CACHE:
return extend(appState, {
transForward: true,
@ -369,15 +378,102 @@ function reduceApp (state, action) {
},
})
case actions.SHOW_ETH_WARNING:
case actions.BUY_ETH_VIEW:
return extend(appState, {
transForward: true,
currentView: {
name: 'accountDetail',
name: 'buyEth',
context: appState.currentView.context,
},
accountDetail: {
subview: 'buy-eth-warning',
buyView: {
subview: 'buyForm',
amount: '5.00',
buyAddress: action.value,
formView: {
coinbase: true,
shapeshift: false,
},
},
})
case actions.UPDATE_BUY_ADDRESS:
return extend(appState, {
buyView: {
subview: 'buyForm',
formView: {
coinbase: appState.buyView.formView.coinbase,
shapeshift: appState.buyView.formView.shapeshift,
},
buyAddress: action.value,
amount: appState.buyView.amount,
},
})
case actions.UPDATE_COINBASE_AMOUNT:
return extend(appState, {
buyView: {
subview: 'buyForm',
formView: {
coinbase: true,
shapeshift: false,
},
buyAddress: appState.buyView.buyAddress,
amount: action.value,
},
})
case actions.COINBASE_SUBVIEW:
return extend(appState, {
buyView: {
subview: 'buyForm',
formView: {
coinbase: true,
shapeshift: false,
},
buyAddress: appState.buyView.buyAddress,
amount: appState.buyView.amount,
},
})
case actions.SHAPESHIFT_SUBVIEW:
return extend(appState, {
buyView: {
subview: 'buyForm',
formView: {
coinbase: false,
shapeshift: true,
marketinfo: action.value.marketinfo,
coinOptions: action.value.coinOptions,
},
buyAddress: appState.buyView.buyAddress,
amount: appState.buyView.amount,
},
})
case actions.PAIR_UPDATE:
return extend(appState, {
buyView: {
subview: 'buyForm',
formView: {
coinbase: false,
shapeshift: true,
marketinfo: action.value.marketinfo,
coinOptions: appState.buyView.formView.coinOptions,
},
buyAddress: appState.buyView.buyAddress,
amount: appState.buyView.amount,
warning: null,
},
})
case actions.SHOW_QR:
return extend(appState, {
qrRequested: true,
transForward: true,
Qr: {
message: action.value.message,
image: action.value.qr,
data: action.value.data,
},
})
default: