aboutsummaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
Diffstat (limited to 'ui')
-rw-r--r--ui/app/components/modals/account-details-modal.js2
-rw-r--r--ui/app/components/modals/account-modal-container.js4
-rw-r--r--ui/app/components/modals/export-private-key-modal.js48
-rw-r--r--ui/app/components/send/send-content/send-to-row/send-to-row.component.js2
-rw-r--r--ui/app/components/send/send-content/send-to-row/tests/send-to-row-component.test.js2
-rw-r--r--ui/app/components/sender-to-recipient/index.scss147
-rw-r--r--ui/app/components/sender-to-recipient/sender-to-recipient.component.js141
-rw-r--r--ui/app/components/sender-to-recipient/sender-to-recipient.constants.js3
8 files changed, 238 insertions, 111 deletions
diff --git a/ui/app/components/modals/account-details-modal.js b/ui/app/components/modals/account-details-modal.js
index cc90cf578..bc577fda0 100644
--- a/ui/app/components/modals/account-details-modal.js
+++ b/ui/app/components/modals/account-details-modal.js
@@ -61,7 +61,7 @@ AccountDetailsModal.prototype.render = function () {
let exportPrivateKeyFeatureEnabled = true
// This feature is disabled for hardware wallets
- if (keyring.type.search('Hardware') !== -1) {
+ if (keyring && keyring.type.search('Hardware') !== -1) {
exportPrivateKeyFeatureEnabled = false
}
diff --git a/ui/app/components/modals/account-modal-container.js b/ui/app/components/modals/account-modal-container.js
index a9856b20f..aa0593df8 100644
--- a/ui/app/components/modals/account-modal-container.js
+++ b/ui/app/components/modals/account-modal-container.js
@@ -7,9 +7,9 @@ const actions = require('../../actions')
const { getSelectedIdentity } = require('../../selectors')
const Identicon = require('../identicon')
-function mapStateToProps (state) {
+function mapStateToProps (state, ownProps) {
return {
- selectedIdentity: getSelectedIdentity(state),
+ selectedIdentity: ownProps.selectedIdentity || getSelectedIdentity(state),
}
}
diff --git a/ui/app/components/modals/export-private-key-modal.js b/ui/app/components/modals/export-private-key-modal.js
index 80ece425f..60a416304 100644
--- a/ui/app/components/modals/export-private-key-modal.js
+++ b/ui/app/components/modals/export-private-key-modal.js
@@ -1,3 +1,4 @@
+const log = require('loglevel')
const Component = require('react').Component
const PropTypes = require('prop-types')
const h = require('react-hyperscript')
@@ -11,19 +12,33 @@ const ReadOnlyInput = require('../readonly-input')
const copyToClipboard = require('copy-to-clipboard')
const { checksumAddress } = require('../../util')
-function mapStateToProps (state) {
- return {
- warning: state.appState.warning,
- privateKey: state.appState.accountDetail.privateKey,
- network: state.metamask.network,
- selectedIdentity: getSelectedIdentity(state),
- previousModalState: state.appState.modal.previousModalState.name,
+function mapStateToPropsFactory () {
+ let selectedIdentity = null
+ return function mapStateToProps (state) {
+ // We should **not** change the identity displayed here even if it changes from underneath us.
+ // If we do, we will be showing the user one private key and a **different** address and name.
+ // Note that the selected identity **will** change from underneath us when we unlock the keyring
+ // which is the expected behavior that we are side-stepping.
+ selectedIdentity = selectedIdentity || getSelectedIdentity(state)
+ return {
+ warning: state.appState.warning,
+ privateKey: state.appState.accountDetail.privateKey,
+ network: state.metamask.network,
+ selectedIdentity,
+ previousModalState: state.appState.modal.previousModalState.name,
+ }
}
}
function mapDispatchToProps (dispatch) {
return {
- exportAccount: (password, address) => dispatch(actions.exportAccount(password, address)),
+ exportAccount: (password, address) => {
+ return dispatch(actions.exportAccount(password, address))
+ .then((res) => {
+ dispatch(actions.hideWarning())
+ return res
+ })
+ },
showAccountDetailModal: () => dispatch(actions.showModal({ name: 'ACCOUNT_DETAILS' })),
hideModal: () => dispatch(actions.hideModal()),
}
@@ -36,6 +51,7 @@ function ExportPrivateKeyModal () {
this.state = {
password: '',
privateKey: null,
+ showWarning: true,
}
}
@@ -43,14 +59,18 @@ ExportPrivateKeyModal.contextTypes = {
t: PropTypes.func,
}
-module.exports = connect(mapStateToProps, mapDispatchToProps)(ExportPrivateKeyModal)
+module.exports = connect(mapStateToPropsFactory, mapDispatchToProps)(ExportPrivateKeyModal)
ExportPrivateKeyModal.prototype.exportAccountAndGetPrivateKey = function (password, address) {
const { exportAccount } = this.props
exportAccount(password, address)
- .then(privateKey => this.setState({ privateKey }))
+ .then(privateKey => this.setState({
+ privateKey,
+ showWarning: false,
+ }))
+ .catch((e) => log.error(e))
}
ExportPrivateKeyModal.prototype.renderPasswordLabel = function (privateKey) {
@@ -110,9 +130,13 @@ ExportPrivateKeyModal.prototype.render = function () {
} = this.props
const { name, address } = selectedIdentity
- const { privateKey } = this.state
+ const {
+ privateKey,
+ showWarning,
+ } = this.state
return h(AccountModalContainer, {
+ selectedIdentity,
showBackButton: previousModalState === 'ACCOUNT_DETAILS',
backButtonAction: () => showAccountDetailModal(),
}, [
@@ -134,7 +158,7 @@ ExportPrivateKeyModal.prototype.render = function () {
this.renderPasswordInput(privateKey),
- !warning ? null : h('span.private-key-password-error', warning),
+ showWarning && warning ? h('span.private-key-password-error', warning) : null,
]),
h('div.private-key-password-warning', this.context.t('privateKeyWarning')),
diff --git a/ui/app/components/send/send-content/send-to-row/send-to-row.component.js b/ui/app/components/send/send-content/send-to-row/send-to-row.component.js
index 1163dcffc..434db81e5 100644
--- a/ui/app/components/send/send-content/send-to-row/send-to-row.component.js
+++ b/ui/app/components/send/send-content/send-to-row/send-to-row.component.js
@@ -48,7 +48,7 @@ export default class SendToRow extends Component {
return (
<SendRowWrapper
errorType={'to'}
- label={`${this.context.t('to')}`}
+ label={`${this.context.t('to')}: `}
showError={inError}
>
<EnsInput
diff --git a/ui/app/components/send/send-content/send-to-row/tests/send-to-row-component.test.js b/ui/app/components/send/send-content/send-to-row/tests/send-to-row-component.test.js
index 781371004..591229deb 100644
--- a/ui/app/components/send/send-content/send-to-row/tests/send-to-row-component.test.js
+++ b/ui/app/components/send/send-content/send-to-row/tests/send-to-row-component.test.js
@@ -102,7 +102,7 @@ describe('SendToRow Component', function () {
assert.equal(errorType, 'to')
- assert.equal(label, 'to_t')
+ assert.equal(label, 'to_t: ')
assert.equal(showError, false)
})
diff --git a/ui/app/components/sender-to-recipient/index.scss b/ui/app/components/sender-to-recipient/index.scss
index a97393b8f..656e30ddf 100644
--- a/ui/app/components/sender-to-recipient/index.scss
+++ b/ui/app/components/sender-to-recipient/index.scss
@@ -1,5 +1,5 @@
.sender-to-recipient {
- &__container {
+ &--default {
width: 100%;
display: flex;
flex-direction: row;
@@ -8,67 +8,114 @@
position: relative;
flex: 0 0 auto;
height: 42px;
- }
- &__tooltip-wrapper {
- min-width: 0;
- }
+ .sender-to-recipient {
+ &__tooltip-wrapper {
+ min-width: 0;
+ }
- &__tooltip-container {
- max-width: 100%;
- }
+ &__tooltip-container {
+ max-width: 100%;
+ }
- &__sender,
- &__recipient {
- display: flex;
- flex-direction: row;
- align-items: center;
- flex: 1;
- padding: 0 16px;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
+ &__party {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ flex: 1;
+ padding: 0 16px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
- &__sender {
- padding-right: 30px;
- cursor: pointer;
- }
+ &--sender {
+ padding-right: 30px;
+ cursor: pointer;
+ }
+
+ &--recipient {
+ padding-left: 30px;
+ border-left: 1px solid $geyser;
+
+ &-with-address {
+ cursor: pointer;
+ }
+ }
+ }
- &__recipient {
- padding-left: 30px;
- border-left: 1px solid $geyser;
+ &__arrow-container {
+ position: absolute;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
- &--with-address {
- cursor: pointer;
+ &__arrow-circle {
+ background: $white;
+ padding: 5px;
+ border: 1px solid $geyser;
+ border-radius: 20px;
+ height: 32px;
+ width: 32px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
+ &__name {
+ padding-left: 14px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ font-size: .875rem;
+ }
}
}
- &__arrow-container {
- position: absolute;
- height: 100%;
+ &--cards {
+ width: 100%;
display: flex;
- align-items: center;
+ flex-direction: row;
justify-content: center;
- }
+ position: relative;
+ flex: 0 0 auto;
+ padding: 8px;
- &__arrow-circle {
- background: $white;
- padding: 5px;
- border: 1px solid $geyser;
- border-radius: 20px;
- height: 32px;
- width: 32px;
- display: flex;
- justify-content: center;
- align-items: center;
- }
+ .sender-to-recipient {
+ &__party {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ flex: 1;
+ border-radius: 4px;
+ box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.08);
+ padding: 6px;
+ background: $white;
+ cursor: pointer;
+ min-width: 0;
+ color: $dusty-gray;
+ }
+
+ &__tooltip-wrapper {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
- &__name {
- padding-left: 14px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- font-size: .875rem;
+ &__name {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ font-size: .5rem;
+ }
+
+ &__arrow-container {
+ padding: 0 2px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+ }
}
}
diff --git a/ui/app/components/sender-to-recipient/sender-to-recipient.component.js b/ui/app/components/sender-to-recipient/sender-to-recipient.component.js
index cae173b56..5af4045f5 100644
--- a/ui/app/components/sender-to-recipient/sender-to-recipient.component.js
+++ b/ui/app/components/sender-to-recipient/sender-to-recipient.component.js
@@ -1,16 +1,29 @@
-import React, { Component } from 'react'
+import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
+import classnames from 'classnames'
import Identicon from '../identicon'
import Tooltip from '../tooltip-v2'
import copyToClipboard from 'copy-to-clipboard'
+import { DEFAULT_VARIANT, CARDS_VARIANT } from './sender-to-recipient.constants'
-export default class SenderToRecipient extends Component {
+const variantHash = {
+ [DEFAULT_VARIANT]: 'sender-to-recipient--default',
+ [CARDS_VARIANT]: 'sender-to-recipient--cards',
+}
+
+export default class SenderToRecipient extends PureComponent {
static propTypes = {
senderName: PropTypes.string,
senderAddress: PropTypes.string,
recipientName: PropTypes.string,
recipientAddress: PropTypes.string,
t: PropTypes.func,
+ variant: PropTypes.oneOf([DEFAULT_VARIANT, CARDS_VARIANT]),
+ addressOnly: PropTypes.bool,
+ }
+
+ static defaultProps = {
+ variant: DEFAULT_VARIANT,
}
static contextTypes = {
@@ -22,24 +35,62 @@ export default class SenderToRecipient extends Component {
recipientAddressCopied: false,
}
+ renderSenderIdenticon () {
+ return !this.props.addressOnly && (
+ <div className="sender-to-recipient__sender-icon">
+ <Identicon
+ address={this.props.senderAddress}
+ diameter={24}
+ />
+ </div>
+ )
+ }
+
+ renderSenderAddress () {
+ const { t } = this.context
+ const { senderName, senderAddress, addressOnly } = this.props
+
+ return (
+ <Tooltip
+ position="bottom"
+ title={this.state.senderAddressCopied ? t('copiedExclamation') : t('copyAddress')}
+ wrapperClassName="sender-to-recipient__tooltip-wrapper"
+ containerClassName="sender-to-recipient__tooltip-container"
+ onHidden={() => this.setState({ senderAddressCopied: false })}
+ >
+ <div className="sender-to-recipient__name">
+ { addressOnly ? `${t('from')}: ${senderAddress}` : senderName }
+ </div>
+ </Tooltip>
+ )
+ }
+
+ renderRecipientIdenticon () {
+ const { recipientAddress } = this.props
+
+ return !this.props.addressOnly && (
+ <div className="sender-to-recipient__sender-icon">
+ <Identicon
+ address={recipientAddress}
+ diameter={24}
+ />
+ </div>
+ )
+ }
+
renderRecipientWithAddress () {
const { t } = this.context
- const { recipientName, recipientAddress } = this.props
+ const { recipientName, recipientAddress, addressOnly } = this.props
return (
<div
- className="sender-to-recipient__recipient sender-to-recipient__recipient--with-address"
+ className="sender-to-recipient__party sender-to-recipient__party--recipient sender-to-recipient__party--recipient-with-address"
onClick={() => {
this.setState({ recipientAddressCopied: true })
copyToClipboard(recipientAddress)
}}
>
- <div className="sender-to-recipient__sender-icon">
- <Identicon
- address={recipientAddress}
- diameter={24}
- />
- </div>
+ { this.renderRecipientIdenticon() }
<Tooltip
position="bottom"
title={this.state.recipientAddressCopied ? t('copiedExclamation') : t('copyAddress')}
@@ -47,8 +98,12 @@ export default class SenderToRecipient extends Component {
containerClassName="sender-to-recipient__tooltip-container"
onHidden={() => this.setState({ recipientAddressCopied: false })}
>
- <div className="sender-to-recipient__name sender-to-recipient__recipient-name">
- { recipientName || this.context.t('newContract') }
+ <div className="sender-to-recipient__name">
+ {
+ addressOnly
+ ? `${t('to')}: ${recipientAddress}`
+ : (recipientName || this.context.t('newContract'))
+ }
</div>
</Tooltip>
</div>
@@ -57,46 +112,25 @@ export default class SenderToRecipient extends Component {
renderRecipientWithoutAddress () {
return (
- <div className="sender-to-recipient__recipient">
+ <div className="sender-to-recipient__party sender-to-recipient__party--recipient">
<i className="fa fa-file-text-o" />
- <div className="sender-to-recipient__name sender-to-recipient__recipient-name">
+ <div className="sender-to-recipient__name">
{ this.context.t('newContract') }
</div>
</div>
)
}
- render () {
- const { t } = this.context
- const { senderName, senderAddress, recipientAddress } = this.props
-
- return (
- <div className="sender-to-recipient__container">
- <div
- className="sender-to-recipient__sender"
- onClick={() => {
- this.setState({ senderAddressCopied: true })
- copyToClipboard(senderAddress)
- }}
- >
- <div className="sender-to-recipient__sender-icon">
- <Identicon
- address={senderAddress}
- diameter={24}
- />
- </div>
- <Tooltip
- position="bottom"
- title={this.state.senderAddressCopied ? t('copiedExclamation') : t('copyAddress')}
- wrapperClassName="sender-to-recipient__tooltip-wrapper"
- containerClassName="sender-to-recipient__tooltip-container"
- onHidden={() => this.setState({ senderAddressCopied: false })}
- >
- <div className="sender-to-recipient__name sender-to-recipient__sender-name">
- { senderName }
- </div>
- </Tooltip>
+ renderArrow () {
+ return this.props.variant === CARDS_VARIANT
+ ? (
+ <div className="sender-to-recipient__arrow-container">
+ <img
+ height={20}
+ src="./images/caret-right.svg"
+ />
</div>
+ ) : (
<div className="sender-to-recipient__arrow-container">
<div className="sender-to-recipient__arrow-circle">
<img
@@ -106,6 +140,25 @@ export default class SenderToRecipient extends Component {
/>
</div>
</div>
+ )
+ }
+
+ render () {
+ const { senderAddress, recipientAddress, variant } = this.props
+
+ return (
+ <div className={classnames(variantHash[variant])}>
+ <div
+ className={classnames('sender-to-recipient__party sender-to-recipient__party--sender')}
+ onClick={() => {
+ this.setState({ senderAddressCopied: true })
+ copyToClipboard(senderAddress)
+ }}
+ >
+ { this.renderSenderIdenticon() }
+ { this.renderSenderAddress() }
+ </div>
+ { this.renderArrow() }
{
recipientAddress
? this.renderRecipientWithAddress()
diff --git a/ui/app/components/sender-to-recipient/sender-to-recipient.constants.js b/ui/app/components/sender-to-recipient/sender-to-recipient.constants.js
new file mode 100644
index 000000000..166228932
--- /dev/null
+++ b/ui/app/components/sender-to-recipient/sender-to-recipient.constants.js
@@ -0,0 +1,3 @@
+// Component design variants
+export const DEFAULT_VARIANT = 'DEFAULT_VARIANT'
+export const CARDS_VARIANT = 'CARDS_VARIANT'