aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/images/coinbase logo.pngbin0 -> 9775 bytes
-rw-r--r--app/images/shapeshift logo.pngbin0 -> 17537 bytes
-rw-r--r--app/scripts/popup.js9
-rw-r--r--gulpfile.js7
-rw-r--r--mascara/server/index.js3
-rw-r--r--mascara/server/util.js4
-rw-r--r--old-ui/app/account-detail.js1
-rw-r--r--old-ui/app/css/index.css6
-rw-r--r--package.json2
-rw-r--r--ui/app/actions.js11
-rw-r--r--ui/app/app.js6
-rw-r--r--ui/app/components/account-menu/index.js2
-rw-r--r--ui/app/components/modals/buy-options-modal.js2
-rw-r--r--ui/app/components/modals/deposit-ether-modal.js182
-rw-r--r--ui/app/components/modals/modal.js32
-rw-r--r--ui/app/components/shapeshift-form.js468
-rw-r--r--ui/app/components/shift-list-item.js50
-rw-r--r--ui/app/components/tx-list.js10
-rw-r--r--ui/app/components/tx-view.js2
-rw-r--r--ui/app/css/itcss/components/header.scss13
-rw-r--r--ui/app/css/itcss/components/modal.scss254
-rw-r--r--ui/app/css/itcss/components/transaction-list.scss2
-rw-r--r--ui/app/css/itcss/settings/variables.scss2
-rw-r--r--ui/app/reducers/app.js5
24 files changed, 758 insertions, 315 deletions
diff --git a/app/images/coinbase logo.png b/app/images/coinbase logo.png
new file mode 100644
index 000000000..a23d7926d
--- /dev/null
+++ b/app/images/coinbase logo.png
Binary files differ
diff --git a/app/images/shapeshift logo.png b/app/images/shapeshift logo.png
new file mode 100644
index 000000000..ac8faba5b
--- /dev/null
+++ b/app/images/shapeshift logo.png
Binary files differ
diff --git a/app/scripts/popup.js b/app/scripts/popup.js
index d0952af6a..97a29fb1a 100644
--- a/app/scripts/popup.js
+++ b/app/scripts/popup.js
@@ -26,8 +26,13 @@ const container = document.getElementById('app-content')
startPopup({ container, connectionStream }, (err, store) => {
if (err) return displayCriticalError(err)
- let betaUIState = store.getState().metamask.featureFlags.betaUI
- let css = betaUIState ? NewMetaMaskUiCss() : OldMetaMaskUiCss()
+ const { isMascara, identities = {}, featureFlags = {} } = store.getState().metamask
+ const firstTime = Object.keys(identities).length === 0
+ let betaUIState = featureFlags.betaUI
+
+ const useBetaCss = isMascara || firstTime || betaUIState
+
+ let css = useBetaCss ? NewMetaMaskUiCss() : OldMetaMaskUiCss()
let deleteInjectedCss = injectCss(css)
let newBetaUIState
diff --git a/gulpfile.js b/gulpfile.js
index 195e3f3ca..f61e15b69 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -23,6 +23,8 @@ var sass = require('gulp-sass')
var autoprefixer = require('gulp-autoprefixer')
var gulpStylelint = require('gulp-stylelint')
var stylefmt = require('gulp-stylefmt')
+var uglify = require('gulp-uglify')
+var babel = require('gulp-babel')
var disableDebugTools = gutil.env.disableDebugTools
@@ -375,6 +377,11 @@ function bundleTask(opts) {
// sourcemaps
// loads map from browserify file
.pipe(gulpif(debug, sourcemaps.init({ loadMaps: true })))
+ // Minification
+ .pipe(babel({
+ presets: ['env']
+ }))
+ .pipe(uglify())
// writes .map file
.pipe(gulpif(debug, sourcemaps.write('./')))
// write completed bundles
diff --git a/mascara/server/index.js b/mascara/server/index.js
index 83f84f6d1..6fb1287cc 100644
--- a/mascara/server/index.js
+++ b/mascara/server/index.js
@@ -2,6 +2,7 @@ const path = require('path')
const express = require('express')
const createBundle = require('./util').createBundle
const serveBundle = require('./util').serveBundle
+const compression = require('compression')
module.exports = createMetamascaraServer
@@ -16,6 +17,8 @@ function createMetamascaraServer () {
// serve bundles
const server = express()
+ server.use(compression())
+
// ui window
serveBundle(server, '/ui.js', uiBundle)
server.use(express.static(path.join(__dirname, '/../ui/'), { setHeaders: (res) => res.set('X-Frame-Options', 'DENY') }))
diff --git a/mascara/server/util.js b/mascara/server/util.js
index af2daddb9..f9692afb6 100644
--- a/mascara/server/util.js
+++ b/mascara/server/util.js
@@ -23,7 +23,9 @@ function createBundle (entryPoint) {
cache: {},
packageCache: {},
plugin: [watchify],
- }).transform('babelify')
+ })
+ .transform('babelify')
+ .transform('uglifyify', { global: true })
bundler.on('update', bundle)
bundle()
diff --git a/old-ui/app/account-detail.js b/old-ui/app/account-detail.js
index ee7eb1258..af189cc79 100644
--- a/old-ui/app/account-detail.js
+++ b/old-ui/app/account-detail.js
@@ -162,6 +162,7 @@ AccountDetailScreen.prototype.render = function () {
textRendering: 'geometricPrecision',
marginTop: '15px',
marginBottom: '15px',
+ marginLeft: '15px',
color: '#AEAEAE',
},
}, checksumAddress),
diff --git a/old-ui/app/css/index.css b/old-ui/app/css/index.css
index 3cbf20e98..4363da049 100644
--- a/old-ui/app/css/index.css
+++ b/old-ui/app/css/index.css
@@ -442,10 +442,10 @@ input.large-input {
flex-wrap: wrap;
overflow-y: auto;
flex-direction: inherit;
+}
- .name-label {
- margin-left: 15px;
- }
+.account-detail-section .name-label {
+ margin-left: 15px;
}
.grow-tenx {
diff --git a/package.json b/package.json
index 4469263cc..9bbdacea2 100644
--- a/package.json
+++ b/package.json
@@ -199,6 +199,7 @@
"eth-json-rpc-middleware": "^1.2.7",
"fs-promise": "^2.0.3",
"gulp": "github:gulpjs/gulp#4.0",
+ "gulp-babel": "^7.0.0",
"gulp-if": "^2.0.1",
"gulp-json-editor": "^2.2.1",
"gulp-livereload": "^3.8.1",
@@ -206,6 +207,7 @@
"gulp-sourcemaps": "^2.6.0",
"gulp-stylefmt": "^1.1.0",
"gulp-stylelint": "^4.0.0",
+ "gulp-uglify": "^3.0.0",
"gulp-util": "^3.0.7",
"gulp-watch": "^4.3.5",
"gulp-zip": "^4.0.0",
diff --git a/ui/app/actions.js b/ui/app/actions.js
index bd3aab45a..0d96d2b59 100644
--- a/ui/app/actions.js
+++ b/ui/app/actions.js
@@ -925,9 +925,13 @@ function lockMetamask () {
})
.then(newState => {
dispatch(actions.updateMetamaskState(newState))
+ dispatch(actions.hideLoadingIndication())
+ dispatch({ type: actions.LOCK_METAMASK })
+ })
+ .catch(() => {
+ dispatch(actions.hideLoadingIndication())
dispatch({ type: actions.LOCK_METAMASK })
})
- .catch(() => dispatch({ type: actions.LOCK_METAMASK }))
}
}
@@ -1434,7 +1438,6 @@ function pairUpdate (coin) {
function shapeShiftSubview (network) {
var pair = 'btc_eth'
-
return (dispatch) => {
dispatch(actions.showSubLoadingIndication())
shapeShiftRequest('marketinfo', {pair}, (mktResponse) => {
@@ -1460,7 +1463,7 @@ function coinShiftRquest (data, marketData) {
dispatch(actions.hideLoadingIndication())
if (response.error) return dispatch(actions.displayWarning(response.error))
var message = `
- Deposit your ${response.depositType} to the address bellow:`
+ Deposit your ${response.depositType} to the address below:`
log.debug(`background.createShapeShiftTx`)
background.createShapeShiftTx(response.deposit, response.depositType)
dispatch(actions.showQrView(response.deposit, [message].concat(marketData)))
@@ -1496,7 +1499,7 @@ function reshowQrCode (data, coin) {
if (mktResponse.error) return dispatch(actions.displayWarning(mktResponse.error))
var message = [
- `Deposit your ${coin} to the address bellow:`,
+ `Deposit your ${coin} to the address below:`,
`Deposit Limit: ${mktResponse.limit}`,
`Deposit Minimum:${mktResponse.minimum}`,
]
diff --git a/ui/app/app.js b/ui/app/app.js
index 73e5c06db..e24ab7109 100644
--- a/ui/app/app.js
+++ b/ui/app/app.js
@@ -3,6 +3,8 @@ const Component = require('react').Component
const connect = require('react-redux').connect
const h = require('react-hyperscript')
const actions = require('./actions')
+const classnames = require('classnames')
+
// mascara
const MascaraFirstTime = require('../../mascara/src/app/first-time').default
const MascaraBuyEtherScreen = require('../../mascara/src/app/first-time/buy-ether-screen').default
@@ -243,7 +245,9 @@ App.prototype.renderAppBar = function () {
}, [
h('.app-header.flex-row.flex-space-between', {
- style: {},
+ className: classnames({
+ 'app-header--initialized': !isOnboarding,
+ }),
}, [
h('div.app-header-contents', {}, [
h('div.left-menu-wrapper', {
diff --git a/ui/app/components/account-menu/index.js b/ui/app/components/account-menu/index.js
index 286a3b587..1b62b42fb 100644
--- a/ui/app/components/account-menu/index.js
+++ b/ui/app/components/account-menu/index.js
@@ -33,7 +33,7 @@ function mapDispatchToProps (dispatch) {
},
lockMetamask: () => {
dispatch(actions.lockMetamask())
- dispatch(actions.displayWarning(null))
+ dispatch(actions.hideWarning())
dispatch(actions.hideSidebar())
dispatch(actions.toggleAccountMenu())
},
diff --git a/ui/app/components/modals/buy-options-modal.js b/ui/app/components/modals/buy-options-modal.js
index d735983f9..74a7a847e 100644
--- a/ui/app/components/modals/buy-options-modal.js
+++ b/ui/app/components/modals/buy-options-modal.js
@@ -69,7 +69,7 @@ BuyOptions.prototype.render = function () {
// h('div.buy-modal-content-option', {}, [
// h('div.buy-modal-content-option-title', {}, 'Shapeshift'),
// h('div.buy-modal-content-option-subtitle', {}, 'Trade any digital asset for any other'),
- // ]),
+ // ]),,
this.renderModalContentOption(
'Direct Deposit',
diff --git a/ui/app/components/modals/deposit-ether-modal.js b/ui/app/components/modals/deposit-ether-modal.js
new file mode 100644
index 000000000..3e6d3fde1
--- /dev/null
+++ b/ui/app/components/modals/deposit-ether-modal.js
@@ -0,0 +1,182 @@
+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 networkNames = require('../../../../app/scripts/config.js').networkNames
+const ShapeshiftForm = require('../shapeshift-form')
+
+const DIRECT_DEPOSIT_ROW_TITLE = 'Directly Deposit Ether'
+const DIRECT_DEPOSIT_ROW_TEXT = `If you already have some Ether, the quickest way to get Ether in
+your new wallet by direct deposit.`
+const COINBASE_ROW_TITLE = 'Buy on Coinbase'
+const COINBASE_ROW_TEXT = `Coinbase is the world’s most popular way to buy and sell bitcoin,
+ethereum, and litecoin.`
+const SHAPESHIFT_ROW_TITLE = 'Deposit with ShapeShift'
+const SHAPESHIFT_ROW_TEXT = `If you own other cryptocurrencies, you can trade and deposit Ether
+directly into your MetaMask wallet. No Account Needed.`
+const FAUCET_ROW_TITLE = 'Test Faucet'
+const facuetRowText = networkName => `Get Ether from a faucet for the ${networkName}`
+
+function mapStateToProps (state) {
+ return {
+ network: state.metamask.network,
+ address: state.metamask.selectedAddress,
+ }
+}
+
+function mapDispatchToProps (dispatch) {
+ return {
+ toCoinbase: (address) => {
+ dispatch(actions.buyEth({ network: '1', address, amount: 0 }))
+ },
+ hideModal: () => {
+ dispatch(actions.hideModal())
+ },
+ showAccountDetailModal: () => {
+ dispatch(actions.showModal({ name: 'ACCOUNT_DETAILS' }))
+ },
+ toFaucet: network => dispatch(actions.buyEth({ network })),
+ }
+}
+
+inherits(DepositEtherModal, Component)
+function DepositEtherModal () {
+ Component.call(this)
+
+ this.state = {
+ buyingWithShapeshift: false,
+ }
+}
+
+module.exports = connect(mapStateToProps, mapDispatchToProps)(DepositEtherModal)
+
+DepositEtherModal.prototype.renderRow = function ({
+ logo,
+ title,
+ text,
+ buttonLabel,
+ onButtonClick,
+ hide,
+ className,
+ hideButton,
+ hideTitle,
+ onBackClick,
+}) {
+ if (hide) {
+ return null
+ }
+
+ return h('div', {
+ className: className || 'deposit-ether-modal__buy-row',
+ }, [
+
+ h('div.deposit-ether-modal__buy-row__back', {
+ onClick: onBackClick,
+ }, [
+
+ h('i.fa.fa-arrow-left.cursor-pointer'),
+
+ ]),
+
+ h('div.deposit-ether-modal__buy-row__logo', [logo]),
+
+ h('div.deposit-ether-modal__buy-row__description', [
+
+ !hideTitle && h('div.deposit-ether-modal__buy-row__description__title', [title]),
+
+ h('div.deposit-ether-modal__buy-row__description__text', [text]),
+
+ ]),
+
+ !hideButton && h('div.deposit-ether-modal__buy-row__button', [
+ h('button.deposit-ether-modal__deposit-button', {
+ onClick: onButtonClick,
+ }, [buttonLabel]),
+ ]),
+
+ ])
+}
+
+DepositEtherModal.prototype.render = function () {
+ const { network, toCoinbase, address, toFaucet } = this.props
+ const { buyingWithShapeshift } = this.state
+
+ const isTestNetwork = ['3', '4', '42'].find(n => n === network)
+ const networkName = networkNames[network]
+
+ return h('div.deposit-ether-modal', {}, [
+
+ h('div.deposit-ether-modal__header', [
+
+ h('div.deposit-ether-modal__header__title', ['Deposit Ether']),
+
+ h('div.deposit-ether-modal__header__description', [
+ 'To interact with decentralized applications using MetaMask, you’ll need Ether in your wallet.',
+ ]),
+
+ h('div.deposit-ether-modal__header__close', {
+ onClick: () => {
+ this.setState({ buyingWithShapeshift: false })
+ this.props.hideModal()
+ },
+ }),
+
+ ]),
+
+ h('div.deposit-ether-modal__buy-rows', [
+
+ this.renderRow({
+ logo: h('img.deposit-ether-modal__buy-row__eth-logo', { src: '../../../images/eth_logo.svg' }),
+ title: DIRECT_DEPOSIT_ROW_TITLE,
+ text: DIRECT_DEPOSIT_ROW_TEXT,
+ buttonLabel: 'View Account',
+ onButtonClick: () => this.goToAccountDetailsModal(),
+ hide: buyingWithShapeshift,
+ }),
+
+ this.renderRow({
+ logo: h('i.fa.fa-tint.fa-2x'),
+ title: FAUCET_ROW_TITLE,
+ text: facuetRowText(networkName),
+ buttonLabel: 'Get Ether',
+ onButtonClick: () => toFaucet(network),
+ hide: !isTestNetwork || buyingWithShapeshift,
+ }),
+
+ this.renderRow({
+ logo: h('img.deposit-ether-modal__buy-row__coinbase-logo', {
+ src: '../../../images/coinbase logo.png',
+ }),
+ title: COINBASE_ROW_TITLE,
+ text: COINBASE_ROW_TEXT,
+ buttonLabel: 'Continue to Coinbase',
+ onButtonClick: () => toCoinbase(address),
+ hide: isTestNetwork || buyingWithShapeshift,
+ }),
+
+ this.renderRow({
+ logo: h('img.deposit-ether-modal__buy-row__shapeshift-logo', {
+ src: '../../../images/shapeshift logo.png',
+ }),
+ title: SHAPESHIFT_ROW_TITLE,
+ text: SHAPESHIFT_ROW_TEXT,
+ buttonLabel: 'Buy with Shapeshift',
+ onButtonClick: () => this.setState({ buyingWithShapeshift: true }),
+ hide: isTestNetwork,
+ hideButton: buyingWithShapeshift,
+ hideTitle: buyingWithShapeshift,
+ onBackClick: () => this.setState({ buyingWithShapeshift: false }),
+ className: buyingWithShapeshift && 'deposit-ether-modal__buy-row__shapeshift-buy',
+ }),
+
+ buyingWithShapeshift && h(ShapeshiftForm),
+
+ ]),
+ ])
+}
+
+DepositEtherModal.prototype.goToAccountDetailsModal = function () {
+ this.props.hideModal()
+ this.props.showAccountDetailModal()
+}
diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js
index 2ff6accaa..afb2a2175 100644
--- a/ui/app/components/modals/modal.js
+++ b/ui/app/components/modals/modal.js
@@ -9,6 +9,7 @@ const isPopupOrNotification = require('../../../../app/scripts/lib/is-popup-or-n
// Modal Components
const BuyOptions = require('./buy-options-modal')
+const DepositEtherModal = require('./deposit-ether-modal')
const AccountDetailsModal = require('./account-details-modal')
const EditAccountNameModal = require('./edit-account-name-modal')
const ExportPrivateKeyModal = require('./export-private-key-modal')
@@ -73,6 +74,37 @@ const MODALS = {
},
},
+ DEPOSIT_ETHER: {
+ contents: [
+ h(DepositEtherModal, {}, []),
+ ],
+ mobileModalStyle: {
+ width: '100%',
+ height: '100%',
+ transform: 'none',
+ left: '0',
+ right: '0',
+ margin: '0 auto',
+ boxShadow: '0 0 7px 0 rgba(0,0,0,0.08)',
+ top: '0',
+ display: 'flex',
+ },
+ laptopModalStyle: {
+ width: '900px',
+ maxWidth: '900px',
+ top: 'calc(10% + 10px)',
+ left: '0',
+ right: '0',
+ margin: '0 auto',
+ boxShadow: '0 0 6px 0 rgba(0,0,0,0.3)',
+ borderRadius: '8px',
+ transform: 'none',
+ },
+ contentStyle: {
+ borderRadius: '8px',
+ },
+ },
+
EDIT_ACCOUNT_NAME: {
contents: [
h(EditAccountNameModal, {}, []),
diff --git a/ui/app/components/shapeshift-form.js b/ui/app/components/shapeshift-form.js
index c5993e3d3..2270b8236 100644
--- a/ui/app/components/shapeshift-form.js
+++ b/ui/app/components/shapeshift-form.js
@@ -1,308 +1,242 @@
-const PersistentForm = require('../../lib/persistent-form')
const h = require('react-hyperscript')
const inherits = require('util').inherits
+const Component = require('react').Component
const connect = require('react-redux').connect
-const actions = require('../actions')
-const Qr = require('./qr-code')
-const isValidAddress = require('../util').isValidAddress
-module.exports = connect(mapStateToProps)(ShapeshiftForm)
+const classnames = require('classnames')
+const { qrcode } = require('qrcode-npm')
+const { shapeShiftSubview, pairUpdate, buyWithShapeShift } = require('../actions')
+const { isValidAddress } = require('../util')
+const SimpleDropdown = require('./dropdowns/simple-dropdown')
function mapStateToProps (state) {
+ const {
+ coinOptions,
+ tokenExchangeRates,
+ selectedAddress,
+ } = state.metamask
+
return {
- warning: state.appState.warning,
- isSubLoading: state.appState.isSubLoading,
- qrRequested: state.appState.qrRequested,
+ coinOptions,
+ tokenExchangeRates,
+ selectedAddress,
}
}
-inherits(ShapeshiftForm, PersistentForm)
+function mapDispatchToProps (dispatch) {
+ return {
+ shapeShiftSubview: () => dispatch(shapeShiftSubview()),
+ pairUpdate: coin => dispatch(pairUpdate(coin)),
+ buyWithShapeShift: data => dispatch(buyWithShapeShift(data)),
+ }
+}
+
+module.exports = connect(mapStateToProps, mapDispatchToProps)(ShapeshiftForm)
+inherits(ShapeshiftForm, Component)
function ShapeshiftForm () {
- PersistentForm.call(this)
- this.persistentFormParentId = 'shapeshift-buy-form'
+ Component.call(this)
+
+ this.state = {
+ depositCoin: 'btc',
+ refundAddress: '',
+ showQrCode: false,
+ depositAddress: '',
+ errorMessage: '',
+ isLoading: false,
+ bought: false,
+ }
}
-ShapeshiftForm.prototype.render = function () {
- return this.props.qrRequested ? h(Qr, {key: 'qr'}) : this.renderMain()
+ShapeshiftForm.prototype.componentWillMount = function () {
+ this.props.shapeShiftSubview()
}
-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: {
- position: 'relative',
- padding: '25px',
- paddingTop: '5px',
- width: '90%',
- minHeight: '215px',
- alignItems: 'center',
- overflowY: 'auto',
- },
- }, [
- h('.flex-row', {
- style: {
- justifyContent: 'center',
- alignItems: 'baseline',
- height: '42px',
- },
- }, [
- h('img', {
- src: coinOptions[coin].image,
- width: '25px',
- height: '25px',
- style: {
- marginRight: '5px',
- },
- }),
-
- h('.input-container', {
- position: 'relative',
- }, [
- h('input#fromCoin.buy-inputs.ex-coins', {
- type: 'text',
- list: 'coinList',
- autoFocus: true,
- dataset: {
- persistentFormId: 'input-coin',
- },
- style: {
- boxSizing: 'border-box',
- },
- onChange: this.handleLiveInput.bind(this),
- defaultValue: 'BTC',
- }),
+ShapeshiftForm.prototype.onCoinChange = function (e) {
+ const coin = e.target.value
+ this.setState({
+ depositCoin: coin,
+ errorMessage: '',
+ })
+ this.props.pairUpdate(coin)
+}
- this.renderCoinList(),
+ShapeshiftForm.prototype.onBuyWithShapeShift = function () {
+ this.setState({
+ isLoading: true,
+ showQrCode: true,
+ })
- h('i.fa.fa-pencil-square-o.edit-text', {
- style: {
- fontSize: '12px',
- color: '#F7861C',
- position: 'absolute',
- },
- }),
- ]),
+ const {
+ buyWithShapeShift,
+ selectedAddress: withdrawal,
+ } = this.props
+ const {
+ refundAddress: returnAddress,
+ depositCoin,
+ } = this.state
+ const pair = `${depositCoin}_eth`
+ const data = {
+ withdrawal,
+ pair,
+ returnAddress,
+ // Public api key
+ 'apiKey': '803d1f5df2ed1b1476e4b9e6bcd089e34d8874595dda6a23b67d93c56ea9cc2445e98a6748b219b2b6ad654d9f075f1f1db139abfa93158c04e825db122c14b6',
+ }
- h('.icon-control', {
- style: {
- position: 'relative',
- },
- }, [
- // Not visible on the screen, can't see it on master.
-
- // h('i.fa.fa-refresh.fa-4.orange', {
- // style: {
- // bottom: '5px',
- // left: '5px',
- // color: '#F7861C',
- // },
- // onClick: this.updateCoin.bind(this),
- // }),
- h('i.fa.fa-chevron-right.fa-4.orange', {
- style: {
- position: 'absolute',
- bottom: '35%',
- left: '0%',
- color: '#F7861C',
- },
- onClick: this.updateCoin.bind(this),
- }),
- ]),
+ if (isValidAddress(withdrawal)) {
+ buyWithShapeShift(data)
+ .then(d => this.setState({
+ showQrCode: true,
+ depositAddress: d.deposit,
+ isLoading: false,
+ }))
+ .catch(() => this.setState({
+ showQrCode: false,
+ errorMessage: 'Invalid Request',
+ isLoading: false,
+ }))
+ }
+}
- h('#toCoin.ex-coins', marketinfo.pair.split('_')[1].toUpperCase()),
+ShapeshiftForm.prototype.renderMetadata = function (label, value) {
+ return h('div', {className: 'shapeshift-form__metadata-wrapper'}, [
- h('img', {
- src: coinOptions[marketinfo.pair.split('_')[1].toUpperCase()].image,
- width: '25px',
- height: '25px',
- style: {
- marginLeft: '5px',
- },
- }),
+ h('div.shapeshift-form__metadata-label', {}, [
+ h('span', `${label}:`),
]),
- h('.flex-column', {
- style: {
- marginTop: '1%',
- 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(),
-
- this.renderRefundAddressForCoin(coin),
+ h('div.shapeshift-form__metadata-value', {}, [
+ h('span', value),
]),
])
}
-ShapeshiftForm.prototype.renderRefundAddressForCoin = function (coin) {
- return h(this.activeToggle('.input-container'), {
- style: {
- marginTop: '1%',
- },
- }, [
-
- h('div', `${coin} Address:`),
-
- h('input#fromCoinAddress.buy-inputs', {
- type: 'text',
- placeholder: `Your ${coin} Refund Address`,
- dataset: {
- persistentFormId: 'refund-address',
-
- },
- style: {
- boxSizing: 'border-box',
- width: '227px',
- height: '30px',
- padding: ' 5px ',
- },
- }),
-
- h('i.fa.fa-pencil-square-o.edit-text', {
- style: {
- fontSize: '12px',
- color: '#F7861C',
- position: 'absolute',
- },
- }),
- h('div.flex-row', {
- style: {
- justifyContent: 'flex-start',
- },
- }, [
- h('button', {
- onClick: this.shift.bind(this),
- style: {
- marginTop: '1%',
- },
- },
- 'Submit'),
- ]),
+ShapeshiftForm.prototype.renderMarketInfo = function () {
+ const { depositCoin } = this.state
+ const coinPair = `${depositCoin}_eth`
+ const { tokenExchangeRates } = this.props
+ const {
+ limit,
+ rate,
+ minimum,
+ } = tokenExchangeRates[coinPair] || {}
+
+ return h('div.shapeshift-form__metadata', {}, [
+
+ this.renderMetadata('Status', limit ? 'Available' : 'Unavailable'),
+ this.renderMetadata('Limit', limit),
+ this.renderMetadata('Exchange Rate', rate),
+ this.renderMetadata('Minimum', minimum),
+
])
}
-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,
- // Public api key
- 'apiKey': '803d1f5df2ed1b1476e4b9e6bcd089e34d8874595dda6a23b67d93c56ea9cc2445e98a6748b219b2b6ad654d9f075f1f1db139abfa93158c04e825db122c14b6',
- }
- 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.renderQrCode = function () {
+ const { depositAddress, isLoading } = this.state
+ const qrImage = qrcode(4, 'M')
+ qrImage.addData(depositAddress)
+ qrImage.make()
-ShapeshiftForm.prototype.renderCoinList = function () {
- var list = Object.keys(this.props.buyView.formView.coinOptions).map((item) => {
- return h('option', {
- value: item,
- }, item)
- })
+ return h('div.shapeshift-form', {}, [
- return h('datalist#coinList', {
- onClick: (event) => {
- event.preventDefault()
- },
- }, list)
-}
+ h('div.shapeshift-form__deposit-instruction', [
+ 'Deposit your BTC to the address below:',
+ ]),
-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.displayWarning(message))
- } else {
- return props.dispatch(actions.pairUpdate(coin))
- }
-}
+ h('div', depositAddress),
-ShapeshiftForm.prototype.handleLiveInput = function () {
- const props = this.props
- var coinOptions = this.props.buyView.formView.coinOptions
- var coin = document.getElementById('fromCoin').value
+ h('div.shapeshift-form__qr-code', [
+ isLoading
+ ? h('img', {
+ src: 'images/loading.svg',
+ style: { width: '60px'},
+ })
+ : h('div', {
+ dangerouslySetInnerHTML: { __html: qrImage.createTableTag(4) },
+ }),
+ ]),
- if (!coinOptions[coin.toUpperCase()] || coin.toUpperCase() === 'ETH') {
- return null
- } else {
- return props.dispatch(actions.pairUpdate(coin))
- }
-}
+ this.renderMarketInfo(),
-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: {
- },
- }, [
- h('h3.flex-row.text-transform-uppercase', {
- style: {
- color: '#868686',
- paddingTop: '4px',
- justifyContent: 'space-around',
- textAlign: 'center',
- fontSize: '17px',
- },
- }, `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.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',
- }),
- ])
+ShapeshiftForm.prototype.render = function () {
+ const { coinOptions, btnClass } = this.props
+ const { depositCoin, errorMessage, showQrCode, depositAddress } = this.state
+ const coinPair = `${depositCoin}_eth`
+ const { tokenExchangeRates } = this.props
+ const token = tokenExchangeRates[coinPair]
+
+ return h('div.shapeshift-form-wrapper', [
+ showQrCode
+ ? this.renderQrCode()
+ : h('div.shapeshift-form', [
+ h('div.shapeshift-form__selectors', [
+
+ h('div.shapeshift-form__selector', [
+
+ h('div.shapeshift-form__selector-label', 'Deposit'),
+
+ h(SimpleDropdown, {
+ selectedOption: this.state.depositCoin,
+ onSelect: this.onCoinChange,
+ options: Object.entries(coinOptions).map(([coin]) => ({
+ value: coin.toLowerCase(),
+ displayValue: coin,
+ })),
+ }),
+
+ ]),
+
+ h('div.icon.shapeshift-form__caret', {
+ style: { backgroundImage: 'url(images/caret-right.svg)'},
+ }),
+
+ h('div.shapeshift-form__selector', [
+
+ h('div.shapeshift-form__selector-label', [
+ 'Receive',
+ ]),
+
+ h('div.shapeshift-form__selector-input', ['ETH']),
+
+ ]),
+
+ ]),
+
+ h('div', {
+ className: classnames('shapeshift-form__address-input-wrapper', {
+ 'shapeshift-form__address-input-wrapper--error': errorMessage,
+ }),
+ }, [
+
+ h('div.shapeshift-form__address-input-label', [
+ 'Your Refund Address',
+ ]),
+
+ h('input.shapeshift-form__address-input', {
+ type: 'text',
+ onChange: e => this.setState({
+ refundAddress: e.target.value,
+ errorMessage: '',
+ }),
+ }),
+
+ h('divshapeshift-form__address-input-error-message', [errorMessage]),
+ ]),
+
+ this.renderMarketInfo(),
+
+ ]),
+
+ !depositAddress && h('button.shapeshift-form__shapeshift-buy-btn', {
+ className: btnClass,
+ disabled: !token,
+ onClick: () => this.onBuyWithShapeShift(),
+ }, ['Buy']),
+
+ ])
}
diff --git a/ui/app/components/shift-list-item.js b/ui/app/components/shift-list-item.js
index 43973de63..111a77df4 100644
--- a/ui/app/components/shift-list-item.js
+++ b/ui/app/components/shift-list-item.js
@@ -16,6 +16,7 @@ module.exports = connect(mapStateToProps)(ShiftListItem)
function mapStateToProps (state) {
return {
+ selectedAddress: state.metamask.selectedAddress,
conversionRate: state.metamask.conversionRate,
currentCurrency: state.metamask.currentCurrency,
}
@@ -28,36 +29,39 @@ function ShiftListItem () {
}
ShiftListItem.prototype.render = function () {
+ const { selectedAddress, receivingAddress } = this.props
return (
- h('div.tx-list-item.tx-list-clickable', {
- style: {
- paddingTop: '20px',
- paddingBottom: '20px',
- justifyContent: 'space-around',
- alignItems: 'center',
- },
- }, [
- h('div', {
+ selectedAddress === receivingAddress
+ ? h('div.tx-list-item.tx-list-clickable', {
style: {
- width: '0px',
- position: 'relative',
- bottom: '19px',
+ paddingTop: '20px',
+ paddingBottom: '20px',
+ justifyContent: 'space-around',
+ alignItems: 'center',
},
}, [
- h('img', {
- src: 'https://info.shapeshift.io/sites/default/files/logo.png',
+ h('div', {
style: {
- height: '35px',
- width: '132px',
- position: 'absolute',
- clip: 'rect(0px,23px,34px,0px)',
+ width: '0px',
+ position: 'relative',
+ bottom: '19px',
},
- }),
- ]),
+ }, [
+ h('img', {
+ src: 'https://info.shapeshift.io/sites/default/files/logo.png',
+ style: {
+ height: '35px',
+ width: '132px',
+ position: 'absolute',
+ clip: 'rect(0px,23px,34px,0px)',
+ },
+ }),
+ ]),
- this.renderInfo(),
- this.renderUtilComponents(),
- ])
+ this.renderInfo(),
+ this.renderUtilComponents(),
+ ])
+ : null
)
}
diff --git a/ui/app/components/tx-list.js b/ui/app/components/tx-list.js
index 70722f43e..50e328dac 100644
--- a/ui/app/components/tx-list.js
+++ b/ui/app/components/tx-list.js
@@ -52,7 +52,7 @@ TxList.prototype.render = function () {
TxList.prototype.renderTransaction = function () {
const { txsToRender, conversionRate } = this.props
return txsToRender.length
- ? txsToRender.map((transaction, i) => this.renderTransactionListItem(transaction, conversionRate))
+ ? txsToRender.map((transaction, i) => this.renderTransactionListItem(transaction, conversionRate, i))
: [h(
'div.tx-list-item.tx-list-item--empty',
{ key: 'tx-list-none' },
@@ -61,12 +61,16 @@ TxList.prototype.renderTransaction = function () {
}
// TODO: Consider moving TxListItem into a separate component
-TxList.prototype.renderTransactionListItem = function (transaction, conversionRate) {
+TxList.prototype.renderTransactionListItem = function (transaction, conversionRate, index) {
// console.log({transaction})
// refer to transaction-list.js:line 58
if (transaction.key === 'shapeshift') {
- return h(ShiftListItem, transaction)
+ return h('div', {
+ key: `shapeshift${index}`,
+ }, [
+ h(ShiftListItem, transaction),
+ ])
}
const props = {
diff --git a/ui/app/components/tx-view.js b/ui/app/components/tx-view.js
index 72183f0f7..0148b32a5 100644
--- a/ui/app/components/tx-view.js
+++ b/ui/app/components/tx-view.js
@@ -70,7 +70,7 @@ TxView.prototype.renderButtons = function () {
h('div.flex-row.flex-center.hero-balance-buttons', [
h('button.btn-clear.hero-balance-button', {
onClick: () => showModal({
- name: 'BUY',
+ name: 'DEPOSIT_ETHER',
}),
}, 'DEPOSIT'),
diff --git a/ui/app/css/itcss/components/header.scss b/ui/app/css/itcss/components/header.scss
index 2a1f7abc7..ac2cecf7e 100644
--- a/ui/app/css/itcss/components/header.scss
+++ b/ui/app/css/itcss/components/header.scss
@@ -17,7 +17,16 @@
@media screen and (min-width: 576px) {
height: 75px;
justify-content: center;
+ }
+
+ .metafox-icon {
+ cursor: pointer;
+ }
+}
+.app-header--initialized {
+
+ @media screen and (min-width: 576px) {
&::after {
content: '';
position: absolute;
@@ -27,10 +36,6 @@
bottom: -32px;
}
}
-
- .metafox-icon {
- cursor: pointer;
- }
}
.app-header-contents {
diff --git a/ui/app/css/itcss/components/modal.scss b/ui/app/css/itcss/components/modal.scss
index 307401666..7a2ec35a4 100644
--- a/ui/app/css/itcss/components/modal.scss
+++ b/ui/app/css/itcss/components/modal.scss
@@ -589,4 +589,256 @@
justify-content: center;
font-size: 17px;
color: $nile-blue;
-} \ No newline at end of file
+}
+
+// Deposit Ether Modal
+.deposit-ether-modal {
+ border-radius: 8px;
+ font-family: Roboto;
+ display: flex;
+ flex-flow: column;
+ height: 100%;
+
+ &__header {
+ width: 100%;
+ border-radius: 8px 8px 0 0;
+ background-color: $mid-gray;
+ display: flex;
+ position: relative;
+ padding: 25px;
+ flex-flow: column;
+ align-items: flex-start;
+
+ &__title {
+ color: $white;
+ font-size: 24px;
+ line-height: 32px;
+ }
+
+ &__description {
+ color: $white;
+ font-size: 16px;
+ line-height: 22px;
+ margin-top: 10px;
+ }
+
+ &__close::after {
+ content: '\00D7';
+ font-size: 2em;
+ color: $white;
+ position: absolute;
+ top: 20.8px;
+ right: 28px;
+ cursor: pointer;
+ }
+ }
+
+ &__buy-rows {
+ width: 100%;
+ padding: 33px;
+ padding-top: 0px;
+ display: flex;
+ flex-flow: column nowrap;
+ flex: 1;
+ overflow-y: auto;
+
+ @media screen and (max-width: 575px) {
+ height: 0;
+ }
+ }
+
+ &__buy-row {
+ border-bottom: 1px solid $alto;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ flex: 1;
+ padding-bottom: 25px;
+ padding-top: 25px;
+
+ @media screen and (max-width: 575px) {
+ min-height: 360px;
+ flex-flow: column;
+ justify-content: center;
+ padding-top: 45px;
+ }
+
+ &__back {
+ position: absolute;
+ top: 10px;
+ left: 0px;
+ }
+
+ &__shapeshift-buy {
+ padding-top: 25px;
+ position: relative;
+ @media screen and (max-width: 575px) {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ flex: 1;
+ padding-bottom: 25px;
+ flex-flow: column;
+ justify-content: center;
+ padding-top: 20px;
+ min-height: 240px;
+ border: none;
+ }
+ }
+
+ &__logo {
+ display: flex;
+ justify-content: center;
+ flex: 0.3 1 auto;
+
+ @media screen and (min-width: 575px) {
+ min-width: 215px;
+ }
+ }
+
+ &__coinbase-logo {
+ height: 40px;
+ width: 180px;
+ }
+
+ &__shapeshift-logo {
+ height: 60px;
+ width: 174px;
+ }
+
+ &__eth-logo {
+ border-radius: 50%;
+ width: 68px;
+ height: 68px;
+ border: 3px solid $tundora;
+ z-index: 25;
+ padding: 4px;
+ background-color: #fff;
+ }
+
+ &__right {
+ display: flex;
+ }
+
+ &__description {
+ color: $cape-cod;
+ flex: 0.5 1 auto;
+
+ @media screen and (min-width: 575px) {
+ min-width: 315px;
+ }
+
+ &__title {
+ font-size: 20px;
+ line-height: 30px;
+ }
+
+ &__text {
+ font-size: 14px;
+ line-height: 22px;
+ margin-top: 7px;
+ }
+ }
+
+ &__button {
+ display: flex;
+ justify-content: flex-end;
+
+ @media screen and (min-width: 575px) {
+ min-width: 300px;
+ }
+ }
+ }
+
+ &__buy-row:last-of-type {
+ border-bottom: 0px;
+ }
+
+ &__deposit-button, .shapeshift-form__shapeshift-buy-btn {
+ height: 54px;
+ width: 257px;
+ border: 1px solid $curious-blue;
+ border-radius: 4px;
+ display: flex;
+ justify-content: center;
+ font-size: 16px;
+ color: $curious-blue;
+ background-color: $white;
+ }
+
+ .shapeshift-form-wrapper {
+ display: flex;
+ flex-flow: column;
+ justify-content: center;
+ align-items: center;
+ margin-top: 28px;
+ flex: 1 0 auto;
+
+ .shapeshift-form {
+ width: auto;
+
+ &__caret {
+ width: auto;
+ flex: 1;
+ }
+ }
+ }
+
+ .shapeshift-form__shapeshift-buy-btn {
+ margin-top: 10px;
+ }
+
+ .simple-dropdown {
+ color: #5B5D67;
+ font-size: 16px;
+ font-weight: 300;
+ line-height: 21px;
+ border: 1px solid #D8D8D8;
+ background-color: #FFFFFF;
+ text-align: center;
+ width: 100%;
+ height: 45px;
+ line-height: 44px;
+ font-family: Montserrat Light;
+ }
+
+ .simple-dropdown__selected {
+ text-align: center;
+ }
+}
+
+//Notification Modal
+
+.notification-modal-wrapper {
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ align-items: center;
+ position: relative;
+ border: 1px solid $alto;
+ box-shadow: 0 0 2px 2px $alto;
+ font-family: Roboto;
+}
+
+.notification-modal-header {
+ background: $wild-sand;
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ padding: 30px;
+ font-size: 22px;
+ color: $nile-blue;
+ height: 79px;
+}
+
+.notification-modal-message {
+ padding: 20px;
+}
+
+.notification-modal-message {
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ font-size: 17px;
+ color: $nile-blue;
+}
diff --git a/ui/app/css/itcss/components/transaction-list.scss b/ui/app/css/itcss/components/transaction-list.scss
index 0ff0b3dda..19dadc69a 100644
--- a/ui/app/css/itcss/components/transaction-list.scss
+++ b/ui/app/css/itcss/components/transaction-list.scss
@@ -206,7 +206,7 @@
}
@media screen and (min-width: $break-large) {
- margin: 0 2.37em;
+ padding: 0 2.37em;
}
&:last-of-type {
diff --git a/ui/app/css/itcss/settings/variables.scss b/ui/app/css/itcss/settings/variables.scss
index 8bd1ad20d..4c0972527 100644
--- a/ui/app/css/itcss/settings/variables.scss
+++ b/ui/app/css/itcss/settings/variables.scss
@@ -44,6 +44,8 @@ $jaffa: #f28930;
$geyser: #d2d8dd;
$manatee: #93949d;
$spindle: #c7ddec;
+$mid-gray: #5b5d67;
+$cape-cod: #38393a;
/*
Z-Indicies
diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js
index 3a4fb536d..e96dea0be 100644
--- a/ui/app/reducers/app.js
+++ b/ui/app/reducers/app.js
@@ -58,6 +58,7 @@ function reduceApp (state, action) {
isLoading: false,
// Used to display error text
warning: null,
+ buyView: {},
}, state.appState)
switch (action.type) {
@@ -591,8 +592,8 @@ function reduceApp (state, action) {
marketinfo: action.value.marketinfo,
coinOptions: action.value.coinOptions,
},
- buyAddress: appState.buyView.buyAddress,
- amount: appState.buyView.amount,
+ buyAddress: action.value.buyAddress || appState.buyView.buyAddress,
+ amount: appState.buyView.amount || 0,
},
})