mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 01:39:44 +01:00
New signature request v3 UI (#6891)
* Refactoring signature-request out to a new component. Wip * Styling polish and a better message display. * Update signature request header to no longer use account dropdown mini * Clean up code and styles * Code cleanup for signature request redesign branch * Fix signature request design for full screen * Replace makenode with object.entries in signature-request-message.component.js * Remove unused accounts prop from signature-request.component.js * Use beforeunload instead of window.onbeforeunload in signature-request
This commit is contained in:
parent
eed4a9ed65
commit
57a29668f3
@ -1188,6 +1188,9 @@
|
||||
"signatureRequest": {
|
||||
"message": "Signature Request"
|
||||
},
|
||||
"signatureRequest1": {
|
||||
"message": "Message"
|
||||
},
|
||||
"signed": {
|
||||
"message": "Signed"
|
||||
},
|
||||
|
@ -84,4 +84,4 @@
|
||||
|
||||
@import 'home-notification/index';
|
||||
|
||||
@import 'multiple-notifications/index';
|
||||
@import 'signature-request/index';
|
||||
|
@ -243,7 +243,7 @@ SignatureRequest.prototype.renderBody = function () {
|
||||
let notice = this.context.t('youSign') + ':'
|
||||
|
||||
const { txData } = this.props
|
||||
const { type, msgParams: { data, version } } = txData
|
||||
const { type, msgParams: { data } } = txData
|
||||
|
||||
if (type === 'personal_sign') {
|
||||
rows = [{ name: this.context.t('message'), value: this.msgHexToText(data) }]
|
||||
@ -275,17 +275,15 @@ SignatureRequest.prototype.renderBody = function () {
|
||||
}, [notice]),
|
||||
|
||||
h('div.request-signature__rows',
|
||||
type === 'eth_signTypedData' && (version === 'V3' || version === 'V4') ?
|
||||
this.renderTypedData(data) :
|
||||
rows.map(({ name, value }) => {
|
||||
if (typeof value === 'boolean') {
|
||||
value = value.toString()
|
||||
}
|
||||
return h('div.request-signature__row', [
|
||||
h('div.request-signature__row-title', [`${name}:`]),
|
||||
h('div.request-signature__row-value', value),
|
||||
])
|
||||
}),
|
||||
rows.map(({ name, value }, index) => {
|
||||
if (typeof value === 'boolean') {
|
||||
value = value.toString()
|
||||
}
|
||||
return h('div.request-signature__row', { key: `request-signature-row-${index}` }, [
|
||||
h('div.request-signature__row-title', [`${name}:`]),
|
||||
h('div.request-signature__row-value', value),
|
||||
])
|
||||
})
|
||||
),
|
||||
])
|
||||
}
|
1
ui/app/components/app/signature-request/index.js
Normal file
1
ui/app/components/app/signature-request/index.js
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './signature-request.container'
|
96
ui/app/components/app/signature-request/index.scss
Normal file
96
ui/app/components/app/signature-request/index.scss
Normal file
@ -0,0 +1,96 @@
|
||||
@import 'signature-request-footer/index';
|
||||
@import 'signature-request-header/index';
|
||||
@import 'signature-request-message/index';
|
||||
|
||||
.signature-request {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
|
||||
@media screen and (min-width: 576px) {
|
||||
flex: initial;
|
||||
}
|
||||
}
|
||||
|
||||
.signature-request-header {
|
||||
flex: 1;
|
||||
|
||||
.network-display__container {
|
||||
padding: 0;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.network-display__name {
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.signature-request-content {
|
||||
flex: 1 40%;
|
||||
margin-top: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
margin-bottom: 25px;
|
||||
min-height: min-content;
|
||||
|
||||
&__title {
|
||||
font-family: Roboto;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
&__identicon-container {
|
||||
padding: 1rem;
|
||||
flex: 1;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__identicon-border {
|
||||
height: 75px;
|
||||
width: 75px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid white;
|
||||
position: absolute;
|
||||
box-shadow: 0 2px 2px 0.5px rgba(0, 0, 0, 0.19);
|
||||
}
|
||||
|
||||
&__identicon-initial {
|
||||
position: absolute;
|
||||
font-family: Roboto;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-size: 60px;
|
||||
color: white;
|
||||
z-index: 1;
|
||||
text-shadow: 0px 4px 6px rgba(0, 0, 0, 0.422);
|
||||
}
|
||||
|
||||
&__info {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
&__info--bolded {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #999999;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.identicon {}
|
||||
}
|
||||
|
||||
.signature-request-footer {
|
||||
flex: 1 1 auto;
|
||||
}
|
@ -0,0 +1 @@
|
||||
export { default } from './signature-request-footer.component'
|
@ -0,0 +1,18 @@
|
||||
.signature-request-footer {
|
||||
display: flex;
|
||||
border-top: 1px solid #d2d8dd;
|
||||
|
||||
button {
|
||||
text-transform: uppercase;
|
||||
flex: 1;
|
||||
margin: 1rem 0.5rem;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
button:first-child() {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
button:last-child() {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
import React, { PureComponent } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Button from '../../../ui/button'
|
||||
|
||||
export default class SignatureRequestFooter extends PureComponent {
|
||||
static propTypes = {
|
||||
cancelAction: PropTypes.func.isRequired,
|
||||
signAction: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
static contextTypes = {
|
||||
t: PropTypes.func,
|
||||
}
|
||||
|
||||
render () {
|
||||
const { cancelAction, signAction } = this.props
|
||||
return (
|
||||
<div className="signature-request-footer">
|
||||
<Button onClick={cancelAction} type="default" large>{this.context.t('cancel')}</Button>
|
||||
<Button onClick={signAction} type="primary" large>{this.context.t('sign')}</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
export { default } from './signature-request-header.component'
|
@ -0,0 +1,25 @@
|
||||
.signature-request-header {
|
||||
display: flex;
|
||||
padding: 1rem;
|
||||
border-bottom: 1px solid $geyser;
|
||||
justify-content: space-between;
|
||||
font-size: .75rem;
|
||||
|
||||
&--account, &--network {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&--account {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.account-list-item__account-name {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.account-list-item__top-row {
|
||||
margin: 0px;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
import React, { PureComponent } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import AccountListItem from '../../../../pages/send/account-list-item/account-list-item.component'
|
||||
import NetworkDisplay from '../../network-display'
|
||||
|
||||
export default class SignatureRequestHeader extends PureComponent {
|
||||
static propTypes = {
|
||||
selectedAccount: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
render () {
|
||||
const { selectedAccount } = this.props
|
||||
|
||||
return (
|
||||
<div className="signature-request-header">
|
||||
<div className="signature-request-header--account">
|
||||
{selectedAccount && <AccountListItem
|
||||
displayBalance={false}
|
||||
account={selectedAccount}
|
||||
/>}
|
||||
{name}
|
||||
</div>
|
||||
<div className="signature-request-header--network">
|
||||
<NetworkDisplay colored={false} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
export { default } from './signature-request-message.component'
|
@ -0,0 +1,67 @@
|
||||
.signature-request-message {
|
||||
flex: 1 60%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
&__title {
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
color: #636778;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
flex: 1 1 0;
|
||||
text-align: left;
|
||||
font-size: 0.8rem;
|
||||
border-bottom: 1px solid #d2d8dd;
|
||||
padding: 0.5rem;
|
||||
margin: 0;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
&--root {
|
||||
flex: 1 100%;
|
||||
background-color: #f8f9fb;
|
||||
padding-bottom: 0.5rem;
|
||||
overflow: auto;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
width: 360px;
|
||||
font-family: monospace;
|
||||
|
||||
@media screen and (min-width: 576px) {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&__type-title {
|
||||
font-family: monospace;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
margin-left: 12px;
|
||||
margin-top: 6px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
&--node, &--node-leaf {
|
||||
padding-left: 0.8rem;
|
||||
|
||||
&-label {
|
||||
color: #5B5D67;
|
||||
}
|
||||
|
||||
&-value {
|
||||
color: black;
|
||||
margin-left: 0.5rem;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
&--node-leaf {
|
||||
display: flex;
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
import React, { PureComponent } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import classnames from 'classnames'
|
||||
|
||||
export default class SignatureRequestMessage extends PureComponent {
|
||||
static propTypes = {
|
||||
data: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
static contextTypes = {
|
||||
t: PropTypes.func,
|
||||
}
|
||||
|
||||
renderNode (data) {
|
||||
return (
|
||||
<div className="signature-request-message--node">
|
||||
{Object.entries(data).map(([ label, value ], i) => (
|
||||
<div
|
||||
className={classnames('signature-request-message--node', {
|
||||
'signature-request-message--node-leaf': typeof value !== 'object' || value === null,
|
||||
})}
|
||||
key={i}
|
||||
>
|
||||
<span className="signature-request-message--node-label">{label}: </span>
|
||||
{
|
||||
typeof value === 'object' && value !== null ?
|
||||
this.renderNode(value)
|
||||
: <span className="signature-request-message--node-value">{value}</span>
|
||||
}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
render () {
|
||||
const { data } = this.props
|
||||
|
||||
return (
|
||||
<div className="signature-request-message">
|
||||
<div className="signature-request-message__title">{this.context.t('signatureRequest1')}</div>
|
||||
<div className="signature-request-message--root">
|
||||
<div className="signature-request-message__type-title">{this.context.t('signatureRequest1')}</div>
|
||||
{this.renderNode(data)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
import React, { PureComponent } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Header from './signature-request-header'
|
||||
import Footer from './signature-request-footer'
|
||||
import Message from './signature-request-message'
|
||||
import { ENVIRONMENT_TYPE_NOTIFICATION } from './signature-request.constants'
|
||||
import { getEnvironmentType } from '../../../../../app/scripts/lib/util'
|
||||
import Identicon from '../../ui/identicon'
|
||||
|
||||
export default class SignatureRequest extends PureComponent {
|
||||
static propTypes = {
|
||||
txData: PropTypes.object.isRequired,
|
||||
selectedAccount: PropTypes.shape({
|
||||
address: PropTypes.string,
|
||||
balance: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
}).isRequired,
|
||||
|
||||
clearConfirmTransaction: PropTypes.func.isRequired,
|
||||
cancel: PropTypes.func.isRequired,
|
||||
sign: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
static contextTypes = {
|
||||
t: PropTypes.func,
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
const { clearConfirmTransaction, cancel } = this.props
|
||||
const { metricsEvent } = this.context
|
||||
if (getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_NOTIFICATION) {
|
||||
window.addEventListener('beforeunload', (event) => {
|
||||
metricsEvent({
|
||||
eventOpts: {
|
||||
category: 'Transactions',
|
||||
action: 'Sign Request',
|
||||
name: 'Cancel Sig Request Via Notification Close',
|
||||
},
|
||||
})
|
||||
clearConfirmTransaction()
|
||||
cancel(event)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
formatWallet (wallet) {
|
||||
return `${wallet.slice(0, 8)}...${wallet.slice(wallet.length - 8, wallet.length)}`
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
selectedAccount,
|
||||
txData: { msgParams: { data, origin, from: senderWallet }},
|
||||
cancel,
|
||||
sign,
|
||||
} = this.props
|
||||
const { message } = JSON.parse(data)
|
||||
|
||||
return (
|
||||
<div className="signature-request page-container">
|
||||
<Header selectedAccount={selectedAccount} />
|
||||
<div className="signature-request-content">
|
||||
<div className="signature-request-content__title">{this.context.t('sigRequest')}</div>
|
||||
<div className="signature-request-content__identicon-container">
|
||||
<div className="signature-request-content__identicon-initial" >{ message.from.name && message.from.name[0] }</div>
|
||||
<div className="signature-request-content__identicon-border" />
|
||||
<Identicon
|
||||
address={message.from.wallet}
|
||||
diameter={70}
|
||||
/>
|
||||
</div>
|
||||
<div className="signature-request-content__info--bolded">{message.from.name}</div>
|
||||
<div className="signature-request-content__info">{origin}</div>
|
||||
<div className="signature-request-content__info">{this.formatWallet(senderWallet)}</div>
|
||||
</div>
|
||||
<Message data={message} />
|
||||
<Footer cancelAction={cancel} signAction={sign} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../../app/scripts/lib/enums'
|
||||
|
||||
export { ENVIRONMENT_TYPE_NOTIFICATION }
|
@ -0,0 +1,72 @@
|
||||
import { connect } from 'react-redux'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import { compose } from 'recompose'
|
||||
import SignatureRequest from './signature-request.component'
|
||||
import { goHome } from '../../../store/actions'
|
||||
import { clearConfirmTransaction } from '../../../ducks/confirm-transaction/confirm-transaction.duck'
|
||||
import {
|
||||
getSelectedAccount,
|
||||
getCurrentAccountWithSendEtherInfo,
|
||||
getSelectedAddress,
|
||||
accountsWithSendEtherInfoSelector,
|
||||
conversionRateSelector,
|
||||
} from '../../../selectors/selectors.js'
|
||||
|
||||
function mapStateToProps (state) {
|
||||
return {
|
||||
balance: getSelectedAccount(state).balance,
|
||||
selectedAccount: getCurrentAccountWithSendEtherInfo(state),
|
||||
selectedAddress: getSelectedAddress(state),
|
||||
accounts: accountsWithSendEtherInfoSelector(state),
|
||||
conversionRate: conversionRateSelector(state),
|
||||
}
|
||||
}
|
||||
|
||||
function mapDispatchToProps (dispatch) {
|
||||
return {
|
||||
goHome: () => dispatch(goHome()),
|
||||
clearConfirmTransaction: () => dispatch(clearConfirmTransaction()),
|
||||
}
|
||||
}
|
||||
|
||||
function mergeProps (stateProps, dispatchProps, ownProps) {
|
||||
const {
|
||||
signPersonalMessage,
|
||||
signTypedMessage,
|
||||
cancelPersonalMessage,
|
||||
cancelTypedMessage,
|
||||
signMessage,
|
||||
cancelMessage,
|
||||
txData,
|
||||
} = ownProps
|
||||
|
||||
const { type } = txData
|
||||
|
||||
let cancel
|
||||
let sign
|
||||
|
||||
if (type === 'personal_sign') {
|
||||
cancel = cancelPersonalMessage
|
||||
sign = signPersonalMessage
|
||||
} else if (type === 'eth_signTypedData') {
|
||||
cancel = cancelTypedMessage
|
||||
sign = signTypedMessage
|
||||
} else if (type === 'eth_sign') {
|
||||
cancel = cancelMessage
|
||||
sign = signMessage
|
||||
}
|
||||
|
||||
return {
|
||||
...stateProps,
|
||||
...dispatchProps,
|
||||
...ownProps,
|
||||
txData,
|
||||
cancel,
|
||||
sign,
|
||||
}
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withRouter,
|
||||
connect(mapStateToProps, mapDispatchToProps, mergeProps)
|
||||
)(SignatureRequest)
|
@ -0,0 +1,25 @@
|
||||
import React from 'react'
|
||||
import assert from 'assert'
|
||||
import shallow from '../../../../../lib/shallow-with-context'
|
||||
import SignatureRequest from '../signature-request.component'
|
||||
|
||||
|
||||
describe('Signature Request Component', function () {
|
||||
let wrapper
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(<SignatureRequest txData={{
|
||||
msgParams: {
|
||||
data: '{"message": {"from": {"name": "hello"}}}',
|
||||
from: '0x123456789abcdef',
|
||||
} }} />)
|
||||
})
|
||||
|
||||
describe('render', () => {
|
||||
it('should render a div with one child', () => {
|
||||
assert(wrapper.is('div'))
|
||||
assert.equal(wrapper.length, 1)
|
||||
assert(wrapper.hasClass('signature-request'))
|
||||
})
|
||||
})
|
||||
})
|
@ -9,7 +9,8 @@ const txHelper = require('../../../lib/tx-helper')
|
||||
const log = require('loglevel')
|
||||
const R = require('ramda')
|
||||
|
||||
const SignatureRequest = require('../../components/app/signature-request')
|
||||
const SignatureRequest = require('../../components/app/signature-request').default
|
||||
const SignatureRequestOriginal = require('../../components/app/signature-request-original')
|
||||
const Loading = require('../../components/ui/loading-screen')
|
||||
const { DEFAULT_ROUTE } = require('../../helpers/constants/routes')
|
||||
|
||||
@ -137,34 +138,45 @@ ConfirmTxScreen.prototype.getTxData = function () {
|
||||
: unconfTxList[index]
|
||||
}
|
||||
|
||||
ConfirmTxScreen.prototype.signatureSelect = function (type, version) {
|
||||
// Temporarily direct only v3 and v4 requests to new code.
|
||||
if (type === 'eth_signTypedData' && (version === 'V3' || version === 'V4')) {
|
||||
return SignatureRequest
|
||||
}
|
||||
|
||||
return SignatureRequestOriginal
|
||||
}
|
||||
|
||||
ConfirmTxScreen.prototype.render = function () {
|
||||
const props = this.props
|
||||
const {
|
||||
currentCurrency,
|
||||
blockGasLimit,
|
||||
conversionRate,
|
||||
} = props
|
||||
|
||||
var txData = this.getTxData() || {}
|
||||
const { msgParams } = txData
|
||||
const { msgParams, type, msgParams: { version } } = txData
|
||||
log.debug('msgParams detected, rendering pending msg')
|
||||
|
||||
return msgParams
|
||||
? h(SignatureRequest, {
|
||||
// Properties
|
||||
txData: txData,
|
||||
key: txData.id,
|
||||
identities: props.identities,
|
||||
currentCurrency,
|
||||
blockGasLimit,
|
||||
// Actions
|
||||
signMessage: this.signMessage.bind(this, txData),
|
||||
signPersonalMessage: this.signPersonalMessage.bind(this, txData),
|
||||
signTypedMessage: this.signTypedMessage.bind(this, txData),
|
||||
cancelMessage: this.cancelMessage.bind(this, txData),
|
||||
cancelPersonalMessage: this.cancelPersonalMessage.bind(this, txData),
|
||||
cancelTypedMessage: this.cancelTypedMessage.bind(this, txData),
|
||||
})
|
||||
: h(Loading)
|
||||
return msgParams ? h(this.signatureSelect(type, version), {
|
||||
// Properties
|
||||
txData: txData,
|
||||
key: txData.id,
|
||||
selectedAddress: props.selectedAddress,
|
||||
accounts: props.accounts,
|
||||
identities: props.identities,
|
||||
conversionRate,
|
||||
currentCurrency,
|
||||
blockGasLimit,
|
||||
// Actions
|
||||
signMessage: this.signMessage.bind(this, txData),
|
||||
signPersonalMessage: this.signPersonalMessage.bind(this, txData),
|
||||
signTypedMessage: this.signTypedMessage.bind(this, txData),
|
||||
cancelMessage: this.cancelMessage.bind(this, txData),
|
||||
cancelPersonalMessage: this.cancelPersonalMessage.bind(this, txData),
|
||||
cancelTypedMessage: this.cancelTypedMessage.bind(this, txData),
|
||||
}) : h(Loading)
|
||||
}
|
||||
|
||||
ConfirmTxScreen.prototype.signMessage = function (msgData, event) {
|
||||
|
@ -45,6 +45,7 @@ export default class ConfirmTransaction extends Component {
|
||||
isTokenMethodAction: PropTypes.bool,
|
||||
fullScreenVsPopupTestGroup: PropTypes.string,
|
||||
trackABTest: PropTypes.bool,
|
||||
conversionRate: PropTypes.number,
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
@ -118,7 +119,6 @@ export default class ConfirmTransaction extends Component {
|
||||
// Show routes when state.confirmTransaction has been set and when either the ID in the params
|
||||
// isn't specified or is specified and matches the ID in state.confirmTransaction in order to
|
||||
// support URLs of /confirm-transaction or /confirm-transaction/<transactionId>
|
||||
|
||||
return transactionId && (!paramsTransactionId || paramsTransactionId === transactionId)
|
||||
? (
|
||||
<Switch>
|
||||
|
@ -25,6 +25,7 @@ const mapStateToProps = (state, ownProps) => {
|
||||
send,
|
||||
unapprovedTxs,
|
||||
abTests: { fullScreenVsPopup },
|
||||
conversionRate,
|
||||
},
|
||||
confirmTransaction,
|
||||
} = state
|
||||
@ -53,6 +54,7 @@ const mapStateToProps = (state, ownProps) => {
|
||||
isTokenMethodAction: isTokenMethodAction(transactionCategory),
|
||||
trackABTest,
|
||||
fullScreenVsPopupTestGroup: fullScreenVsPopup,
|
||||
conversionRate,
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user