aboutsummaryrefslogtreecommitdiffstats
path: root/ui/app/components
diff options
context:
space:
mode:
Diffstat (limited to 'ui/app/components')
-rw-r--r--ui/app/components/app/account-details/account-details.component.js99
-rw-r--r--ui/app/components/app/account-details/account-details.container.js14
-rw-r--r--ui/app/components/app/account-details/index.js1
-rw-r--r--ui/app/components/app/account-details/index.scss79
-rw-r--r--ui/app/components/app/app-header/app-header.component.js18
-rw-r--r--ui/app/components/app/app-header/index.scss3
-rw-r--r--ui/app/components/app/confirm-page-container/confirm-detail-row/tests/confirm-detail-row.component.test.js4
-rwxr-xr-xui/app/components/app/confirm-page-container/confirm-page-container-navigation/confirm-page-container-navigation.component.js6
-rw-r--r--ui/app/components/app/confirm-page-container/confirm-page-container.component.js20
-rw-r--r--ui/app/components/app/contact-list/contact-list.component.js114
-rw-r--r--ui/app/components/app/contact-list/index.js1
-rw-r--r--ui/app/components/app/contact-list/recipient-group/index.js1
-rw-r--r--ui/app/components/app/contact-list/recipient-group/recipient-group.component.js59
-rw-r--r--ui/app/components/app/dropdowns/account-details-dropdown.js2
-rw-r--r--ui/app/components/app/dropdowns/network-dropdown.js16
-rw-r--r--ui/app/components/app/ens-input.js181
-rw-r--r--ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.component.js4
-rw-r--r--ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js6
-rw-r--r--ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/index.scss24
-rw-r--r--ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/tests/advanced-tab-content-component.test.js2
-rw-r--r--ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/index.js1
-rw-r--r--ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/index.scss17
-rw-r--r--ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/tests/time-remaining-component.test.js30
-rw-r--r--ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/time-remaining.component.js33
-rw-r--r--ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/time-remaining.utils.js11
-rw-r--r--ui/app/components/app/gas-customization/gas-modal-page-container/basic-tab-content/basic-tab-content.component.js12
-rw-r--r--ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js12
-rw-r--r--ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js74
-rw-r--r--ui/app/components/app/gas-customization/gas-price-chart/gas-price-chart.utils.js36
-rw-r--r--ui/app/components/app/home-notification/home-notification.component.js112
-rw-r--r--ui/app/components/app/home-notification/index.js1
-rw-r--r--ui/app/components/app/home-notification/index.scss118
-rw-r--r--ui/app/components/app/index.scss8
-rw-r--r--ui/app/components/app/menu-droppo.js2
-rw-r--r--ui/app/components/app/modals/account-details-modal/account-details-modal.component.js16
-rw-r--r--ui/app/components/app/modals/add-to-addressbook-modal/add-to-addressbook-modal.component.js79
-rw-r--r--ui/app/components/app/modals/add-to-addressbook-modal/add-to-addressbook-modal.container.js18
-rw-r--r--ui/app/components/app/modals/add-to-addressbook-modal/index.js1
-rw-r--r--ui/app/components/app/modals/add-to-addressbook-modal/index.scss37
-rw-r--r--ui/app/components/app/modals/confirm-delete-network/confirm-delete-network.component.js43
-rw-r--r--ui/app/components/app/modals/confirm-delete-network/confirm-delete-network.container.js16
-rw-r--r--ui/app/components/app/modals/confirm-delete-network/index.js1
-rw-r--r--ui/app/components/app/modals/deposit-ether-modal.js28
-rw-r--r--ui/app/components/app/modals/export-private-key-modal.js46
-rw-r--r--ui/app/components/app/modals/index.scss2
-rw-r--r--ui/app/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.component.js15
-rw-r--r--ui/app/components/app/modals/modal.js45
-rw-r--r--ui/app/components/app/modals/new-account-modal.js2
-rw-r--r--ui/app/components/app/modals/notification-modal.js2
-rw-r--r--ui/app/components/app/modals/qr-scanner/qr-scanner.component.js36
-rw-r--r--ui/app/components/app/multiple-notifications/index.js1
-rw-r--r--ui/app/components/app/multiple-notifications/index.scss78
-rw-r--r--ui/app/components/app/multiple-notifications/multiple-notifications.component.js44
-rw-r--r--ui/app/components/app/network-display/network-display.component.js24
-rw-r--r--ui/app/components/app/network.js24
-rw-r--r--ui/app/components/app/provider-page-container/provider-page-container-content/provider-page-container-content.component.js2
-rw-r--r--ui/app/components/app/sidebars/sidebar.component.js4
-rw-r--r--ui/app/components/app/sidebars/tests/sidebars-component.test.js2
-rw-r--r--ui/app/components/app/signature-request.js28
-rw-r--r--ui/app/components/app/token-list.js18
-rw-r--r--ui/app/components/app/transaction-activity-log/transaction-activity-log-icon/transaction-activity-log-icon.component.js18
-rw-r--r--ui/app/components/app/transaction-list-item-details/tests/transaction-list-item-details.component.test.js69
-rw-r--r--ui/app/components/app/transaction-list-item-details/transaction-list-item-details.component.js6
-rw-r--r--ui/app/components/app/transaction-list/transaction-list.component.js9
-rw-r--r--ui/app/components/app/transaction-status/index.scss6
-rw-r--r--ui/app/components/app/transaction-status/transaction-status.component.js3
-rw-r--r--ui/app/components/app/transaction-view-balance/transaction-view-balance.component.js62
-rw-r--r--ui/app/components/app/transaction-view/transaction-view.component.js12
-rw-r--r--ui/app/components/app/ui-migration-annoucement/index.js1
-rw-r--r--ui/app/components/app/ui-migration-annoucement/index.scss22
-rw-r--r--ui/app/components/app/ui-migration-annoucement/ui-migration-annoucement.component.js33
-rw-r--r--ui/app/components/app/ui-migration-annoucement/ui-migration-announcement.container.js21
-rw-r--r--ui/app/components/app/wallet-view.js80
-rw-r--r--ui/app/components/ui/account-dropdown-mini/account-dropdown-mini.component.js84
-rw-r--r--ui/app/components/ui/account-dropdown-mini/index.js1
-rw-r--r--ui/app/components/ui/account-dropdown-mini/tests/account-dropdown-mini.component.test.js107
-rw-r--r--ui/app/components/ui/alert/index.js90
-rw-r--r--ui/app/components/ui/button-group/tests/button-group-component.test.js50
-rw-r--r--ui/app/components/ui/button/buttons.scss1
-rw-r--r--ui/app/components/ui/currency-input/currency-input.component.js32
-rw-r--r--ui/app/components/ui/dialog/dialog.scss26
-rw-r--r--ui/app/components/ui/dialog/index.js26
-rw-r--r--ui/app/components/ui/identicon/identicon.component.js11
-rw-r--r--ui/app/components/ui/identicon/index.scss13
-rw-r--r--ui/app/components/ui/metafox-logo/index.js1
-rw-r--r--ui/app/components/ui/metafox-logo/metafox-logo.component.js31
-rw-r--r--ui/app/components/ui/metafox-logo/tests/metafox-logo.component.test.js25
-rw-r--r--ui/app/components/ui/page-container/page-container-header/page-container-header.component.js16
-rw-r--r--ui/app/components/ui/sender-to-recipient/sender-to-recipient.component.js8
-rw-r--r--ui/app/components/ui/text-field/text-field.component.js3
-rw-r--r--ui/app/components/ui/toggle-button/index.js2
-rw-r--r--ui/app/components/ui/toggle-button/index.scss14
-rw-r--r--ui/app/components/ui/toggle-button/toggle-button.component.js75
-rw-r--r--ui/app/components/ui/unit-input/index.scss1
94 files changed, 1673 insertions, 1019 deletions
diff --git a/ui/app/components/app/account-details/account-details.component.js b/ui/app/components/app/account-details/account-details.component.js
new file mode 100644
index 000000000..ecf2f9428
--- /dev/null
+++ b/ui/app/components/app/account-details/account-details.component.js
@@ -0,0 +1,99 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import classnames from 'classnames'
+import Identicon from '../../ui/identicon'
+import Tooltip from '../../ui/tooltip-v2'
+import copyToClipboard from 'copy-to-clipboard'
+
+export default class AccountDetails extends Component {
+ static contextTypes = {
+ t: PropTypes.func.isRequired,
+ metricsEvent: PropTypes.func,
+ }
+
+ static defaultProps = {
+ hideSidebar: () => {},
+ showAccountDetailModal: () => {},
+ }
+
+ static propTypes = {
+ hideSidebar: PropTypes.func,
+ showAccountDetailModal: PropTypes.func,
+ label: PropTypes.string.isRequired,
+ checksummedAddress: PropTypes.string.isRequired,
+ name: PropTypes.string.isRequired,
+ }
+
+ state = {
+ hasCopied: false,
+ copyToClipboardPressed: false,
+ }
+
+ copyAddress () {
+ copyToClipboard(this.props.checksummedAddress)
+ this.context.metricsEvent({
+ eventOpts: {
+ category: 'Navigation',
+ action: 'Home',
+ name: 'Copied Address',
+ },
+ })
+ this.setState({ hasCopied: true })
+ setTimeout(() => this.setState({ hasCopied: false }), 3000)
+ }
+
+ render () {
+ const { t } = this.context
+
+ const {
+ hideSidebar,
+ showAccountDetailModal,
+ label,
+ checksummedAddress,
+ name,
+ } = this.props
+
+ const {
+ hasCopied,
+ copyToClipboardPressed,
+ } = this.state
+
+ return (
+ <div>
+ <div className="flex-column account-details">
+ <div className="account-details__sidebar-close" onClick={hideSidebar} />
+ <div className="account-details__keyring-label allcaps">
+ {label}
+ </div>
+ <div className="flex-column flex-center account-details__name-container" onClick={showAccountDetailModal}>
+ <Identicon diameter={54} address={checksummedAddress} />
+ <span className="account-details__account-name">
+ {name}
+ </span>
+ <button className="btn-secondary account-details__details-button">
+ {t('details')}
+ </button>
+ </div>
+ </div>
+ <Tooltip
+ position={'bottom'}
+ title={hasCopied ? t('copiedExclamation') : t('copyToClipboard')}
+ wrapperClassName="account-details__tooltip"
+ >
+ <button
+ className={classnames({
+ 'account-details__address': true,
+ 'account-details__address__pressed': copyToClipboardPressed,
+ })}
+ onClick={() => this.copyAddress()}
+ onMouseDown={() => this.setState({ copyToClipboardPressed: true })}
+ onMouseUp={() => this.setState({ copyToClipboardPressed: false })}
+ >
+ {checksummedAddress.slice(0, 6)}...{checksummedAddress.slice(-4)}
+ <i className="fa fa-clipboard" style={{ marginLeft: '8px' }} />
+ </button>
+ </Tooltip>
+ </div>
+ )
+ }
+}
diff --git a/ui/app/components/app/account-details/account-details.container.js b/ui/app/components/app/account-details/account-details.container.js
new file mode 100644
index 000000000..581ff1e2f
--- /dev/null
+++ b/ui/app/components/app/account-details/account-details.container.js
@@ -0,0 +1,14 @@
+import { connect } from 'react-redux'
+import { hideSidebar, showModal } from '../../../store/actions'
+import AccountDetails from './account-details.component'
+
+function mapDispatchToProps (dispatch) {
+ return {
+ hideSidebar: () => dispatch(hideSidebar()),
+ showAccountDetailModal: () => {
+ dispatch(showModal({ name: 'ACCOUNT_DETAILS' }))
+ },
+ }
+}
+
+export default connect(null, mapDispatchToProps)(AccountDetails)
diff --git a/ui/app/components/app/account-details/index.js b/ui/app/components/app/account-details/index.js
new file mode 100644
index 000000000..dca244fee
--- /dev/null
+++ b/ui/app/components/app/account-details/index.js
@@ -0,0 +1 @@
+export { default } from './account-details.container'
diff --git a/ui/app/components/app/account-details/index.scss b/ui/app/components/app/account-details/index.scss
new file mode 100644
index 000000000..b0a921df3
--- /dev/null
+++ b/ui/app/components/app/account-details/index.scss
@@ -0,0 +1,79 @@
+.account-details {
+ flex: 0 0 auto;
+
+ &__keyring-label {
+ height: 50px;
+ color: $dusty-gray;
+ font-family: Roboto;
+ font-size: 10px;
+ text-align: right;
+ padding: 17px 20px 0;
+ box-sizing: border-box;
+ }
+
+ &__name-container {
+ flex: 0 0 auto;
+ cursor: pointer;
+ width: 100%;
+ margin: 0 auto;
+ }
+
+ &__account-name {
+ font-size: 24px;
+ color: $black;
+ margin-top: 8px;
+ margin-bottom: .9rem;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ width: 100%;
+ padding: 0 8px;
+ text-align: center;
+ }
+
+ &__details-button {
+ font-size: 10px;
+ border-radius: 17px;
+ background-color: transparent;
+ margin: 0 auto;
+ padding: 4px 12px;
+ flex: 0 0 auto;
+ }
+
+ &__tooltip {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ padding: 24px;
+ }
+
+ &__address {
+ border-radius: 3px;
+ background-color: $alto;
+ color: $scorpion;
+ font-size: 14px;
+ line-height: 12px;
+ padding: 4px 12px;
+ cursor: pointer;
+ flex: 0 0 auto;
+
+ &__pressed {
+ background-color: $manatee,
+ }
+ }
+
+ &__sidebar-close {
+
+ @media screen and (max-width: 575px) {
+ &::after {
+ content: '\00D7';
+ font-size: 40px;
+ color: $tundora;
+ position: absolute;
+ top: 12px;
+ left: 12px;
+ cursor: pointer;
+ }
+ }
+ }
+}
diff --git a/ui/app/components/app/app-header/app-header.component.js b/ui/app/components/app/app-header/app-header.component.js
index 171a3499f..7bf7a39bd 100644
--- a/ui/app/components/app/app-header/app-header.component.js
+++ b/ui/app/components/app/app-header/app-header.component.js
@@ -2,6 +2,7 @@ import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import Identicon from '../../ui/identicon'
+import MetaFoxLogo from '../../ui/metafox-logo'
import { DEFAULT_ROUTE } from '../../../helpers/constants/routes'
const NetworkIndicator = require('../network')
@@ -70,6 +71,7 @@ export default class AppHeader extends PureComponent {
<Identicon
address={selectedAddress}
diameter={32}
+ addBorder={true}
/>
</div>
)
@@ -89,20 +91,10 @@ export default class AppHeader extends PureComponent {
<div
className={classnames('app-header', { 'app-header--back-drop': isUnlocked })}>
<div className="app-header__contents">
- <div
- className="app-header__logo-container"
+ <MetaFoxLogo
+ unsetIconHeight={true}
onClick={() => history.push(DEFAULT_ROUTE)}
- >
- <img
- className="app-header__metafox-logo app-header__metafox-logo--horizontal"
- src="/images/logo/metamask-logo-horizontal.svg"
- height={30}
- />
- <img
- className="app-header__metafox-logo app-header__metafox-logo--icon"
- src="/images/logo/metamask-fox.svg"
- />
- </div>
+ />
<div className="app-header__account-menu-container">
{
!hideNetworkIndicator && (
diff --git a/ui/app/components/app/app-header/index.scss b/ui/app/components/app/app-header/index.scss
index d3f37b7a2..0ea1793ca 100644
--- a/ui/app/components/app/app-header/index.scss
+++ b/ui/app/components/app/app-header/index.scss
@@ -10,7 +10,6 @@
@media screen and (max-width: 575px) {
padding: 1rem;
- box-shadow: 0 0 0 1px rgba(0, 0, 0, .08);
z-index: $mobile-header-z-index;
}
@@ -24,7 +23,7 @@
position: absolute;
width: 100%;
height: 32px;
- background: $gallery;
+ background: $Grey-000;
bottom: -32px;
}
}
diff --git a/ui/app/components/app/confirm-page-container/confirm-detail-row/tests/confirm-detail-row.component.test.js b/ui/app/components/app/confirm-page-container/confirm-detail-row/tests/confirm-detail-row.component.test.js
index c8507985d..95ca8144a 100644
--- a/ui/app/components/app/confirm-page-container/confirm-detail-row/tests/confirm-detail-row.component.test.js
+++ b/ui/app/components/app/confirm-page-container/confirm-detail-row/tests/confirm-detail-row.component.test.js
@@ -27,7 +27,7 @@ describe('Confirm Detail Row Component', function () {
)
})
- describe('render', () => {
+ describe('render', () => {
it('should render a div with a confirm-detail-row class', () => {
assert.equal(wrapper.find('div.confirm-detail-row').length, 1)
})
@@ -60,5 +60,5 @@ describe('Confirm Detail Row Component', function () {
wrapper.find('.confirm-detail-row__header-text').props().onClick()
assert.equal(assert.equal(propsMethodSpies.onHeaderClick.callCount, 1))
})
- })
+ })
})
diff --git a/ui/app/components/app/confirm-page-container/confirm-page-container-navigation/confirm-page-container-navigation.component.js b/ui/app/components/app/confirm-page-container/confirm-page-container-navigation/confirm-page-container-navigation.component.js
index 8327f997b..c24d24b17 100755
--- a/ui/app/components/app/confirm-page-container/confirm-page-container-navigation/confirm-page-container-navigation.component.js
+++ b/ui/app/components/app/confirm-page-container/confirm-page-container-navigation/confirm-page-container-navigation.component.js
@@ -6,9 +6,9 @@ const ConfirmPageContainerNavigation = props => {
return (
<div className="confirm-page-container-navigation"
- style={{
- display: showNavigation ? 'flex' : 'none',
- }}
+ style={{
+ display: showNavigation ? 'flex' : 'none',
+ }}
>
<div className="confirm-page-container-navigation__container"
style={{
diff --git a/ui/app/components/app/confirm-page-container/confirm-page-container.component.js b/ui/app/components/app/confirm-page-container/confirm-page-container.component.js
index 326e4f83e..1ff797fa1 100644
--- a/ui/app/components/app/confirm-page-container/confirm-page-container.component.js
+++ b/ui/app/components/app/confirm-page-container/confirm-page-container.component.js
@@ -106,16 +106,16 @@ export default class ConfirmPageContainer extends Component {
return (
<div className="page-container">
<ConfirmPageContainerNavigation
- totalTx={totalTx}
- positionOfCurrentTx={positionOfCurrentTx}
- nextTxId={nextTxId}
- prevTxId={prevTxId}
- showNavigation={showNavigation}
- onNextTx={(txId) => onNextTx(txId)}
- firstTx={firstTx}
- lastTx={lastTx}
- ofText={ofText}
- requestsWaitingText={requestsWaitingText}
+ totalTx={totalTx}
+ positionOfCurrentTx={positionOfCurrentTx}
+ nextTxId={nextTxId}
+ prevTxId={prevTxId}
+ showNavigation={showNavigation}
+ onNextTx={(txId) => onNextTx(txId)}
+ firstTx={firstTx}
+ lastTx={lastTx}
+ ofText={ofText}
+ requestsWaitingText={requestsWaitingText}
/>
<ConfirmPageContainerHeader
showEdit={showEdit}
diff --git a/ui/app/components/app/contact-list/contact-list.component.js b/ui/app/components/app/contact-list/contact-list.component.js
new file mode 100644
index 000000000..ec9b5f8eb
--- /dev/null
+++ b/ui/app/components/app/contact-list/contact-list.component.js
@@ -0,0 +1,114 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+import RecipientGroup from './recipient-group/recipient-group.component'
+
+export default class ContactList extends PureComponent {
+ static propTypes = {
+ searchForContacts: PropTypes.func,
+ searchForRecents: PropTypes.func,
+ searchForMyAccounts: PropTypes.func,
+ selectRecipient: PropTypes.func,
+ children: PropTypes.node,
+ selectedAddress: PropTypes.string,
+ }
+
+ static contextTypes = {
+ t: PropTypes.func,
+ }
+
+ state = {
+ isShowingAllRecent: false,
+ }
+
+ renderRecents () {
+ const { t } = this.context
+ const { isShowingAllRecent } = this.state
+ const nonContacts = this.props.searchForRecents()
+
+ const showLoadMore = !isShowingAllRecent && nonContacts.length > 2
+
+ return (
+ <div className="send__select-recipient-wrapper__recent-group-wrapper">
+ <RecipientGroup
+ label={t('recents')}
+ items={showLoadMore ? nonContacts.slice(0, 2) : nonContacts}
+ onSelect={this.props.selectRecipient}
+ selectedAddress={this.props.selectedAddress}
+ />
+ {
+ showLoadMore && (
+ <div
+ className="send__select-recipient-wrapper__recent-group-wrapper__load-more"
+ onClick={() => this.setState({ isShowingAllRecent: true })}
+ >
+ {t('loadMore')}
+ </div>
+ )
+ }
+ </div>
+ )
+ }
+
+ renderAddressBook () {
+ const contacts = this.props.searchForContacts()
+
+ const contactGroups = contacts.reduce((acc, contact) => {
+ const firstLetter = contact.name.slice(0, 1).toUpperCase()
+ acc[firstLetter] = acc[firstLetter] || []
+ const bucket = acc[firstLetter]
+ bucket.push(contact)
+ return acc
+ }, {})
+
+ return Object
+ .entries(contactGroups)
+ .sort(([letter1], [letter2]) => {
+ if (letter1 > letter2) {
+ return 1
+ } else if (letter1 === letter2) {
+ return 0
+ } else if (letter1 < letter2) {
+ return -1
+ }
+ })
+ .map(([letter, groupItems]) => (
+ <RecipientGroup
+ key={`${letter}-contract-group`}
+ label={letter}
+ items={groupItems}
+ onSelect={this.props.selectRecipient}
+ selectedAddress={this.props.selectedAddress}
+ />
+ ))
+ }
+
+ renderMyAccounts () {
+ const myAccounts = this.props.searchForMyAccounts()
+
+ return (
+ <RecipientGroup
+ items={myAccounts}
+ onSelect={this.props.selectRecipient}
+ selectedAddress={this.props.selectedAddress}
+ />
+ )
+ }
+
+ render () {
+ const {
+ children,
+ searchForRecents,
+ searchForContacts,
+ searchForMyAccounts,
+ } = this.props
+
+ return (
+ <div className="send__select-recipient-wrapper__list">
+ { children || null }
+ { searchForRecents && this.renderRecents() }
+ { searchForContacts && this.renderAddressBook() }
+ { searchForMyAccounts && this.renderMyAccounts() }
+ </div>
+ )
+ }
+}
diff --git a/ui/app/components/app/contact-list/index.js b/ui/app/components/app/contact-list/index.js
new file mode 100644
index 000000000..d90c29b2b
--- /dev/null
+++ b/ui/app/components/app/contact-list/index.js
@@ -0,0 +1 @@
+export { default } from './contact-list.component'
diff --git a/ui/app/components/app/contact-list/recipient-group/index.js b/ui/app/components/app/contact-list/recipient-group/index.js
new file mode 100644
index 000000000..7d827523f
--- /dev/null
+++ b/ui/app/components/app/contact-list/recipient-group/index.js
@@ -0,0 +1 @@
+export { default } from './recipient-group.component'
diff --git a/ui/app/components/app/contact-list/recipient-group/recipient-group.component.js b/ui/app/components/app/contact-list/recipient-group/recipient-group.component.js
new file mode 100644
index 000000000..a2248326e
--- /dev/null
+++ b/ui/app/components/app/contact-list/recipient-group/recipient-group.component.js
@@ -0,0 +1,59 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+import Identicon from '../../../ui/identicon'
+import classnames from 'classnames'
+import { ellipsify } from '../../../../pages/send/send.utils'
+
+function addressesEqual (address1, address2) {
+ return String(address1).toLowerCase() === String(address2).toLowerCase()
+}
+
+export default function RecipientGroup ({ label, items, onSelect, selectedAddress }) {
+ if (!items || !items.length) {
+ return null
+ }
+
+ return (
+ <div className="send__select-recipient-wrapper__group">
+ {label && <div className="send__select-recipient-wrapper__group-label">
+ {label}
+ </div>}
+ {
+ items.map(({ address, name }) => (
+ <div
+ key={address}
+ onClick={() => onSelect(address, name)}
+ className={classnames({
+ 'send__select-recipient-wrapper__group-item': !addressesEqual(address, selectedAddress),
+ 'send__select-recipient-wrapper__group-item--selected': addressesEqual(address, selectedAddress),
+ })}
+ >
+ <Identicon address={address} diameter={28} />
+ <div className="send__select-recipient-wrapper__group-item__content">
+ <div className="send__select-recipient-wrapper__group-item__title">
+ {name || ellipsify(address)}
+ </div>
+ {
+ name && (
+ <div className="send__select-recipient-wrapper__group-item__subtitle">
+ {ellipsify(address)}
+ </div>
+ )
+ }
+ </div>
+ </div>
+ ))
+ }
+ </div>
+ )
+}
+
+RecipientGroup.propTypes = {
+ label: PropTypes.string,
+ items: PropTypes.arrayOf(PropTypes.shape({
+ address: PropTypes.string,
+ name: PropTypes.string,
+ })),
+ onSelect: PropTypes.func.isRequired,
+ selectedAddress: PropTypes.string,
+}
diff --git a/ui/app/components/app/dropdowns/account-details-dropdown.js b/ui/app/components/app/dropdowns/account-details-dropdown.js
index a4c33620a..cf2aa8ae8 100644
--- a/ui/app/components/app/dropdowns/account-details-dropdown.js
+++ b/ui/app/components/app/dropdowns/account-details-dropdown.js
@@ -59,7 +59,7 @@ AccountDetailsDropdown.prototype.render = function () {
viewOnEtherscan,
showRemoveAccountConfirmationModal,
rpcPrefs,
- } = this.props
+ } = this.props
const address = selectedIdentity.address
diff --git a/ui/app/components/app/dropdowns/network-dropdown.js b/ui/app/components/app/dropdowns/network-dropdown.js
index 378ad3ba6..e6a24ef11 100644
--- a/ui/app/components/app/dropdowns/network-dropdown.js
+++ b/ui/app/components/app/dropdowns/network-dropdown.js
@@ -32,9 +32,6 @@ function mapStateToProps (state) {
function mapDispatchToProps (dispatch) {
return {
- hideModal: () => {
- dispatch(actions.hideModal())
- },
setProviderType: (type) => {
dispatch(actions.setProviderType(type))
},
@@ -47,7 +44,6 @@ function mapDispatchToProps (dispatch) {
delRpcTarget: (target) => {
dispatch(actions.delRpcTarget(target))
},
- showNetworkDropdown: () => dispatch(actions.showNetworkDropdown()),
hideNetworkDropdown: () => dispatch(actions.hideNetworkDropdown()),
setNetworksTabAddMode: isInAddMode => dispatch(actions.setNetworksTabAddMode(isInAddMode)),
}
@@ -357,12 +353,12 @@ NetworkDropdown.prototype.renderCommonRpc = function (rpcListDetail, provider) {
},
}, nickname || rpc),
h('i.fa.fa-times.delete',
- {
- onClick: (e) => {
- e.stopPropagation()
- props.delRpcTarget(rpc)
- },
- }),
+ {
+ onClick: (e) => {
+ e.stopPropagation()
+ props.delRpcTarget(rpc)
+ },
+ }),
]
)
}
diff --git a/ui/app/components/app/ens-input.js b/ui/app/components/app/ens-input.js
deleted file mode 100644
index 5eea0dd90..000000000
--- a/ui/app/components/app/ens-input.js
+++ /dev/null
@@ -1,181 +0,0 @@
-const Component = require('react').Component
-const PropTypes = require('prop-types')
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const extend = require('xtend')
-const debounce = require('debounce')
-const copyToClipboard = require('copy-to-clipboard')
-const ENS = require('ethjs-ens')
-const networkMap = require('ethjs-ens/lib/network-map.json')
-const ensRE = /.+\..+$/
-const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
-const connect = require('react-redux').connect
-const ToAutoComplete = require('../../pages/send/to-autocomplete').default
-const log = require('loglevel')
-const { isValidENSAddress } = require('../../helpers/utils/util')
-
-EnsInput.contextTypes = {
- t: PropTypes.func,
-}
-
-module.exports = connect()(EnsInput)
-
-
-inherits(EnsInput, Component)
-function EnsInput () {
- Component.call(this)
-}
-
-EnsInput.prototype.onChange = function (recipient) {
-
- const network = this.props.network
- const networkHasEnsSupport = getNetworkEnsSupport(network)
-
- this.props.onChange({ toAddress: recipient })
-
- if (!networkHasEnsSupport) return
-
- if (recipient.match(ensRE) === null) {
- return this.setState({
- loadingEns: false,
- ensResolution: null,
- ensFailure: null,
- toError: null,
- })
- }
-
- this.setState({
- loadingEns: true,
- })
- this.checkName(recipient)
-}
-
-EnsInput.prototype.render = function () {
- const props = this.props
- const opts = extend(props, {
- list: 'addresses',
- onChange: this.onChange.bind(this),
- qrScanner: true,
- })
- return h('div', {
- style: { width: '100%', position: 'relative' },
- }, [
- h(ToAutoComplete, { ...opts }),
- this.ensIcon(),
- ])
-}
-
-EnsInput.prototype.componentDidMount = function () {
- const network = this.props.network
- const networkHasEnsSupport = getNetworkEnsSupport(network)
- this.setState({ ensResolution: ZERO_ADDRESS })
-
- if (networkHasEnsSupport) {
- const provider = global.ethereumProvider
- this.ens = new ENS({ provider, network })
- this.checkName = debounce(this.lookupEnsName.bind(this), 200)
- }
-}
-
-EnsInput.prototype.lookupEnsName = function (recipient) {
- const { ensResolution } = this.state
-
- log.info(`ENS attempting to resolve name: ${recipient}`)
- this.ens.lookup(recipient.trim())
- .then((address) => {
- if (address === ZERO_ADDRESS) throw new Error(this.context.t('noAddressForName'))
- if (address !== ensResolution) {
- this.setState({
- loadingEns: false,
- ensResolution: address,
- nickname: recipient.trim(),
- hoverText: address + '\n' + this.context.t('clickCopy'),
- ensFailure: false,
- toError: null,
- })
- }
- })
- .catch((reason) => {
- const setStateObj = {
- loadingEns: false,
- ensResolution: recipient,
- ensFailure: true,
- toError: null,
- }
- if (isValidENSAddress(recipient) && reason.message === 'ENS name not defined.') {
- setStateObj.hoverText = this.context.t('ensNameNotFound')
- setStateObj.toError = 'ensNameNotFound'
- setStateObj.ensFailure = false
- } else {
- log.error(reason)
- setStateObj.hoverText = reason.message
- }
-
- return this.setState(setStateObj)
- })
-}
-
-EnsInput.prototype.componentDidUpdate = function (prevProps, prevState) {
- const state = this.state || {}
- const ensResolution = state.ensResolution
- // If an address is sent without a nickname, meaning not from ENS or from
- // the user's own accounts, a default of a one-space string is used.
- const nickname = state.nickname || ' '
- if (prevProps.network !== this.props.network) {
- const provider = global.ethereumProvider
- this.ens = new ENS({ provider, network: this.props.network })
- this.onChange(ensResolution)
- }
- if (prevState && ensResolution && this.props.onChange &&
- ensResolution !== prevState.ensResolution) {
- this.props.onChange({ toAddress: ensResolution, nickname, toError: state.toError, toWarning: state.toWarning })
- }
-}
-
-EnsInput.prototype.ensIcon = function (recipient) {
- const { hoverText } = this.state || {}
- return h('span.#ensIcon', {
- title: hoverText,
- style: {
- position: 'absolute',
- top: '16px',
- left: '-25px',
- },
- }, this.ensIconContents(recipient))
-}
-
-EnsInput.prototype.ensIconContents = function () {
- const { loadingEns, ensFailure, ensResolution, toError } = this.state || { ensResolution: ZERO_ADDRESS }
-
- if (toError) return
-
- if (loadingEns) {
- return h('img', {
- src: 'images/loading.svg',
- style: {
- width: '30px',
- height: '30px',
- transform: 'translateY(-6px)',
- },
- })
- }
-
- if (ensFailure) {
- return h('i.fa.fa-warning.fa-lg.warning')
- }
-
- if (ensResolution && (ensResolution !== ZERO_ADDRESS)) {
- return h('i.fa.fa-check-circle.fa-lg.cursor-pointer', {
- style: { color: 'green' },
- onClick: (event) => {
- event.preventDefault()
- event.stopPropagation()
- copyToClipboard(ensResolution)
- },
- })
- }
-}
-
-function getNetworkEnsSupport (network) {
- return Boolean(networkMap[network])
-}
diff --git a/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.component.js b/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.component.js
index d942fd150..7b87b3033 100644
--- a/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.component.js
+++ b/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.component.js
@@ -131,8 +131,8 @@ export default class AdvancedTabContent extends Component {
</div>
{ isInError
? <div className={`advanced-gas-inputs__gas-edit-row__${errorType}-text`}>
- { errorText }
- </div>
+ { errorText }
+ </div>
: null }
</div>
)
diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js b/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js
index eab3434df..88d28b9ed 100644
--- a/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js
+++ b/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js
@@ -104,8 +104,8 @@ export default class AdvancedTabContent extends Component {
</div>
{ isInError
? <div className={`advanced-tab__gas-edit-row__${errorType}-text`}>
- { errorText }
- </div>
+ { errorText }
+ </div>
: null }
</div>
)
@@ -126,7 +126,7 @@ export default class AdvancedTabContent extends Component {
<div className="advanced-tab__transaction-data-summary__fee">
{transactionFee}
</div>
- <div className="time-remaining">{timeRemaining}</div>
+ <div className="advanced-tab__transaction-data-summary__time-remaining">{timeRemaining}</div>
</div>
</div>
)
diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/index.scss b/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/index.scss
index 20a503018..e35b6d594 100644
--- a/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/index.scss
+++ b/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/index.scss
@@ -1,5 +1,3 @@
-@import './time-remaining/index';
-
.advanced-tab {
display: flex;
flex-flow: column;
@@ -36,6 +34,24 @@
font-size: 16px;
color: #313A5E;
}
+
+ &__time-remaining {
+ color: #313A5E;
+ font-size: 16px;
+
+ .minutes-num, .seconds-num {
+ font-size: 16px;
+ }
+
+ .seconds-num {
+ margin-left: 7px;
+ font-size: 16px;
+ }
+
+ .minutes-label, .seconds-label {
+ font-size: 16px;
+ }
+ }
}
&__fee-chart {
@@ -94,7 +110,7 @@
display: flex;
justify-content: space-between;
align-items: center;
-
+
.fa-info-circle {
color: $silver;
margin-left: 10px;
@@ -204,4 +220,4 @@
color: $dusty-gray;
}
}
-} \ No newline at end of file
+}
diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/tests/advanced-tab-content-component.test.js b/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/tests/advanced-tab-content-component.test.js
index 5f7d90922..683eeda9b 100644
--- a/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/tests/advanced-tab-content-component.test.js
+++ b/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/tests/advanced-tab-content-component.test.js
@@ -124,7 +124,7 @@ describe('AdvancedTabContent Component', function () {
const dataNode = dataSummary.children().at(1)
assert(dataNode.hasClass('advanced-tab__transaction-data-summary__container'))
assert.equal(dataNode.children().at(0).text(), 'mockTotalFee')
- assert(dataNode.children().at(1).hasClass('time-remaining'))
+ assert(dataNode.children().at(1).hasClass('advanced-tab__transaction-data-summary__time-remaining'))
assert.equal(dataNode.children().at(1).text(), 'mockMsRemaining')
})
})
diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/index.js b/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/index.js
deleted file mode 100644
index 61b681e1a..000000000
--- a/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from './time-remaining.component'
diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/index.scss b/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/index.scss
deleted file mode 100644
index e2115af7f..000000000
--- a/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/index.scss
+++ /dev/null
@@ -1,17 +0,0 @@
-.time-remaining {
- color: #313A5E;
- font-size: 16px;
-
- .minutes-num, .seconds-num {
- font-size: 16px;
- }
-
- .seconds-num {
- margin-left: 7px;
- font-size: 16px;
- }
-
- .minutes-label, .seconds-label {
- font-size: 16px;
- }
-} \ No newline at end of file
diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/tests/time-remaining-component.test.js b/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/tests/time-remaining-component.test.js
deleted file mode 100644
index 17f0345d5..000000000
--- a/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/tests/time-remaining-component.test.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import React from 'react'
-import assert from 'assert'
-import shallow from '../../../../../../../../lib/shallow-with-context'
-import TimeRemaining from '../time-remaining.component.js'
-
-describe('TimeRemaining Component', function () {
- let wrapper
-
- beforeEach(() => {
- wrapper = shallow(<TimeRemaining
- milliseconds={495000}
- />)
- })
-
- describe('render()', () => {
- it('should render the time-remaining root node', () => {
- assert(wrapper.hasClass('time-remaining'))
- })
-
- it('should render minutes and seconds numbers and labels', () => {
- const timeRemainingChildren = wrapper.children()
- assert.equal(timeRemainingChildren.length, 4)
- assert.equal(timeRemainingChildren.at(0).text(), 8)
- assert.equal(timeRemainingChildren.at(1).text(), 'minutesShorthand')
- assert.equal(timeRemainingChildren.at(2).text(), 15)
- assert.equal(timeRemainingChildren.at(3).text(), 'secondsShorthand')
- })
- })
-
-})
diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/time-remaining.component.js b/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/time-remaining.component.js
deleted file mode 100644
index 826d41f9c..000000000
--- a/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/time-remaining.component.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import React, { Component } from 'react'
-import PropTypes from 'prop-types'
-import { getTimeBreakdown } from './time-remaining.utils'
-
-export default class TimeRemaining extends Component {
- static contextTypes = {
- t: PropTypes.func,
- }
-
- static propTypes = {
- milliseconds: PropTypes.number,
- }
-
- render () {
- const {
- milliseconds,
- } = this.props
-
- const {
- minutes,
- seconds,
- } = getTimeBreakdown(milliseconds)
-
- return (
- <div className="time-remaining">
- <span className="minutes-num">{minutes}</span>
- <span className="minutes-label">{this.context.t('minutesShorthand')}</span>
- <span className="seconds-num">{seconds}</span>
- <span className="seconds-label">{this.context.t('secondsShorthand')}</span>
- </div>
- )
- }
-}
diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/time-remaining.utils.js b/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/time-remaining.utils.js
deleted file mode 100644
index cf43e0acb..000000000
--- a/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/time-remaining.utils.js
+++ /dev/null
@@ -1,11 +0,0 @@
-function getTimeBreakdown (milliseconds) {
- return {
- hours: Math.floor(milliseconds / 3600000),
- minutes: Math.floor((milliseconds % 3600000) / 60000),
- seconds: Math.floor((milliseconds % 60000) / 1000),
- }
-}
-
-module.exports = {
- getTimeBreakdown,
-}
diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/basic-tab-content/basic-tab-content.component.js b/ui/app/components/app/gas-customization/gas-modal-page-container/basic-tab-content/basic-tab-content.component.js
index 5f3925fa5..931611460 100644
--- a/ui/app/components/app/gas-customization/gas-modal-page-container/basic-tab-content/basic-tab-content.component.js
+++ b/ui/app/components/app/gas-customization/gas-modal-page-container/basic-tab-content/basic-tab-content.component.js
@@ -21,12 +21,12 @@ export default class BasicTabContent extends Component {
<div className="basic-tab-content__title">{ t('estimatedProcessingTimes') }</div>
<div className="basic-tab-content__blurb">{ t('selectAHigherGasFee') }</div>
{!gasPriceButtonGroupProps.loading
- ? <GasPriceButtonGroup
- className="gas-price-button-group--alt"
- showCheck={true}
- {...gasPriceButtonGroupProps}
- />
- : <Loading />
+ ? <GasPriceButtonGroup
+ className="gas-price-button-group--alt"
+ showCheck={true}
+ {...gasPriceButtonGroupProps}
+ />
+ : <Loading />
}
<div className="basic-tab-content__footer-blurb">{ t('acceleratingATransaction') }</div>
</div>
diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js b/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js
index e18c1067e..5e557f660 100644
--- a/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js
+++ b/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js
@@ -47,7 +47,7 @@ export default class GasModalPageContainer extends Component {
const promise = this.props.hideBasic
? Promise.resolve(this.props.blockTime)
: this.props.fetchBasicGasAndTimeEstimates()
- .then(basicEstimates => basicEstimates.blockTime)
+ .then(basicEstimates => basicEstimates.blockTime)
promise
.then(blockTime => {
@@ -144,11 +144,11 @@ export default class GasModalPageContainer extends Component {
return (
<Tabs>
{tabsToRender.map(({ name, content }, i) => <Tab name={this.context.t(name)} key={`gas-modal-tab-${i}`}>
- <div className="gas-modal-content">
- { content }
- { this.renderInfoRows(newTotalFiat, newTotalEth, sendAmount, transactionFee) }
- </div>
- </Tab>
+ <div className="gas-modal-content">
+ { content }
+ { this.renderInfoRows(newTotalFiat, newTotalEth, sendAmount, transactionFee) }
+ </div>
+ </Tab>
)}
</Tabs>
)
diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js b/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js
index 03d254eee..d5f3837a9 100644
--- a/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js
+++ b/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js
@@ -341,44 +341,44 @@ describe('gas-modal-page-container container', () => {
})
describe('mergeProps', () => {
- let stateProps
- let dispatchProps
- let ownProps
-
- beforeEach(() => {
- stateProps = {
- gasPriceButtonGroupProps: {
- someGasPriceButtonGroupProp: 'foo',
- anotherGasPriceButtonGroupProp: 'bar',
- },
- isConfirm: true,
- someOtherStateProp: 'baz',
- transaction: {},
- }
- dispatchProps = {
- updateCustomGasPrice: sinon.spy(),
- hideGasButtonGroup: sinon.spy(),
- setGasData: sinon.spy(),
- updateConfirmTxGasAndCalculate: sinon.spy(),
- someOtherDispatchProp: sinon.spy(),
- createSpeedUpTransaction: sinon.spy(),
- hideSidebar: sinon.spy(),
- hideModal: sinon.spy(),
- cancelAndClose: sinon.spy(),
- }
- ownProps = { someOwnProp: 123 }
- })
+ let stateProps
+ let dispatchProps
+ let ownProps
- afterEach(() => {
- dispatchProps.updateCustomGasPrice.resetHistory()
- dispatchProps.hideGasButtonGroup.resetHistory()
- dispatchProps.setGasData.resetHistory()
- dispatchProps.updateConfirmTxGasAndCalculate.resetHistory()
- dispatchProps.someOtherDispatchProp.resetHistory()
- dispatchProps.createSpeedUpTransaction.resetHistory()
- dispatchProps.hideSidebar.resetHistory()
- dispatchProps.hideModal.resetHistory()
- })
+ beforeEach(() => {
+ stateProps = {
+ gasPriceButtonGroupProps: {
+ someGasPriceButtonGroupProp: 'foo',
+ anotherGasPriceButtonGroupProp: 'bar',
+ },
+ isConfirm: true,
+ someOtherStateProp: 'baz',
+ transaction: {},
+ }
+ dispatchProps = {
+ updateCustomGasPrice: sinon.spy(),
+ hideGasButtonGroup: sinon.spy(),
+ setGasData: sinon.spy(),
+ updateConfirmTxGasAndCalculate: sinon.spy(),
+ someOtherDispatchProp: sinon.spy(),
+ createSpeedUpTransaction: sinon.spy(),
+ hideSidebar: sinon.spy(),
+ hideModal: sinon.spy(),
+ cancelAndClose: sinon.spy(),
+ }
+ ownProps = { someOwnProp: 123 }
+ })
+
+ afterEach(() => {
+ dispatchProps.updateCustomGasPrice.resetHistory()
+ dispatchProps.hideGasButtonGroup.resetHistory()
+ dispatchProps.setGasData.resetHistory()
+ dispatchProps.updateConfirmTxGasAndCalculate.resetHistory()
+ dispatchProps.someOtherDispatchProp.resetHistory()
+ dispatchProps.createSpeedUpTransaction.resetHistory()
+ dispatchProps.hideSidebar.resetHistory()
+ dispatchProps.hideModal.resetHistory()
+ })
it('should return the expected props when isConfirm is true', () => {
const result = mergeProps(stateProps, dispatchProps, ownProps)
diff --git a/ui/app/components/app/gas-customization/gas-price-chart/gas-price-chart.utils.js b/ui/app/components/app/gas-customization/gas-price-chart/gas-price-chart.utils.js
index 55512ce09..b941f1cf9 100644
--- a/ui/app/components/app/gas-customization/gas-price-chart/gas-price-chart.utils.js
+++ b/ui/app/components/app/gas-customization/gas-price-chart/gas-price-chart.utils.js
@@ -210,17 +210,17 @@ export function generateChart (gasPrices, estimatedTimes, gasPricesMax, estimate
},
padding: {left: 20, right: 15, top: 6, bottom: 10},
data: {
- x: 'x',
- columns: [
- ['x', ...gasPrices],
- ['data1', ...estimatedTimes],
- ],
- types: {
- data1: 'area',
- },
- selection: {
- enabled: false,
- },
+ x: 'x',
+ columns: [
+ ['x', ...gasPrices],
+ ['data1', ...estimatedTimes],
+ ],
+ types: {
+ data1: 'area',
+ },
+ selection: {
+ enabled: false,
+ },
},
color: {
data1: '#259de5',
@@ -254,13 +254,13 @@ export function generateChart (gasPrices, estimatedTimes, gasPricesMax, estimate
},
},
legend: {
- show: false,
+ show: false,
},
grid: {
- x: {},
- lines: {
- front: false,
- },
+ x: {},
+ lines: {
+ front: false,
+ },
},
point: {
focus: {
@@ -296,8 +296,8 @@ export function generateChart (gasPrices, estimatedTimes, gasPricesMax, estimate
const flipTooltip = circleY - circleWidth < chartYStart + 5
d3
- .select('.tooltip-arrow')
- .style('margin-top', flipTooltip ? '-16px' : '4px')
+ .select('.tooltip-arrow')
+ .style('margin-top', flipTooltip ? '-16px' : '4px')
return {
top: bigNumMinus(circleY, chartYStart).minus(19).plus(flipTooltip ? circleWidth + 38 : 0).toNumber(),
diff --git a/ui/app/components/app/home-notification/home-notification.component.js b/ui/app/components/app/home-notification/home-notification.component.js
new file mode 100644
index 000000000..cc86ef6d8
--- /dev/null
+++ b/ui/app/components/app/home-notification/home-notification.component.js
@@ -0,0 +1,112 @@
+import React, { PureComponent } from 'react'
+import classnames from 'classnames'
+import {Tooltip as ReactTippy} from 'react-tippy'
+import PropTypes from 'prop-types'
+import Button from '../../ui/button'
+
+export default class HomeNotification extends PureComponent {
+ static contextTypes = {
+ metricsEvent: PropTypes.func,
+ }
+
+ static defaultProps = {
+ onAccept: null,
+ ignoreText: null,
+ onIgnore: null,
+ infoText: null,
+ }
+
+ static propTypes = {
+ acceptText: PropTypes.string.isRequired,
+ onAccept: PropTypes.func,
+ ignoreText: PropTypes.string,
+ onIgnore: PropTypes.func,
+ descriptionText: PropTypes.string.isRequired,
+ infoText: PropTypes.string,
+ classNames: PropTypes.array,
+ }
+
+ handleAccept = () => {
+ this.props.onAccept()
+ }
+
+ handleIgnore = () => {
+ this.props.onIgnore()
+ }
+
+ render () {
+ const { descriptionText, acceptText, onAccept, ignoreText, onIgnore, infoText, classNames = [] } = this.props
+
+ return (
+ <div className={classnames('home-notification', ...classNames)}>
+ <div className="home-notification__header">
+ <div className="home-notification__header-container">
+ <img
+ className="home-notification__icon"
+ alt=""
+ src="images/icons/connect.svg"
+ />
+ <div className="home-notification__text">
+ { descriptionText }
+ </div>
+ </div>
+ {
+ infoText ? (
+ <ReactTippy
+ style={{
+ display: 'flex',
+ }}
+ html={(
+ <p className="home-notification-tooltip__content">
+ {infoText}
+ </p>
+ )}
+ offset={-36}
+ distance={36}
+ animation="none"
+ position="top"
+ arrow
+ theme="info"
+ >
+ <img
+ alt=""
+ src="images/icons/info.svg"
+ />
+ </ReactTippy>
+ ) : (
+ null
+ )
+ }
+ </div>
+ <div className="home-notification__buttons">
+ {
+ (onAccept && acceptText) ? (
+ <Button
+ type="primary"
+ className="home-notification__accept-button"
+ onClick={this.handleAccept}
+ >
+ { acceptText }
+ </Button>
+ ) : (
+ null
+ )
+ }
+ {
+ (onIgnore && ignoreText) ? (
+ <Button
+ type="secondary"
+ className="home-notification__ignore-button"
+ onClick={this.handleIgnore}
+ >
+ { ignoreText }
+ </Button>
+ ) : (
+ null
+ )
+ }
+ </div>
+ </div>
+ )
+ }
+}
diff --git a/ui/app/components/app/home-notification/index.js b/ui/app/components/app/home-notification/index.js
new file mode 100644
index 000000000..918a35be2
--- /dev/null
+++ b/ui/app/components/app/home-notification/index.js
@@ -0,0 +1 @@
+export { default } from './home-notification.component'
diff --git a/ui/app/components/app/home-notification/index.scss b/ui/app/components/app/home-notification/index.scss
new file mode 100644
index 000000000..c855a0814
--- /dev/null
+++ b/ui/app/components/app/home-notification/index.scss
@@ -0,0 +1,118 @@
+.tippy-tooltip.info-theme {
+ background: rgba(36, 41, 46, 0.9);
+ color: $white;
+ border-radius: 8px;
+}
+
+.home-notification {
+ background: rgba(36, 41, 46, 0.9);
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.12);
+ border-radius: 8px;
+ height: 116px;
+ padding: 16px;
+
+ @media screen and (min-width: 576px) {
+ min-width: 472px;
+ }
+
+ display: flex;
+ flex-flow: column;
+ justify-content: space-between;
+
+ &__header-container {
+ display: flex;
+ }
+
+ &__header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ }
+
+ &__text {
+ font-family: Roboto, 'sans-serif';
+ font-style: normal;
+ font-weight: normal;
+ font-size: 12px;
+ color: $white;
+ margin-left: 10px;
+ margin-right: 8px;
+ }
+
+ .fa-info-circle {
+ color: #6A737D;
+ }
+
+ &__ignore-button {
+ border: 2px solid #6A737D;
+ box-sizing: border-box;
+ border-radius: 6px;
+ color: $white;
+ background-color: inherit;
+ height: 34px;
+ width: 155px;
+ padding: 0;
+
+ @media screen and (max-width: 575px) {
+ width: 135px;
+ }
+
+ &:hover {
+ border-color: #6A737D;
+ background-color: #6A737D;
+ }
+
+ &:active {
+ background-color: #141618;
+ }
+ }
+
+ &__accept-button {
+ border: 2px solid #6A737D;
+ box-sizing: border-box;
+ border-radius: 6px;
+ color: $white;
+ background-color: inherit;
+ height: 34px;
+ width: 155px;
+ padding: 0;
+ margin-left: 4px;
+
+ @media screen and (max-width: 575px) {
+ width: 135px;
+ }
+
+ &:hover {
+ border-color: #6A737D;
+ background-color: #6A737D;
+ }
+
+ &:active {
+ background-color: #141618;
+ }
+ }
+
+ &__buttons {
+ display: flex;
+ width: 100%;
+ justify-content: flex-start;
+ flex-direction: row-reverse;
+ }
+}
+
+.home-notification-tooltip {
+ &__tooltip-container {
+ display: flex;
+ }
+
+ &__content {
+ font-family: Roboto, 'sans-serif';
+ font-style: normal;
+ font-weight: normal;
+ font-size: 12px;
+ color: $white;
+ text-align: left;
+ display: inline-block;
+ width: 200px;
+ }
+}
diff --git a/ui/app/components/app/index.scss b/ui/app/components/app/index.scss
index e9bb4ac9f..1ccb6a94a 100644
--- a/ui/app/components/app/index.scss
+++ b/ui/app/components/app/index.scss
@@ -1,3 +1,5 @@
+@import 'account-details/index';
+
@import 'account-menu/index';
@import 'add-token-button/index';
@@ -78,4 +80,8 @@
@import 'gas-customization/gas-price-button-group/index';
-@import 'ui-migration-annoucement/index';
+@import '../ui/toggle-button/index';
+
+@import 'home-notification/index';
+
+@import 'multiple-notifications/index';
diff --git a/ui/app/components/app/menu-droppo.js b/ui/app/components/app/menu-droppo.js
index c80bee2be..a88cad4b4 100644
--- a/ui/app/components/app/menu-droppo.js
+++ b/ui/app/components/app/menu-droppo.js
@@ -2,7 +2,7 @@ const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const findDOMNode = require('react-dom').findDOMNode
-const ReactCSSTransitionGroup = require('react-addons-css-transition-group')
+const ReactCSSTransitionGroup = require('react-transition-group/CSSTransitionGroup')
module.exports = MenuDroppoComponent
diff --git a/ui/app/components/app/modals/account-details-modal/account-details-modal.component.js b/ui/app/components/app/modals/account-details-modal/account-details-modal.component.js
index e3919edcf..1b9a6a718 100644
--- a/ui/app/components/app/modals/account-details-modal/account-details-modal.component.js
+++ b/ui/app/components/app/modals/account-details-modal/account-details-modal.component.js
@@ -72,14 +72,14 @@ export default class AccountDetailsModal extends Component {
</Button>
{exportPrivateKeyFeatureEnabled
- ? <Button
- type="secondary"
- className="account-modal__button"
- onClick={() => showExportPrivateKeyModal()}
- >
- {this.context.t('exportPrivateKey')}
- </Button>
- : null
+ ? <Button
+ type="secondary"
+ className="account-modal__button"
+ onClick={() => showExportPrivateKeyModal()}
+ >
+ {this.context.t('exportPrivateKey')}
+ </Button>
+ : null
}
</AccountModalContainer>
)
diff --git a/ui/app/components/app/modals/add-to-addressbook-modal/add-to-addressbook-modal.component.js b/ui/app/components/app/modals/add-to-addressbook-modal/add-to-addressbook-modal.component.js
new file mode 100644
index 000000000..64161a632
--- /dev/null
+++ b/ui/app/components/app/modals/add-to-addressbook-modal/add-to-addressbook-modal.component.js
@@ -0,0 +1,79 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import Button from '../../../ui/button/button.component'
+
+export default class AddToAddressBookModal extends Component {
+
+ static contextTypes = {
+ t: PropTypes.func,
+ }
+
+ static propTypes = {
+ hideModal: PropTypes.func.isRequired,
+ addToAddressBook: PropTypes.func.isRequired,
+ recipient: PropTypes.string.isRequired,
+ }
+
+ state = {
+ alias: '',
+ }
+
+ onSave = () => {
+ const { recipient, addToAddressBook, hideModal } = this.props
+ addToAddressBook(recipient, this.state.alias)
+ hideModal()
+ }
+
+ onChange = e => {
+ this.setState({
+ alias: e.target.value,
+ })
+ }
+
+ onKeyPress = e => {
+ if (e.key === 'Enter' && this.state.alias) {
+ this.onSave()
+ }
+ }
+
+ render () {
+ const { t } = this.context
+
+ return (
+ <div className="add-to-address-book-modal">
+ <div className="add-to-address-book-modal__content">
+ <div className="add-to-address-book-modal__content__header">
+ {t('addToAddressBook')}
+ </div>
+ <div className="add-to-address-book-modal__input-label">
+ {t('enterAnAlias')}
+ </div>
+ <input
+ type="text"
+ className="add-to-address-book-modal__input"
+ placeholder={t('addToAddressBookModalPlaceholder')}
+ onChange={this.onChange}
+ onKeyPress={this.onKeyPress}
+ value={this.state.alias}
+ autoFocus
+ />
+ </div>
+ <div className="add-to-address-book-modal__footer">
+ <Button
+ type="secondary"
+ onClick={this.props.hideModal}
+ >
+ {t('cancel')}
+ </Button>
+ <Button
+ type="primary"
+ onClick={this.onSave}
+ disabled={!this.state.alias}
+ >
+ {t('save')}
+ </Button>
+ </div>
+ </div>
+ )
+ }
+}
diff --git a/ui/app/components/app/modals/add-to-addressbook-modal/add-to-addressbook-modal.container.js b/ui/app/components/app/modals/add-to-addressbook-modal/add-to-addressbook-modal.container.js
new file mode 100644
index 000000000..413d4aa4a
--- /dev/null
+++ b/ui/app/components/app/modals/add-to-addressbook-modal/add-to-addressbook-modal.container.js
@@ -0,0 +1,18 @@
+import { connect } from 'react-redux'
+import AddToAddressBookModal from './add-to-addressbook-modal.component'
+import actions from '../../../../store/actions'
+
+function mapStateToProps (state) {
+ return {
+ ...state.appState.modal.modalState.props || {},
+ }
+}
+
+function mapDispatchToProps (dispatch) {
+ return {
+ hideModal: () => dispatch(actions.hideModal()),
+ addToAddressBook: (recipient, nickname) => dispatch(actions.addToAddressBook(recipient, nickname)),
+ }
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(AddToAddressBookModal)
diff --git a/ui/app/components/app/modals/add-to-addressbook-modal/index.js b/ui/app/components/app/modals/add-to-addressbook-modal/index.js
new file mode 100644
index 000000000..9ed4f018f
--- /dev/null
+++ b/ui/app/components/app/modals/add-to-addressbook-modal/index.js
@@ -0,0 +1 @@
+export { default } from './add-to-addressbook-modal.container'
diff --git a/ui/app/components/app/modals/add-to-addressbook-modal/index.scss b/ui/app/components/app/modals/add-to-addressbook-modal/index.scss
new file mode 100644
index 000000000..f6bf85a0a
--- /dev/null
+++ b/ui/app/components/app/modals/add-to-addressbook-modal/index.scss
@@ -0,0 +1,37 @@
+.add-to-address-book-modal {
+ @extend %col-nowrap;
+ @extend %modal;
+
+ &__content {
+ @extend %col-nowrap;
+ padding: 1.5rem;
+ border-bottom: 1px solid $Grey-100;
+
+ &__header {
+ @extend %h3;
+ }
+ }
+
+ &__input-label {
+ color: $Grey-600;
+ margin-top: 1.25rem;
+ }
+
+ &__input {
+ @extend %input;
+ margin-top: 0.75rem;
+
+ &::placeholder {
+ color: $Grey-300;
+ }
+ }
+
+ &__footer {
+ @extend %row-nowrap;
+ padding: 1rem;
+
+ button + button {
+ margin-left: 1rem;
+ }
+ }
+}
diff --git a/ui/app/components/app/modals/confirm-delete-network/confirm-delete-network.component.js b/ui/app/components/app/modals/confirm-delete-network/confirm-delete-network.component.js
new file mode 100644
index 000000000..ea92e340c
--- /dev/null
+++ b/ui/app/components/app/modals/confirm-delete-network/confirm-delete-network.component.js
@@ -0,0 +1,43 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+import Modal, { ModalContent } from '../../modal'
+
+export default class ConfirmDeleteNetwork extends PureComponent {
+ static propTypes = {
+ hideModal: PropTypes.func.isRequired,
+ delRpcTarget: PropTypes.func.isRequired,
+ onConfirm: PropTypes.func.isRequired,
+ target: PropTypes.string.isRequired,
+ }
+
+ static contextTypes = {
+ t: PropTypes.func,
+ }
+
+ handleDelete = () => {
+ this.props.delRpcTarget(this.props.target)
+ .then(() => {
+ this.props.onConfirm()
+ this.props.hideModal()
+ })
+ }
+
+ render () {
+ const { t } = this.context
+
+ return (
+ <Modal
+ onSubmit={this.handleDelete}
+ onCancel={() => this.props.hideModal()}
+ submitText={t('delete')}
+ cancelText={t('cancel')}
+ submitType="danger"
+ >
+ <ModalContent
+ title={t('deleteNetwork')}
+ description={t('deleteNetworkDescription')}
+ />
+ </Modal>
+ )
+ }
+}
diff --git a/ui/app/components/app/modals/confirm-delete-network/confirm-delete-network.container.js b/ui/app/components/app/modals/confirm-delete-network/confirm-delete-network.container.js
new file mode 100644
index 000000000..4c9bb279f
--- /dev/null
+++ b/ui/app/components/app/modals/confirm-delete-network/confirm-delete-network.container.js
@@ -0,0 +1,16 @@
+import { connect } from 'react-redux'
+import { compose } from 'recompose'
+import withModalProps from '../../../../helpers/higher-order-components/with-modal-props'
+import ConfirmDeleteNetwork from './confirm-delete-network.component'
+import { delRpcTarget } from '../../../../store/actions'
+
+const mapDispatchToProps = dispatch => {
+ return {
+ delRpcTarget: (target) => dispatch(delRpcTarget(target)),
+ }
+}
+
+export default compose(
+ withModalProps,
+ connect(null, mapDispatchToProps)
+)(ConfirmDeleteNetwork)
diff --git a/ui/app/components/app/modals/confirm-delete-network/index.js b/ui/app/components/app/modals/confirm-delete-network/index.js
new file mode 100644
index 000000000..de9543eea
--- /dev/null
+++ b/ui/app/components/app/modals/confirm-delete-network/index.js
@@ -0,0 +1 @@
+export { default } from './confirm-delete-network.container'
diff --git a/ui/app/components/app/modals/deposit-ether-modal.js b/ui/app/components/app/modals/deposit-ether-modal.js
index 20c4d018c..ff2411209 100644
--- a/ui/app/components/app/modals/deposit-ether-modal.js
+++ b/ui/app/components/app/modals/deposit-ether-modal.js
@@ -87,8 +87,8 @@ DepositEtherModal.prototype.renderRow = function ({
}
return h('div', {
- className: className || 'deposit-ether-modal__buy-row',
- }, [
+ className: className || 'deposit-ether-modal__buy-row',
+ }, [
onBackClick && showBackButton && h('div.deposit-ether-modal__buy-row__back', {
onClick: onBackClick,
@@ -100,22 +100,22 @@ DepositEtherModal.prototype.renderRow = function ({
h('div.deposit-ether-modal__buy-row__logo-container', [logo]),
- h('div.deposit-ether-modal__buy-row__description', [
+ h('div.deposit-ether-modal__buy-row__description', [
- !hideTitle && h('div.deposit-ether-modal__buy-row__description__title', [title]),
+ !hideTitle && h('div.deposit-ether-modal__buy-row__description__title', [title]),
- h('div.deposit-ether-modal__buy-row__description__text', [text]),
+ h('div.deposit-ether-modal__buy-row__description__text', [text]),
- ]),
+ ]),
- !hideButton && h('div.deposit-ether-modal__buy-row__button', [
- h(Button, {
- type: 'secondary',
- className: 'deposit-ether-modal__deposit-button',
- large: true,
- onClick: onButtonClick,
- }, [buttonLabel]),
- ]),
+ !hideButton && h('div.deposit-ether-modal__buy-row__button', [
+ h(Button, {
+ type: 'secondary',
+ className: 'deposit-ether-modal__deposit-button',
+ large: true,
+ onClick: onButtonClick,
+ }, [buttonLabel]),
+ ]),
])
}
diff --git a/ui/app/components/app/modals/export-private-key-modal.js b/ui/app/components/app/modals/export-private-key-modal.js
index c3098a16c..43d7bcd74 100644
--- a/ui/app/components/app/modals/export-private-key-modal.js
+++ b/ui/app/components/app/modals/export-private-key-modal.js
@@ -86,12 +86,12 @@ ExportPrivateKeyModal.prototype.renderPasswordInput = function (privateKey) {
return privateKey
? h(ReadOnlyInput, {
- wrapperClass: 'private-key-password-display-wrapper',
- inputClass: 'private-key-password-display-textarea',
- textarea: true,
- value: plainKey,
- onClick: () => copyToClipboard(plainKey),
- })
+ wrapperClass: 'private-key-password-display-wrapper',
+ inputClass: 'private-key-password-display-textarea',
+ textarea: true,
+ value: plainKey,
+ onClick: () => copyToClipboard(plainKey),
+ })
: h('input.private-key-password-input', {
type: 'password',
onChange: event => this.setState({ password: event.target.value }),
@@ -109,14 +109,14 @@ ExportPrivateKeyModal.prototype.renderButtons = function (privateKey, address, h
(privateKey
? (
- h(Button, {
+ h(Button, {
type: 'secondary',
large: true,
className: 'export-private-key__button',
onClick: () => hideModal(),
}, this.context.t('done'))
) : (
- h(Button, {
+ h(Button, {
type: 'secondary',
large: true,
className: 'export-private-key__button',
@@ -149,29 +149,29 @@ ExportPrivateKeyModal.prototype.render = function () {
backButtonAction: () => showAccountDetailModal(),
}, [
- h('span.account-name', name),
+ h('span.account-name', name),
- h(ReadOnlyInput, {
- wrapperClass: 'ellip-address-wrapper',
- inputClass: 'qr-ellip-address ellip-address',
- value: checksumAddress(address),
- }),
+ h(ReadOnlyInput, {
+ wrapperClass: 'ellip-address-wrapper',
+ inputClass: 'qr-ellip-address ellip-address',
+ value: checksumAddress(address),
+ }),
- h('div.account-modal-divider'),
+ h('div.account-modal-divider'),
- h('span.modal-body-title', this.context.t('showPrivateKeys')),
+ h('span.modal-body-title', this.context.t('showPrivateKeys')),
- h('div.private-key-password', {}, [
- this.renderPasswordLabel(privateKey),
+ h('div.private-key-password', {}, [
+ this.renderPasswordLabel(privateKey),
- this.renderPasswordInput(privateKey),
+ this.renderPasswordInput(privateKey),
- showWarning && warning ? h('span.private-key-password-error', warning) : null,
- ]),
+ showWarning && warning ? h('span.private-key-password-error', warning) : null,
+ ]),
- h('div.private-key-password-warning', this.context.t('privateKeyWarning')),
+ h('div.private-key-password-warning', this.context.t('privateKeyWarning')),
- this.renderButtons(privateKey, address, hideModal),
+ this.renderButtons(privateKey, address, hideModal),
])
}
diff --git a/ui/app/components/app/modals/index.scss b/ui/app/components/app/modals/index.scss
index 09b0bb73c..1bbfd2d07 100644
--- a/ui/app/components/app/modals/index.scss
+++ b/ui/app/components/app/modals/index.scss
@@ -9,3 +9,5 @@
@import 'transaction-confirmed/index';
@import 'metametrics-opt-in-modal/index';
+
+@import './add-to-addressbook-modal/index';
diff --git a/ui/app/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.component.js b/ui/app/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.component.js
index 0335991fc..1bf7c21b5 100644
--- a/ui/app/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.component.js
+++ b/ui/app/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.component.js
@@ -1,5 +1,6 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
+import MetaFoxLogo from '../../../ui/metafox-logo'
import PageContainerFooter from '../../../ui/page-container/page-container-footer'
export default class MetaMetricsOptInModal extends Component {
@@ -20,19 +21,7 @@ export default class MetaMetricsOptInModal extends Component {
<div className="metametrics-opt-in metametrics-opt-in-modal">
<div className="metametrics-opt-in__main">
<div className="metametrics-opt-in__content">
- <div className="app-header__logo-container">
- <img
- className="app-header__metafox-logo app-header__metafox-logo--horizontal"
- src="/images/logo/metamask-logo-horizontal.svg"
- height={30}
- />
- <img
- className="app-header__metafox-logo app-header__metafox-logo--icon"
- src="/images/logo/metamask-fox.svg"
- height={42}
- width={42}
- />
- </div>
+ <MetaFoxLogo />
<div className="metametrics-opt-in__body-graphic">
<img src="images/metrics-chart.svg" />
</div>
diff --git a/ui/app/components/app/modals/modal.js b/ui/app/components/app/modals/modal.js
index 394367c46..4044ded8c 100644
--- a/ui/app/components/app/modals/modal.js
+++ b/ui/app/components/app/modals/modal.js
@@ -29,6 +29,8 @@ import MetaMetricsOptInModal from './metametrics-opt-in-modal'
import RejectTransactions from './reject-transactions'
import ClearApprovedOrigins from './clear-approved-origins'
import ConfirmCustomizeGasModal from '../gas-customization/gas-modal-page-container'
+import ConfirmDeleteNetwork from './confirm-delete-network'
+import AddToAddressBookModal from './add-to-addressbook-modal'
const modalContainerBaseStyle = {
transform: 'translate3d(-50%, 0, 0px)',
@@ -166,6 +168,35 @@ const MODALS = {
},
},
+ ADD_TO_ADDRESSBOOK: {
+ contents: [
+ h(AddToAddressBookModal, {}, []),
+ ],
+ mobileModalStyle: {
+ width: '95%',
+ top: '10%',
+ boxShadow: 'rgba(0, 0, 0, 0.15) 0px 2px 2px 2px',
+ transform: 'none',
+ left: '0',
+ right: '0',
+ margin: '0 auto',
+ borderRadius: '10px',
+ },
+ laptopModalStyle: {
+ width: '375px',
+ top: '10%',
+ boxShadow: 'rgba(0, 0, 0, 0.15) 0px 2px 2px 2px',
+ transform: 'none',
+ left: '0',
+ right: '0',
+ margin: '0 auto',
+ borderRadius: '10px',
+ },
+ contentStyle: {
+ borderRadius: '10px',
+ },
+ },
+
ACCOUNT_DETAILS: {
contents: [
h(AccountDetailsModal, {}, []),
@@ -301,6 +332,19 @@ const MODALS = {
},
},
+ CONFIRM_DELETE_NETWORK: {
+ contents: h(ConfirmDeleteNetwork),
+ mobileModalStyle: {
+ ...modalContainerMobileStyle,
+ },
+ laptopModalStyle: {
+ ...modalContainerLaptopStyle,
+ },
+ contentStyle: {
+ borderRadius: '8px',
+ },
+ },
+
NEW_ACCOUNT: {
contents: [
h(NewAccountModal, {}, []),
@@ -452,7 +496,6 @@ module.exports = connect(mapStateToProps, mapDispatchToProps)(Modal)
Modal.prototype.render = function () {
const modal = MODALS[this.props.modalState.name || 'DEFAULT']
-
const { contents: children, disableBackdropClick = false } = modal
const modalStyle = modal[isMobileView() ? 'mobileModalStyle' : 'laptopModalStyle']
const contentStyle = modal.contentStyle || {}
diff --git a/ui/app/components/app/modals/new-account-modal.js b/ui/app/components/app/modals/new-account-modal.js
index 27c81a701..4b18c52ba 100644
--- a/ui/app/components/app/modals/new-account-modal.js
+++ b/ui/app/components/app/modals/new-account-modal.js
@@ -69,7 +69,7 @@ NewAccountModal.propTypes = {
showImportPage: PropTypes.func,
createAccount: PropTypes.func,
numberOfExistingAccounts: PropTypes.number,
- t: PropTypes.func,
+ t: PropTypes.func,
}
const mapStateToProps = state => {
diff --git a/ui/app/components/app/modals/notification-modal.js b/ui/app/components/app/modals/notification-modal.js
index b8503ec1a..84d9004b7 100644
--- a/ui/app/components/app/modals/notification-modal.js
+++ b/ui/app/components/app/modals/notification-modal.js
@@ -62,7 +62,7 @@ NotificationModal.propTypes = {
showCancelButton: PropTypes.bool,
showConfirmButton: PropTypes.bool,
onConfirm: PropTypes.func,
- t: PropTypes.func,
+ t: PropTypes.func,
}
const mapDispatchToProps = dispatch => {
diff --git a/ui/app/components/app/modals/qr-scanner/qr-scanner.component.js b/ui/app/components/app/modals/qr-scanner/qr-scanner.component.js
index a83ba8f8e..afeaef0da 100644
--- a/ui/app/components/app/modals/qr-scanner/qr-scanner.component.js
+++ b/ui/app/components/app/modals/qr-scanner/qr-scanner.component.js
@@ -1,7 +1,7 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { BrowserQRCodeReader } from '@zxing/library'
-import adapter from 'webrtc-adapter' // eslint-disable-line import/no-nodejs-modules, no-unused-vars
+import 'webrtc-adapter'
import Spinner from '../../../ui/spinner'
import WebcamUtils from '../../../../../lib/webcam-utils'
import PageContainerFooter from '../../../ui/page-container/page-container-footer/page-container-footer.component'
@@ -75,23 +75,23 @@ export default class QrScanner extends Component {
clearTimeout(this.permissionChecker)
this.checkPermisisions()
this.codeReader.decodeFromInputVideoDevice(undefined, 'video')
- .then(content => {
- const result = this.parseContent(content.text)
- if (result.type !== 'unknown') {
- this.props.qrCodeDetected(result)
- this.stopAndClose()
- } else {
- this.setState({msg: this.context.t('unknownQrCode')})
- }
- })
- .catch(err => {
- if (err && err.name === 'NotAllowedError') {
- this.setState({msg: this.context.t('youNeedToAllowCameraAccess')})
- clearTimeout(this.permissionChecker)
- this.needsToReinit = true
- this.checkPermisisions()
- }
- })
+ .then(content => {
+ const result = this.parseContent(content.text)
+ if (result.type !== 'unknown') {
+ this.props.qrCodeDetected(result)
+ this.stopAndClose()
+ } else {
+ this.setState({msg: this.context.t('unknownQrCode')})
+ }
+ })
+ .catch(err => {
+ if (err && err.name === 'NotAllowedError') {
+ this.setState({msg: this.context.t('youNeedToAllowCameraAccess')})
+ clearTimeout(this.permissionChecker)
+ this.needsToReinit = true
+ this.checkPermisisions()
+ }
+ })
}).catch(err => {
console.error('[QR-SCANNER]: getVideoInputDevices threw an exception: ', err)
})
diff --git a/ui/app/components/app/multiple-notifications/index.js b/ui/app/components/app/multiple-notifications/index.js
new file mode 100644
index 000000000..a27a65187
--- /dev/null
+++ b/ui/app/components/app/multiple-notifications/index.js
@@ -0,0 +1 @@
+export { default } from './multiple-notifications.component'
diff --git a/ui/app/components/app/multiple-notifications/index.scss b/ui/app/components/app/multiple-notifications/index.scss
new file mode 100644
index 000000000..e8d064bc0
--- /dev/null
+++ b/ui/app/components/app/multiple-notifications/index.scss
@@ -0,0 +1,78 @@
+.home-notification-wrapper--show-all,
+.home-notification-wrapper--show-first {
+ display: flex;
+ flex-direction: column;
+ width: 472px;
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ margin: 8px;
+
+ @media screen and (max-width: 576px) {
+ width: 340px;
+ }
+
+ .home-notification-wrapper__i-container {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ visibility: none;
+
+ .fa-sm {
+ display: initial;
+ position: absolute;
+ bottom: 14px;
+ left: 16px;
+ color: white;
+ cursor: pointer;
+ visibility: visible;
+
+ &:hover {
+ color: #b0d7f2;
+ font-size: 1.1rem;
+ }
+ }
+ }
+}
+
+.home-notification-wrapper--show-all {
+ justify-content: flex-end;
+ margin-bottom: 0;
+
+ .home-notification-wrapper__i-container {
+ height: 0;
+ }
+
+ > div {
+ position: relative;
+ margin-top: 8px;
+ }
+
+ .fa-sm {
+ margin-bottom: 8px;
+ }
+
+}
+
+.home-notification-wrapper--show-first {
+ > div {
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ visibility: hidden;
+ }
+
+ > div:first-of-type {
+ visibility: visible;
+
+ }
+
+ .fa-sm {
+ position: relative;
+ display: initial;
+ }
+}
+
+.flipped {
+ transform: rotate(180deg);
+}
diff --git a/ui/app/components/app/multiple-notifications/multiple-notifications.component.js b/ui/app/components/app/multiple-notifications/multiple-notifications.component.js
new file mode 100644
index 000000000..040890e18
--- /dev/null
+++ b/ui/app/components/app/multiple-notifications/multiple-notifications.component.js
@@ -0,0 +1,44 @@
+import React, { PureComponent } from 'react'
+import classnames from 'classnames'
+import PropTypes from 'prop-types'
+
+export default class MultipleNotifications extends PureComponent {
+ static propTypes = {
+ notifications: PropTypes.array,
+ classNames: PropTypes.array,
+ }
+
+ state = {
+ showAll: false,
+ }
+
+ render () {
+ const { showAll } = this.state
+ const { notifications, classNames = [] } = this.props
+
+ const notificationsToBeRendered = notifications.filter(notificationConfig => notificationConfig.shouldBeRendered)
+
+ if (notificationsToBeRendered.length === 0) {
+ return null
+ }
+
+ return (
+ <div
+ className={classnames(...classNames, {
+ 'home-notification-wrapper--show-all': showAll,
+ 'home-notification-wrapper--show-first': !showAll,
+ })}
+ >
+ { notificationsToBeRendered.map(notificationConfig => notificationConfig.component) }
+ <div
+ className="home-notification-wrapper__i-container"
+ onClick={() => this.setState({ showAll: !showAll })}
+ >
+ {notificationsToBeRendered.length > 1 ? <i className={classnames('fa fa-sm fa-sort-amount-asc', {
+ 'flipped': !showAll,
+ })} /> : null}
+ </div>
+ </div>
+ )
+ }
+}
diff --git a/ui/app/components/app/network-display/network-display.component.js b/ui/app/components/app/network-display/network-display.component.js
index 9ef5341b0..266476267 100644
--- a/ui/app/components/app/network-display/network-display.component.js
+++ b/ui/app/components/app/network-display/network-display.component.js
@@ -39,12 +39,12 @@ export default class NetworkDisplay extends Component {
return networkClass
? <div className={`network-display__icon network-display__icon--${networkClass}`} />
: <div
- className="i fa fa-question-circle fa-med"
- style={{
- margin: '0 4px',
- color: 'rgb(125, 128, 130)',
- }}
- />
+ className="i fa fa-question-circle fa-med"
+ style={{
+ margin: '0 4px',
+ color: 'rgb(125, 128, 130)',
+ }}
+ />
}
render () {
@@ -62,12 +62,12 @@ export default class NetworkDisplay extends Component {
networkClass
? <div className={`network-display__icon network-display__icon--${networkClass}`} />
: <div
- className="i fa fa-question-circle fa-med"
- style={{
- margin: '0 4px',
- color: 'rgb(125, 128, 130)',
- }}
- />
+ className="i fa fa-question-circle fa-med"
+ style={{
+ margin: '0 4px',
+ color: 'rgb(125, 128, 130)',
+ }}
+ />
}
<div className="network-display__name">
{ type === 'rpc' && nickname ? nickname : this.context.t(type) }
diff --git a/ui/app/components/app/network.js b/ui/app/components/app/network.js
index e778700cd..d46906a66 100644
--- a/ui/app/components/app/network.js
+++ b/ui/app/components/app/network.js
@@ -127,19 +127,19 @@ Network.prototype.render = function () {
default:
return h('.network-indicator', [
networkNumber === 'loading'
- ? h('span.pointer.network-loading-spinner', {
- onClick: (event) => this.props.onClick(event),
- }, [
- h('img', {
- title: context.t('attemptingConnect'),
- src: 'images/loading.svg',
+ ? h('span.pointer.network-loading-spinner', {
+ onClick: (event) => this.props.onClick(event),
+ }, [
+ h('img', {
+ title: context.t('attemptingConnect'),
+ src: 'images/loading.svg',
+ }),
+ ])
+ : h('i.fa.fa-question-circle.fa-lg', {
+ style: {
+ color: 'rgb(125, 128, 130)',
+ },
}),
- ])
- : h('i.fa.fa-question-circle.fa-lg', {
- style: {
- color: 'rgb(125, 128, 130)',
- },
- }),
h('.network-name', providerName === 'localhost' ? context.t('localhost') : providerNick || context.t('privateNetwork')),
h('.network-indicator__down-arrow'),
diff --git a/ui/app/components/app/provider-page-container/provider-page-container-content/provider-page-container-content.component.js b/ui/app/components/app/provider-page-container/provider-page-container-content/provider-page-container-content.component.js
index 0eb1d616a..7eda7f2b7 100644
--- a/ui/app/components/app/provider-page-container/provider-page-container-content/provider-page-container-content.component.js
+++ b/ui/app/components/app/provider-page-container/provider-page-container-content/provider-page-container-content.component.js
@@ -5,7 +5,7 @@ import Identicon from '../../../ui/identicon'
export default class ProviderPageContainerContent extends PureComponent {
static propTypes = {
origin: PropTypes.string.isRequired,
- selectedIdentity: PropTypes.string.isRequired,
+ selectedIdentity: PropTypes.object.isRequired,
siteImage: PropTypes.string,
siteTitle: PropTypes.string.isRequired,
}
diff --git a/ui/app/components/app/sidebars/sidebar.component.js b/ui/app/components/app/sidebars/sidebar.component.js
index b9e0f9e81..e532ba7e5 100644
--- a/ui/app/components/app/sidebars/sidebar.component.js
+++ b/ui/app/components/app/sidebars/sidebar.component.js
@@ -1,6 +1,6 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
-import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
+import ReactCSSTransitionGroup from 'react-transition-group/CSSTransitionGroup'
import WalletView from '../wallet-view'
import { WALLET_VIEW_SIDEBAR } from './sidebar.constants'
import CustomizeGas from '../gas-customization/gas-modal-page-container/'
@@ -26,7 +26,7 @@ export default class Sidebar extends Component {
onOverlayClose && onOverlayClose()
this.props.hideSidebar()
}
- } />
+ } />
}
renderSidebarContent () {
diff --git a/ui/app/components/app/sidebars/tests/sidebars-component.test.js b/ui/app/components/app/sidebars/tests/sidebars-component.test.js
index cee22aca8..e2daea9b6 100644
--- a/ui/app/components/app/sidebars/tests/sidebars-component.test.js
+++ b/ui/app/components/app/sidebars/tests/sidebars-component.test.js
@@ -2,7 +2,7 @@ import React from 'react'
import assert from 'assert'
import { shallow } from 'enzyme'
import sinon from 'sinon'
-import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
+import ReactCSSTransitionGroup from 'react-transition-group/CSSTransitionGroup'
import Sidebar from '../sidebar.component.js'
import WalletView from '../../wallet-view'
diff --git a/ui/app/components/app/signature-request.js b/ui/app/components/app/signature-request.js
index fa237f1d1..9c0f53f57 100644
--- a/ui/app/components/app/signature-request.js
+++ b/ui/app/components/app/signature-request.js
@@ -12,7 +12,7 @@ const { compose } = require('recompose')
const { withRouter } = require('react-router-dom')
const { ObjectInspector } = require('react-inspector')
-import AccountDropdownMini from '../ui/account-dropdown-mini'
+import AccountListItem from '../../pages/send/account-list-item/account-list-item.component'
const actions = require('../../store/actions')
const { conversionUtil } = require('../../helpers/utils/conversion-util')
@@ -21,7 +21,6 @@ const {
getSelectedAccount,
getCurrentAccountWithSendEtherInfo,
getSelectedAddress,
- accountsWithSendEtherInfoSelector,
conversionRateSelector,
} = require('../../selectors/selectors.js')
@@ -37,7 +36,6 @@ function mapStateToProps (state) {
selectedAddress: getSelectedAddress(state),
requester: null,
requesterAddress: null,
- accounts: accountsWithSendEtherInfoSelector(state),
conversionRate: conversionRateSelector(state),
}
}
@@ -76,9 +74,9 @@ function mergeProps (stateProps, dispatchProps, ownProps) {
}
return {
+ ...ownProps,
...stateProps,
...dispatchProps,
- ...ownProps,
txData,
cancel,
sign,
@@ -137,23 +135,19 @@ SignatureRequest.prototype.renderHeader = function () {
])
}
-SignatureRequest.prototype.renderAccountDropdown = function () {
+SignatureRequest.prototype.renderAccount = function () {
const { selectedAccount } = this.state
- const {
- accounts,
- } = this.props
-
return h('div.request-signature__account', [
h('div.request-signature__account-text', [this.context.t('account') + ':']),
- h(AccountDropdownMini, {
- selectedAccount,
- accounts,
- disabled: true,
- }),
-
+ h('div.request-signature__account-item', [
+ h(AccountListItem, {
+ account: selectedAccount,
+ displayBalance: false,
+ }),
+ ]),
])
}
@@ -180,7 +174,7 @@ SignatureRequest.prototype.renderBalance = function () {
SignatureRequest.prototype.renderAccountInfo = function () {
return h('div.request-signature__account-info', [
- this.renderAccountDropdown(),
+ this.renderAccount(),
this.renderRequestIcon(),
@@ -257,7 +251,7 @@ SignatureRequest.prototype.renderBody = function () {
url: 'https://metamask.zendesk.com/hc/en-us/articles/360015488751',
})
},
- }, this.context.t('learnMore'))]
+ }, this.context.t('learnMore'))]
}
return h('div.request-signature__body', {}, [
diff --git a/ui/app/components/app/token-list.js b/ui/app/components/app/token-list.js
index 2188e7020..000ca6b3f 100644
--- a/ui/app/components/app/token-list.js
+++ b/ui/app/components/app/token-list.js
@@ -67,8 +67,8 @@ TokenList.prototype.render = function () {
},
onClick: () => {
global.platform.openWindow({
- url: `https://ethplorer.io/address/${userAddress}`,
- })
+ url: `https://ethplorer.io/address/${userAddress}`,
+ })
},
}, this.context.t('here')),
])
@@ -125,13 +125,13 @@ TokenList.prototype.createFreshTokenTracker = function () {
this.tracker.on('error', this.showError)
this.tracker.updateBalances()
- .then(() => {
- this.updateBalances(this.tracker.serialize())
- })
- .catch((reason) => {
- log.error(`Problem updating balances`, reason)
- this.setState({ isLoading: false })
- })
+ .then(() => {
+ this.updateBalances(this.tracker.serialize())
+ })
+ .catch((reason) => {
+ log.error(`Problem updating balances`, reason)
+ this.setState({ isLoading: false })
+ })
}
TokenList.prototype.componentDidUpdate = function (prevProps) {
diff --git a/ui/app/components/app/transaction-activity-log/transaction-activity-log-icon/transaction-activity-log-icon.component.js b/ui/app/components/app/transaction-activity-log/transaction-activity-log-icon/transaction-activity-log-icon.component.js
index 871716002..6124325be 100644
--- a/ui/app/components/app/transaction-activity-log/transaction-activity-log-icon/transaction-activity-log-icon.component.js
+++ b/ui/app/components/app/transaction-activity-log/transaction-activity-log-icon/transaction-activity-log-icon.component.js
@@ -40,15 +40,15 @@ export default class TransactionActivityLogIcon extends PureComponent {
return (
<div className={classnames('transaction-activity-log-icon', className)}>
- {
- imagePath && (
- <img
- src={imagePath}
- height={9}
- width={9}
- />
- )
- }
+ {
+ imagePath && (
+ <img
+ src={imagePath}
+ height={9}
+ width={9}
+ />
+ )
+ }
</div>
)
}
diff --git a/ui/app/components/app/transaction-list-item-details/tests/transaction-list-item-details.component.test.js b/ui/app/components/app/transaction-list-item-details/tests/transaction-list-item-details.component.test.js
index c4e118b01..583980d26 100644
--- a/ui/app/components/app/transaction-list-item-details/tests/transaction-list-item-details.component.test.js
+++ b/ui/app/components/app/transaction-list-item-details/tests/transaction-list-item-details.component.test.js
@@ -78,4 +78,73 @@ describe('TransactionListItemDetails Component', () => {
assert.ok(wrapper.hasClass('transaction-list-item-details'))
assert.equal(wrapper.find(Button).length, 3)
})
+
+ it('should disable the Copy Tx ID and View In Etherscan buttons when tx hash is missing', () => {
+ const transaction = {
+ history: [],
+ id: 1,
+ status: 'confirmed',
+ txParams: {
+ from: '0x1',
+ gas: '0x5208',
+ gasPrice: '0x3b9aca00',
+ nonce: '0xa4',
+ to: '0x2',
+ value: '0x2386f26fc10000',
+ },
+ }
+
+ const transactionGroup = {
+ transactions: [transaction],
+ primaryTransaction: transaction,
+ initialTransaction: transaction,
+ }
+
+ const wrapper = shallow(
+ <TransactionListItemDetails
+ transactionGroup={transactionGroup}
+ />,
+ { context: { t: (str1, str2) => str2 ? str1 + str2 : str1 } }
+ )
+
+ assert.ok(wrapper.hasClass('transaction-list-item-details'))
+ const buttons = wrapper.find(Button)
+ assert.strictEqual(buttons.at(0).prop('disabled'), true)
+ assert.strictEqual(buttons.at(1).prop('disabled'), true)
+ })
+
+ it('should render functional Copy Tx ID and View In Etherscan buttons when tx hash exists', () => {
+ const transaction = {
+ history: [],
+ id: 1,
+ status: 'confirmed',
+ hash: '0xaa',
+ txParams: {
+ from: '0x1',
+ gas: '0x5208',
+ gasPrice: '0x3b9aca00',
+ nonce: '0xa4',
+ to: '0x2',
+ value: '0x2386f26fc10000',
+ },
+ }
+
+ const transactionGroup = {
+ transactions: [transaction],
+ primaryTransaction: transaction,
+ initialTransaction: transaction,
+ }
+
+ const wrapper = shallow(
+ <TransactionListItemDetails
+ transactionGroup={transactionGroup}
+ />,
+ { context: { t: (str1, str2) => str2 ? str1 + str2 : str1 } }
+ )
+
+ assert.ok(wrapper.hasClass('transaction-list-item-details'))
+ const buttons = wrapper.find(Button)
+ assert.strictEqual(buttons.at(0).prop('disabled'), false)
+ assert.strictEqual(buttons.at(1).prop('disabled'), false)
+ })
})
diff --git a/ui/app/components/app/transaction-list-item-details/transaction-list-item-details.component.js b/ui/app/components/app/transaction-list-item-details/transaction-list-item-details.component.js
index 72ca784e2..d8dd965fc 100644
--- a/ui/app/components/app/transaction-list-item-details/transaction-list-item-details.component.js
+++ b/ui/app/components/app/transaction-list-item-details/transaction-list-item-details.component.js
@@ -128,7 +128,7 @@ export default class TransactionListItemDetails extends PureComponent {
rpcPrefs: { blockExplorerUrl } = {},
} = this.props
const { primaryTransaction: transaction } = transactionGroup
- const { txParams: { to, from } = {} } = transaction
+ const { hash, txParams: { to, from } = {} } = transaction
return (
<div className="transaction-list-item-details">
@@ -152,6 +152,7 @@ export default class TransactionListItemDetails extends PureComponent {
type="raised"
onClick={this.handleCopyTxId}
className="transaction-list-item-details__header-button"
+ disabled={!hash}
>
<img
className="transaction-list-item-details__header-button__copy-icon"
@@ -164,7 +165,8 @@ export default class TransactionListItemDetails extends PureComponent {
type="raised"
onClick={this.handleEtherscanClick}
className="transaction-list-item-details__header-button"
- >
+ disabled={!hash}
+ >
<img src="/images/arrow-popout.svg" />
</Button>
</Tooltip>
diff --git a/ui/app/components/app/transaction-list/transaction-list.component.js b/ui/app/components/app/transaction-list/transaction-list.component.js
index fc5488884..157e7200b 100644
--- a/ui/app/components/app/transaction-list/transaction-list.component.js
+++ b/ui/app/components/app/transaction-list/transaction-list.component.js
@@ -10,11 +10,13 @@ export default class TransactionList extends PureComponent {
}
static defaultProps = {
+ children: null,
pendingTransactions: [],
completedTransactions: [],
}
static propTypes = {
+ children: PropTypes.node,
pendingTransactions: PropTypes.array,
completedTransactions: PropTypes.array,
selectedToken: PropTypes.object,
@@ -39,7 +41,7 @@ export default class TransactionList extends PureComponent {
const { transactions = [], hasRetried } = transactionGroup
const [earliestTransaction = {}] = transactions
const { submittedTime } = earliestTransaction
- return Date.now() - submittedTime > 30000 && isEarliestNonce && !hasRetried
+ return Date.now() - submittedTime > 5000 && isEarliestNonce && !hasRetried
}
shouldShowCancel (transactionGroup) {
@@ -75,8 +77,8 @@ export default class TransactionList extends PureComponent {
{
completedTransactions.length > 0
? completedTransactions.map((transactionGroup, index) => (
- this.renderTransaction(transactionGroup, index)
- ))
+ this.renderTransaction(transactionGroup, index)
+ ))
: this.renderEmpty()
}
</div>
@@ -120,6 +122,7 @@ export default class TransactionList extends PureComponent {
return (
<div className="transaction-list">
{ this.renderTransactions() }
+ { this.props.children }
</div>
)
}
diff --git a/ui/app/components/app/transaction-status/index.scss b/ui/app/components/app/transaction-status/index.scss
index 024cbf2a1..99884d28c 100644
--- a/ui/app/components/app/transaction-status/index.scss
+++ b/ui/app/components/app/transaction-status/index.scss
@@ -43,4 +43,10 @@
border: 1px solid $monzo;
}
}
+
+ &__pending-spinner {
+ height: 16px;
+ width: 16px;
+ margin-right: 6px;
+ }
}
diff --git a/ui/app/components/app/transaction-status/transaction-status.component.js b/ui/app/components/app/transaction-status/transaction-status.component.js
index d3a239539..a97b79bde 100644
--- a/ui/app/components/app/transaction-status/transaction-status.component.js
+++ b/ui/app/components/app/transaction-status/transaction-status.component.js
@@ -2,6 +2,8 @@ import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import Tooltip from '../../ui/tooltip-v2'
+import Spinner from '../../ui/spinner'
+
import {
UNAPPROVED_STATUS,
REJECTED_STATUS,
@@ -51,6 +53,7 @@ export default class TransactionStatus extends PureComponent {
return (
<div className={classnames('transaction-status', className, statusToClassNameHash[statusKey])}>
+ { statusToTextHash[statusKey] === 'pending' ? <Spinner className="transaction-status__pending-spinner" /> : null }
<Tooltip
position="top"
title={title}
diff --git a/ui/app/components/app/transaction-view-balance/transaction-view-balance.component.js b/ui/app/components/app/transaction-view-balance/transaction-view-balance.component.js
index 3f6abbb00..feb701dbe 100644
--- a/ui/app/components/app/transaction-view-balance/transaction-view-balance.component.js
+++ b/ui/app/components/app/transaction-view-balance/transaction-view-balance.component.js
@@ -43,38 +43,38 @@ export default class TransactionViewBalance extends PureComponent {
/>
</div>
) : (
- <Tooltip position="top" title={this.context.t('balanceOutdated')} disabled={!balanceIsCached}>
- <div className="transaction-view-balance__balance">
- <div className="transaction-view-balance__primary-container">
- <UserPreferencedCurrencyDisplay
- className={classnames('transaction-view-balance__primary-balance', {
- 'transaction-view-balance__cached-balance': balanceIsCached,
- })}
- value={balance}
- type={PRIMARY}
- ethNumberOfDecimals={4}
- hideTitle={true}
- />
- {
- balanceIsCached ? <span className="transaction-view-balance__cached-star">*</span> : null
- }
- </div>
- {
- showFiat && (
- <UserPreferencedCurrencyDisplay
- className={classnames({
- 'transaction-view-balance__cached-secondary-balance': balanceIsCached,
- 'transaction-view-balance__secondary-balance': !balanceIsCached,
- })}
- value={balance}
- type={SECONDARY}
- ethNumberOfDecimals={4}
- hideTitle={true}
- />
- )
- }
+ <Tooltip position="top" title={this.context.t('balanceOutdated')} disabled={!balanceIsCached}>
+ <div className="transaction-view-balance__balance">
+ <div className="transaction-view-balance__primary-container">
+ <UserPreferencedCurrencyDisplay
+ className={classnames('transaction-view-balance__primary-balance', {
+ 'transaction-view-balance__cached-balance': balanceIsCached,
+ })}
+ value={balance}
+ type={PRIMARY}
+ ethNumberOfDecimals={4}
+ hideTitle={true}
+ />
+ {
+ balanceIsCached ? <span className="transaction-view-balance__cached-star">*</span> : null
+ }
</div>
- </Tooltip>
+ {
+ showFiat && (
+ <UserPreferencedCurrencyDisplay
+ className={classnames({
+ 'transaction-view-balance__cached-secondary-balance': balanceIsCached,
+ 'transaction-view-balance__secondary-balance': !balanceIsCached,
+ })}
+ value={balance}
+ type={SECONDARY}
+ ethNumberOfDecimals={4}
+ hideTitle={true}
+ />
+ )
+ }
+ </div>
+ </Tooltip>
)
}
diff --git a/ui/app/components/app/transaction-view/transaction-view.component.js b/ui/app/components/app/transaction-view/transaction-view.component.js
index 7014ca173..fb2c2145c 100644
--- a/ui/app/components/app/transaction-view/transaction-view.component.js
+++ b/ui/app/components/app/transaction-view/transaction-view.component.js
@@ -10,6 +10,14 @@ export default class TransactionView extends PureComponent {
t: PropTypes.func,
}
+ static propTypes = {
+ children: PropTypes.node,
+ }
+
+ static defaultProps = {
+ children: null,
+ }
+
render () {
return (
<div className="transaction-view">
@@ -20,7 +28,9 @@ export default class TransactionView extends PureComponent {
<div className="transaction-view__balance-wrapper">
<TransactionViewBalance />
</div>
- <TransactionList />
+ <TransactionList>
+ { this.props.children }
+ </TransactionList>
</div>
)
}
diff --git a/ui/app/components/app/ui-migration-annoucement/index.js b/ui/app/components/app/ui-migration-annoucement/index.js
deleted file mode 100644
index c6c8cc619..000000000
--- a/ui/app/components/app/ui-migration-annoucement/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export {default} from './ui-migration-announcement.container'
diff --git a/ui/app/components/app/ui-migration-annoucement/index.scss b/ui/app/components/app/ui-migration-annoucement/index.scss
deleted file mode 100644
index 6138a3079..000000000
--- a/ui/app/components/app/ui-migration-annoucement/index.scss
+++ /dev/null
@@ -1,22 +0,0 @@
-.ui-migration-announcement {
- position: absolute;
- z-index: 9999;
- width: 100vw;
- height: 100vh;
- display: flex;
- flex-direction: column;
- align-items: center;
- background: $white;
-
- p {
- box-sizing: border-box;
- padding: 1em;
- font-size: 12pt;
- }
-
- p:last-of-type {
- cursor: pointer;
- text-decoration: underline;
- font-weight: bold;
- }
-}
diff --git a/ui/app/components/app/ui-migration-annoucement/ui-migration-annoucement.component.js b/ui/app/components/app/ui-migration-annoucement/ui-migration-annoucement.component.js
deleted file mode 100644
index 7a4124972..000000000
--- a/ui/app/components/app/ui-migration-annoucement/ui-migration-annoucement.component.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import PropTypes from 'prop-types'
-import React, {PureComponent} from 'react'
-
-export default class UiMigrationAnnouncement extends PureComponent {
- static contextTypes = {
- t: PropTypes.func.isRequired,
- }
-
- static defaultProps = {
- shouldShowAnnouncement: true,
- };
-
- static propTypes = {
- onClose: PropTypes.func.isRequired,
- shouldShowAnnouncement: PropTypes.bool,
- }
-
- render () {
- const { t } = this.context
- const { onClose, shouldShowAnnouncement } = this.props
-
- if (!shouldShowAnnouncement) {
- return null
- }
-
- return (
- <div className="ui-migration-announcement">
- <p>{t('uiMigrationAnnouncement')}</p>
- <p onClick={onClose}>{t('close')}</p>
- </div>
- )
- }
-}
diff --git a/ui/app/components/app/ui-migration-annoucement/ui-migration-announcement.container.js b/ui/app/components/app/ui-migration-annoucement/ui-migration-announcement.container.js
deleted file mode 100644
index 55efd5a44..000000000
--- a/ui/app/components/app/ui-migration-annoucement/ui-migration-announcement.container.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import { connect } from 'react-redux'
-import UiMigrationAnnouncement from './ui-migration-annoucement.component'
-import { setCompletedUiMigration } from '../../../store/actions'
-
-const mapStateToProps = (state) => {
- const shouldShowAnnouncement = !state.metamask.completedUiMigration
-
- return {
- shouldShowAnnouncement,
- }
-}
-
-const mapDispatchToProps = dispatch => {
- return {
- onClose () {
- dispatch(setCompletedUiMigration())
- },
- }
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(UiMigrationAnnouncement)
diff --git a/ui/app/components/app/wallet-view.js b/ui/app/components/app/wallet-view.js
index b8bae5421..55aeec333 100644
--- a/ui/app/components/app/wallet-view.js
+++ b/ui/app/components/app/wallet-view.js
@@ -5,12 +5,8 @@ const h = require('react-hyperscript')
const { withRouter } = require('react-router-dom')
const { compose } = require('recompose')
const inherits = require('util').inherits
-const classnames = require('classnames')
const { checksumAddress } = require('../../helpers/utils/util')
-import Identicon from '../ui/identicon'
// const AccountDropdowns = require('./dropdowns/index.js').AccountDropdowns
-const Tooltip = require('../ui/tooltip-v2.js').default
-const copyToClipboard = require('copy-to-clipboard')
const actions = require('../../store/actions')
import BalanceComponent from '../ui/balance'
const TokenList = require('./token-list')
@@ -18,6 +14,7 @@ const selectors = require('../../selectors/selectors')
const { ADD_TOKEN_ROUTE } = require('../../helpers/constants/routes')
import AddTokenButton from './add-token-button'
+import AccountDetails from './account-details'
module.exports = compose(
withRouter,
@@ -52,9 +49,6 @@ function mapDispatchToProps (dispatch) {
showSendPage: () => dispatch(actions.showSendPage()),
hideSidebar: () => dispatch(actions.hideSidebar()),
unsetSelectedToken: () => dispatch(actions.setSelectedToken()),
- showAccountDetailModal: () => {
- dispatch(actions.showModal({ name: 'ACCOUNT_DETAILS' }))
- },
showAddTokenPage: () => dispatch(actions.showAddTokenPage()),
}
}
@@ -62,10 +56,6 @@ function mapDispatchToProps (dispatch) {
inherits(WalletView, Component)
function WalletView () {
Component.call(this)
- this.state = {
- hasCopied: false,
- copyToClipboardPressed: false,
- }
}
WalletView.prototype.renderWalletBalance = function () {
@@ -130,8 +120,6 @@ WalletView.prototype.render = function () {
responsiveDisplayClassname,
selectedAddress,
keyrings,
- showAccountDetailModal,
- hideSidebar,
identities,
network,
} = this.props
@@ -165,67 +153,11 @@ WalletView.prototype.render = function () {
className: responsiveDisplayClassname,
}, [
- // TODO: Separate component: wallet account details
- h('div.flex-column.wallet-view-account-details', {
- style: {},
- }, [
- h('div.wallet-view__sidebar-close', {
- onClick: hideSidebar,
- }),
-
- h('div.wallet-view__keyring-label.allcaps', label),
-
- h('div.flex-column.flex-center.wallet-view__name-container', {
- style: { margin: '0 auto' },
- onClick: showAccountDetailModal,
- }, [
- h(Identicon, {
- diameter: 54,
- address: checksummedAddress,
- }),
-
- h('span.account-name', {
- style: {},
- }, [
- identities[selectedAddress].name,
- ]),
-
- h('button.btn-secondary.wallet-view__details-button', this.context.t('details')),
- ]),
- ]),
-
- h(Tooltip, {
- position: 'bottom',
- title: this.state.hasCopied ? this.context.t('copiedExclamation') : this.context.t('copyToClipboard'),
- wrapperClassName: 'wallet-view__tooltip',
- }, [
- h('button.wallet-view__address', {
- className: classnames({
- 'wallet-view__address__pressed': this.state.copyToClipboardPressed,
- }),
- onClick: () => {
- copyToClipboard(checksummedAddress)
- this.context.metricsEvent({
- eventOpts: {
- category: 'Navigation',
- action: 'Home',
- name: 'Copied Address',
- },
- })
- this.setState({ hasCopied: true })
- setTimeout(() => this.setState({ hasCopied: false }), 3000)
- },
- onMouseDown: () => {
- this.setState({ copyToClipboardPressed: true })
- },
- onMouseUp: () => {
- this.setState({ copyToClipboardPressed: false })
- },
- }, [
- `${checksummedAddress.slice(0, 6)}...${checksummedAddress.slice(-4)}`,
- h('i.fa.fa-clipboard', { style: { marginLeft: '8px' } }),
- ]),
- ]),
+ h(AccountDetails, {
+ label,
+ checksummedAddress,
+ name: identities[selectedAddress].name,
+ }),
this.renderWalletBalance(),
diff --git a/ui/app/components/ui/account-dropdown-mini/account-dropdown-mini.component.js b/ui/app/components/ui/account-dropdown-mini/account-dropdown-mini.component.js
deleted file mode 100644
index d9627e31b..000000000
--- a/ui/app/components/ui/account-dropdown-mini/account-dropdown-mini.component.js
+++ /dev/null
@@ -1,84 +0,0 @@
-import React, { PureComponent } from 'react'
-import PropTypes from 'prop-types'
-import AccountListItem from '../../../pages/send/account-list-item/account-list-item.component'
-
-export default class AccountDropdownMini extends PureComponent {
- static propTypes = {
- accounts: PropTypes.array.isRequired,
- closeDropdown: PropTypes.func,
- disabled: PropTypes.bool,
- dropdownOpen: PropTypes.bool,
- onSelect: PropTypes.func,
- openDropdown: PropTypes.func,
- selectedAccount: PropTypes.object.isRequired,
- }
-
- static defaultProps = {
- closeDropdown: () => {},
- disabled: false,
- dropdownOpen: false,
- onSelect: () => {},
- openDropdown: () => {},
- }
-
- getListItemIcon (currentAccount, selectedAccount) {
- return currentAccount.address === selectedAccount.address && (
- <i
- className="fa fa-check fa-lg"
- style={{ color: '#02c9b1' }}
- />
- )
- }
-
- renderDropdown () {
- const { accounts, selectedAccount, closeDropdown, onSelect } = this.props
-
- return (
- <div>
- <div
- className="account-dropdown-mini__close-area"
- onClick={closeDropdown}
- />
- <div className="account-dropdown-mini__list">
- {
- accounts.map(account => (
- <AccountListItem
- key={account.address}
- account={account}
- displayBalance={false}
- displayAddress={false}
- handleClick={() => {
- onSelect(account)
- closeDropdown()
- }}
- icon={this.getListItemIcon(account, selectedAccount)}
- />
- ))
- }
- </div>
- </div>
- )
- }
-
- render () {
- const { disabled, selectedAccount, openDropdown, dropdownOpen } = this.props
-
- return (
- <div className="account-dropdown-mini">
- <AccountListItem
- account={selectedAccount}
- handleClick={() => !disabled && openDropdown()}
- displayBalance={false}
- displayAddress={false}
- icon={
- !disabled && <i
- className="fa fa-caret-down fa-lg"
- style={{ color: '#dedede' }}
- />
- }
- />
- { !disabled && dropdownOpen && this.renderDropdown() }
- </div>
- )
- }
-}
diff --git a/ui/app/components/ui/account-dropdown-mini/index.js b/ui/app/components/ui/account-dropdown-mini/index.js
deleted file mode 100644
index cb0839e72..000000000
--- a/ui/app/components/ui/account-dropdown-mini/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from './account-dropdown-mini.component'
diff --git a/ui/app/components/ui/account-dropdown-mini/tests/account-dropdown-mini.component.test.js b/ui/app/components/ui/account-dropdown-mini/tests/account-dropdown-mini.component.test.js
deleted file mode 100644
index 9691f38aa..000000000
--- a/ui/app/components/ui/account-dropdown-mini/tests/account-dropdown-mini.component.test.js
+++ /dev/null
@@ -1,107 +0,0 @@
-import React from 'react'
-import assert from 'assert'
-import { shallow } from 'enzyme'
-import AccountDropdownMini from '../account-dropdown-mini.component'
-import AccountListItem from '../../../../pages/send/account-list-item/account-list-item.component'
-
-describe('AccountDropdownMini', () => {
- it('should render an account with an icon', () => {
- const accounts = [
- {
- address: '0x1',
- name: 'account1',
- balance: '0x1',
- },
- {
- address: '0x2',
- name: 'account2',
- balance: '0x2',
- },
- {
- address: '0x3',
- name: 'account3',
- balance: '0x3',
- },
- ]
-
- const wrapper = shallow(
- <AccountDropdownMini
- selectedAccount={{ address: '0x1', name: 'account1', balance: '0x1' }}
- accounts={accounts}
- />
- )
-
- assert.ok(wrapper)
- assert.equal(wrapper.find(AccountListItem).length, 1)
- const accountListItemProps = wrapper.find(AccountListItem).at(0).props()
- assert.equal(accountListItemProps.account.address, '0x1')
- const iconProps = accountListItemProps.icon.props
- assert.equal(iconProps.className, 'fa fa-caret-down fa-lg')
- })
-
- it('should render a list of accounts', () => {
- const accounts = [
- {
- address: '0x1',
- name: 'account1',
- balance: '0x1',
- },
- {
- address: '0x2',
- name: 'account2',
- balance: '0x2',
- },
- {
- address: '0x3',
- name: 'account3',
- balance: '0x3',
- },
- ]
-
- const wrapper = shallow(
- <AccountDropdownMini
- selectedAccount={{ address: '0x1', name: 'account1', balance: '0x1' }}
- accounts={accounts}
- dropdownOpen={true}
- />
- )
-
- assert.ok(wrapper)
- assert.equal(wrapper.find(AccountListItem).length, 4)
- })
-
- it('should render a single account when disabled', () => {
- const accounts = [
- {
- address: '0x1',
- name: 'account1',
- balance: '0x1',
- },
- {
- address: '0x2',
- name: 'account2',
- balance: '0x2',
- },
- {
- address: '0x3',
- name: 'account3',
- balance: '0x3',
- },
- ]
-
- const wrapper = shallow(
- <AccountDropdownMini
- selectedAccount={{ address: '0x1', name: 'account1', balance: '0x1' }}
- accounts={accounts}
- dropdownOpen={false}
- disabled={true}
- />
- )
-
- assert.ok(wrapper)
- assert.equal(wrapper.find(AccountListItem).length, 1)
- const accountListItemProps = wrapper.find(AccountListItem).at(0).props()
- assert.equal(accountListItemProps.account.address, '0x1')
- assert.equal(accountListItemProps.icon, false)
- })
-})
diff --git a/ui/app/components/ui/alert/index.js b/ui/app/components/ui/alert/index.js
index b1229f502..da2ca4b66 100644
--- a/ui/app/components/ui/alert/index.js
+++ b/ui/app/components/ui/alert/index.js
@@ -4,59 +4,59 @@ const h = require('react-hyperscript')
class Alert extends Component {
- constructor (props) {
- super(props)
-
- this.state = {
- visble: false,
- msg: false,
- className: '',
- }
- }
-
- componentWillReceiveProps (nextProps) {
- if (!this.props.visible && nextProps.visible) {
- this.animateIn(nextProps)
- } else if (this.props.visible && !nextProps.visible) {
- this.animateOut()
- }
- }
+ constructor (props) {
+ super(props)
- animateIn (props) {
- this.setState({
- msg: props.msg,
- visible: true,
- className: '.visible',
- })
+ this.state = {
+ visble: false,
+ msg: false,
+ className: '',
}
+ }
- animateOut () {
- this.setState({
- msg: null,
- className: '.hidden',
- })
-
- setTimeout(_ => {
- this.setState({visible: false})
- }, 500)
-
+ componentWillReceiveProps (nextProps) {
+ if (!this.props.visible && nextProps.visible) {
+ this.animateIn(nextProps)
+ } else if (this.props.visible && !nextProps.visible) {
+ this.animateOut()
}
-
- render () {
- if (this.state.visible) {
- return (
- h(`div.global-alert${this.state.className}`, {},
- h('a.msg', {}, this.state.msg)
- )
- )
- }
- return null
+ }
+
+ animateIn (props) {
+ this.setState({
+ msg: props.msg,
+ visible: true,
+ className: '.visible',
+ })
+ }
+
+ animateOut () {
+ this.setState({
+ msg: null,
+ className: '.hidden',
+ })
+
+ setTimeout(_ => {
+ this.setState({visible: false})
+ }, 500)
+
+ }
+
+ render () {
+ if (this.state.visible) {
+ return (
+ h(`div.global-alert${this.state.className}`, {},
+ h('a.msg', {}, this.state.msg)
+ )
+ )
}
+ return null
+ }
}
Alert.propTypes = {
- visible: PropTypes.bool.isRequired,
- msg: PropTypes.string,
+ visible: PropTypes.bool.isRequired,
+ msg: PropTypes.string,
}
module.exports = Alert
diff --git a/ui/app/components/ui/button-group/tests/button-group-component.test.js b/ui/app/components/ui/button-group/tests/button-group-component.test.js
index 0bece90d6..f2e512445 100644
--- a/ui/app/components/ui/button-group/tests/button-group-component.test.js
+++ b/ui/app/components/ui/button-group/tests/button-group-component.test.js
@@ -59,40 +59,40 @@ describe('ButtonGroup Component', function () {
describe('renderButtons', () => {
it('should render a button for each child', () => {
- const childButtons = wrapper.find('.button-group__button')
- assert.equal(childButtons.length, 3)
+ const childButtons = wrapper.find('.button-group__button')
+ assert.equal(childButtons.length, 3)
})
it('should render the correct button with an active state', () => {
- const childButtons = wrapper.find('.button-group__button')
- const activeChildButton = wrapper.find('.button-group__button--active')
- assert.deepEqual(childButtons.get(1), activeChildButton.get(0))
+ const childButtons = wrapper.find('.button-group__button')
+ const activeChildButton = wrapper.find('.button-group__button--active')
+ assert.deepEqual(childButtons.get(1), activeChildButton.get(0))
})
it('should call handleButtonClick and the respective button\'s onClick method when a button is clicked', () => {
- assert.equal(ButtonGroup.prototype.handleButtonClick.callCount, 0)
- assert.equal(childButtonSpies.onClick.callCount, 0)
- const childButtons = wrapper.find('.button-group__button')
- childButtons.at(0).props().onClick()
- childButtons.at(1).props().onClick()
- childButtons.at(2).props().onClick()
- assert.equal(ButtonGroup.prototype.handleButtonClick.callCount, 3)
- assert.equal(childButtonSpies.onClick.callCount, 3)
+ assert.equal(ButtonGroup.prototype.handleButtonClick.callCount, 0)
+ assert.equal(childButtonSpies.onClick.callCount, 0)
+ const childButtons = wrapper.find('.button-group__button')
+ childButtons.at(0).props().onClick()
+ childButtons.at(1).props().onClick()
+ childButtons.at(2).props().onClick()
+ assert.equal(ButtonGroup.prototype.handleButtonClick.callCount, 3)
+ assert.equal(childButtonSpies.onClick.callCount, 3)
})
it('should render all child buttons as disabled if props.disabled is true', () => {
- const childButtons = wrapper.find('.button-group__button')
- childButtons.forEach(button => {
- assert.equal(button.props().disabled, undefined)
- })
- wrapper.setProps({ disabled: true })
- const disabledChildButtons = wrapper.find('[disabled=true]')
- assert.equal(disabledChildButtons.length, 3)
+ const childButtons = wrapper.find('.button-group__button')
+ childButtons.forEach(button => {
+ assert.equal(button.props().disabled, undefined)
+ })
+ wrapper.setProps({ disabled: true })
+ const disabledChildButtons = wrapper.find('[disabled=true]')
+ assert.equal(disabledChildButtons.length, 3)
})
it('should render the children of the button', () => {
- const mockClass = wrapper.find('.mockClass')
- assert.equal(mockClass.length, 1)
+ const mockClass = wrapper.find('.mockClass')
+ assert.equal(mockClass.length, 1)
})
})
@@ -103,9 +103,9 @@ describe('ButtonGroup Component', function () {
})
it('should call renderButtons when rendering', () => {
- assert.equal(ButtonGroup.prototype.renderButtons.callCount, 1)
- wrapper.instance().render()
- assert.equal(ButtonGroup.prototype.renderButtons.callCount, 2)
+ assert.equal(ButtonGroup.prototype.renderButtons.callCount, 1)
+ wrapper.instance().render()
+ assert.equal(ButtonGroup.prototype.renderButtons.callCount, 2)
})
})
})
diff --git a/ui/app/components/ui/button/buttons.scss b/ui/app/components/ui/button/buttons.scss
index f1366cffe..f6388fa47 100644
--- a/ui/app/components/ui/button/buttons.scss
+++ b/ui/app/components/ui/button/buttons.scss
@@ -22,7 +22,6 @@ $hover-orange: #FFD3B5;
box-sizing: border-box;
border-radius: 6px;
width: 100%;
- outline: none;
transition: border-color .3s ease, background-color .3s ease;
&--disabled,
diff --git a/ui/app/components/ui/currency-input/currency-input.component.js b/ui/app/components/ui/currency-input/currency-input.component.js
index 1876c9591..f7db2b829 100644
--- a/ui/app/components/ui/currency-input/currency-input.component.js
+++ b/ui/app/components/ui/currency-input/currency-input.component.js
@@ -141,22 +141,22 @@ export default class CurrencyInput extends PureComponent {
const { decimalValue } = this.state
return (
- <UnitInput
- {...restProps}
- suffix={this.shouldUseFiat() ? fiatSuffix : nativeSuffix}
- onChange={this.handleChange}
- onBlur={this.handleBlur}
- value={decimalValue}
- maxModeOn={maxModeOn}
- actionComponent={(
- <div
- className="currency-input__swap-component"
- onClick={this.swap}
- />
- )}
- >
- { this.renderConversionComponent() }
- </UnitInput>
+ <UnitInput
+ {...restProps}
+ suffix={this.shouldUseFiat() ? fiatSuffix : nativeSuffix}
+ onChange={this.handleChange}
+ onBlur={this.handleBlur}
+ value={decimalValue}
+ maxModeOn={maxModeOn}
+ actionComponent={(
+ <div
+ className="currency-input__swap-component"
+ onClick={this.swap}
+ />
+ )}
+ >
+ { this.renderConversionComponent() }
+ </UnitInput>
)
}
}
diff --git a/ui/app/components/ui/dialog/dialog.scss b/ui/app/components/ui/dialog/dialog.scss
new file mode 100644
index 000000000..68b5ce329
--- /dev/null
+++ b/ui/app/components/ui/dialog/dialog.scss
@@ -0,0 +1,26 @@
+.dialog {
+ font-size: .75rem;
+ line-height: 1rem;
+ padding: 1rem;
+ border: 1px solid $black;
+ box-sizing: border-box;
+ border-radius: 8px;
+
+ &--message {
+ border-color: $Blue-200;
+ color: $Blue-600;
+ background-color: $Blue-000;
+ }
+
+ &--error {
+ border-color: $Red-300;
+ color: $Red-600;
+ background-color: $Red-000;
+ }
+
+ &--warning {
+ border-color: $Orange-300;
+ color: $Orange-600;
+ background-color: $Orange-000;
+ }
+}
diff --git a/ui/app/components/ui/dialog/index.js b/ui/app/components/ui/dialog/index.js
new file mode 100644
index 000000000..d7e522b22
--- /dev/null
+++ b/ui/app/components/ui/dialog/index.js
@@ -0,0 +1,26 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+import c from 'classnames'
+
+export default function Dialog (props) {
+ const { children, type, className, onClick } = props
+ return (
+ <div
+ className={c('dialog', className, {
+ 'dialog--message': type === 'message',
+ 'dialog--error': type === 'error',
+ 'dialog--warning': type === 'warning',
+ })}
+ onClick={onClick}
+ >
+ { children }
+ </div>
+ )
+}
+
+Dialog.propTypes = {
+ className: PropTypes.string,
+ children: PropTypes.node,
+ type: PropTypes.oneOf(['message', 'error', 'warning']),
+ onClick: PropTypes.func,
+}
diff --git a/ui/app/components/ui/identicon/identicon.component.js b/ui/app/components/ui/identicon/identicon.component.js
index 88521247c..5582c7d12 100644
--- a/ui/app/components/ui/identicon/identicon.component.js
+++ b/ui/app/components/ui/identicon/identicon.component.js
@@ -16,6 +16,7 @@ const getStyles = diameter => (
export default class Identicon extends PureComponent {
static propTypes = {
+ addBorder: PropTypes.bool,
address: PropTypes.string,
className: PropTypes.string,
diameter: PropTypes.number,
@@ -70,7 +71,7 @@ export default class Identicon extends PureComponent {
}
render () {
- const { className, address, image, diameter, useBlockie } = this.props
+ const { className, address, image, diameter, useBlockie, addBorder } = this.props
if (image) {
return this.renderImage()
@@ -83,9 +84,11 @@ export default class Identicon extends PureComponent {
return this.renderJazzicon()
}
- return useBlockie
- ? this.renderBlockie()
- : this.renderJazzicon()
+ return (
+ <div className={classnames({ 'identicon__address-wrapper': addBorder })}>
+ { useBlockie ? this.renderBlockie() : this.renderJazzicon() }
+ </div>
+ )
}
return (
diff --git a/ui/app/components/ui/identicon/index.scss b/ui/app/components/ui/identicon/index.scss
index 657afc48f..4c8213f01 100644
--- a/ui/app/components/ui/identicon/index.scss
+++ b/ui/app/components/ui/identicon/index.scss
@@ -4,4 +4,17 @@
align-items: center;
justify-content: center;
overflow: hidden;
+
+ &__address-wrapper {
+ height: 40px;
+ width: 40px;
+ border-radius: 18px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border-style: solid;
+ border-radius: 50%;
+ border-width: 2px;
+ border-color: $curious-blue;
+ }
}
diff --git a/ui/app/components/ui/metafox-logo/index.js b/ui/app/components/ui/metafox-logo/index.js
new file mode 100644
index 000000000..0aeaed743
--- /dev/null
+++ b/ui/app/components/ui/metafox-logo/index.js
@@ -0,0 +1 @@
+export { default } from './metafox-logo.component'
diff --git a/ui/app/components/ui/metafox-logo/metafox-logo.component.js b/ui/app/components/ui/metafox-logo/metafox-logo.component.js
new file mode 100644
index 000000000..041e354ef
--- /dev/null
+++ b/ui/app/components/ui/metafox-logo/metafox-logo.component.js
@@ -0,0 +1,31 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+
+export default class MetaFoxLogo extends PureComponent {
+ static propTypes = {
+ onClick: PropTypes.func,
+ unsetIconHeight: PropTypes.bool,
+ }
+
+ render () {
+ const iconProps = this.props.unsetIconHeight ? {} : { height: 42, width: 42 }
+
+ return (
+ <div
+ onClick={this.props.onClick}
+ className="app-header__logo-container"
+ >
+ <img
+ height={30}
+ src="/images/logo/metamask-logo-horizontal.svg"
+ className="app-header__metafox-logo app-header__metafox-logo--horizontal"
+ />
+ <img
+ {...iconProps}
+ src="/images/logo/metamask-fox.svg"
+ className="app-header__metafox-logo app-header__metafox-logo--icon"
+ />
+ </div>
+ )
+ }
+}
diff --git a/ui/app/components/ui/metafox-logo/tests/metafox-logo.component.test.js b/ui/app/components/ui/metafox-logo/tests/metafox-logo.component.test.js
new file mode 100644
index 000000000..c794a004f
--- /dev/null
+++ b/ui/app/components/ui/metafox-logo/tests/metafox-logo.component.test.js
@@ -0,0 +1,25 @@
+import React from 'react'
+import assert from 'assert'
+import { mount } from 'enzyme'
+import MetaFoxLogo from '../'
+
+describe('MetaFoxLogo', () => {
+
+ it('sets icon height and width to 42 by default', () => {
+ const wrapper = mount(
+ <MetaFoxLogo />
+ )
+
+ assert.equal(wrapper.find('img.app-header__metafox-logo--icon').prop('width'), 42)
+ assert.equal(wrapper.find('img.app-header__metafox-logo--icon').prop('height'), 42)
+ })
+
+ it('does not set icon height and width when unsetIconHeight is true', () => {
+ const wrapper = mount(
+ <MetaFoxLogo unsetIconHeight={true} />
+ )
+
+ assert.equal(wrapper.find('img.app-header__metafox-logo--icon').prop('width'), null)
+ assert.equal(wrapper.find('img.app-header__metafox-logo--icon').prop('height'), null)
+ })
+})
diff --git a/ui/app/components/ui/page-container/page-container-header/page-container-header.component.js b/ui/app/components/ui/page-container/page-container-header/page-container-header.component.js
index 08f9c7544..f1e15f10f 100644
--- a/ui/app/components/ui/page-container/page-container-header/page-container-header.component.js
+++ b/ui/app/components/ui/page-container/page-container-header/page-container-header.component.js
@@ -1,6 +1,6 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
-import classnames from 'classnames'
+import c from 'classnames'
export default class PageContainerHeader extends Component {
static propTypes = {
@@ -13,6 +13,7 @@ export default class PageContainerHeader extends Component {
backButtonString: PropTypes.string,
tabs: PropTypes.node,
headerCloseText: PropTypes.string,
+ className: PropTypes.string,
}
renderTabs () {
@@ -42,15 +43,14 @@ export default class PageContainerHeader extends Component {
}
render () {
- const { title, subtitle, onClose, tabs, headerCloseText } = this.props
+ const { title, subtitle, onClose, tabs, headerCloseText, className } = this.props
return (
- <div className={
- classnames(
- 'page-container__header',
- { 'page-container__header--no-padding-bottom': Boolean(tabs) }
- )
- }>
+ <div
+ className={c('page-container__header', className, {
+ 'page-container__header--no-padding-bottom': Boolean(tabs),
+ })}
+ >
{ this.renderHeaderRow() }
diff --git a/ui/app/components/ui/sender-to-recipient/sender-to-recipient.component.js b/ui/app/components/ui/sender-to-recipient/sender-to-recipient.component.js
index 57b595d48..a98a94101 100644
--- a/ui/app/components/ui/sender-to-recipient/sender-to-recipient.component.js
+++ b/ui/app/components/ui/sender-to-recipient/sender-to-recipient.component.js
@@ -64,10 +64,10 @@ export default class SenderToRecipient extends PureComponent {
containerClassName="sender-to-recipient__tooltip-container"
onHidden={() => this.setState({ senderAddressCopied: false })}
>
- <div className="sender-to-recipient__name">
- { addressOnly ? `${t('from')}: ${checksummedSenderAddress}` : senderName }
- </div>
- </Tooltip>
+ <div className="sender-to-recipient__name">
+ { addressOnly ? `${t('from')}: ${checksummedSenderAddress}` : senderName }
+ </div>
+ </Tooltip>
)
}
diff --git a/ui/app/components/ui/text-field/text-field.component.js b/ui/app/components/ui/text-field/text-field.component.js
index 1153a595b..ac7712c65 100644
--- a/ui/app/components/ui/text-field/text-field.component.js
+++ b/ui/app/components/ui/text-field/text-field.component.js
@@ -61,6 +61,9 @@ const styles = {
...inputLabelBase,
fontSize: '.75rem',
},
+ inputMultiline: {
+ lineHeight: 'initial !important',
+ },
}
const TextField = props => {
diff --git a/ui/app/components/ui/toggle-button/index.js b/ui/app/components/ui/toggle-button/index.js
new file mode 100644
index 000000000..7948d3ca1
--- /dev/null
+++ b/ui/app/components/ui/toggle-button/index.js
@@ -0,0 +1,2 @@
+import ToggleButton from './toggle-button.component'
+module.exports = ToggleButton
diff --git a/ui/app/components/ui/toggle-button/index.scss b/ui/app/components/ui/toggle-button/index.scss
new file mode 100644
index 000000000..868d416c8
--- /dev/null
+++ b/ui/app/components/ui/toggle-button/index.scss
@@ -0,0 +1,14 @@
+.toggle-button {
+ display: flex;
+
+ &__status-label {
+ font-family: Roboto;
+ font-style: normal;
+ font-weight: normal;
+ font-size: 16px;
+ line-height: 23px;
+ display: flex;
+ align-items: center;
+ text-transform: uppercase;
+ }
+} \ No newline at end of file
diff --git a/ui/app/components/ui/toggle-button/toggle-button.component.js b/ui/app/components/ui/toggle-button/toggle-button.component.js
new file mode 100644
index 000000000..3f13203a5
--- /dev/null
+++ b/ui/app/components/ui/toggle-button/toggle-button.component.js
@@ -0,0 +1,75 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+import ReactToggleButton from 'react-toggle-button'
+
+const trackStyle = {
+ width: '40px',
+ height: '24px',
+ padding: '0px',
+ borderRadius: '26px',
+ border: '2px solid rgb(3, 125, 214)',
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+}
+
+const offTrackStyle = {
+ ...trackStyle,
+ border: '2px solid #8E8E8E',
+}
+
+const thumbStyle = {
+ width: '18px',
+ height: '18px',
+ display: 'flex',
+ boxShadow: 'none',
+ alignSelf: 'center',
+ borderRadius: '50%',
+ position: 'relative',
+}
+
+const colors = {
+ activeThumb: {
+ base: '#037DD6',
+ },
+ inactiveThumb: {
+ base: '#037DD6',
+ },
+ active: {
+ base: '#ffffff',
+ hover: '#ffffff',
+ },
+ inactive: {
+ base: '#DADADA',
+ hover: '#DADADA',
+ },
+}
+
+const ToggleButton = props => {
+ const { value, onToggle, offLabel, onLabel } = props
+
+ return (
+ <div className="toggle-button">
+ <ReactToggleButton
+ value={value}
+ onToggle={onToggle}
+ activeLabel=""
+ inactiveLabel=""
+ trackStyle={value ? trackStyle : offTrackStyle}
+ thumbStyle={thumbStyle}
+ thumbAnimateRange={[3, 18]}
+ colors={colors}
+ />
+ <div className="toggle-button__status-label">{ value ? onLabel : offLabel }</div>
+ </div>
+ )
+}
+
+ToggleButton.propTypes = {
+ value: PropTypes.bool,
+ onToggle: PropTypes.func,
+ offLabel: PropTypes.string,
+ onLabel: PropTypes.string,
+}
+
+export default ToggleButton
diff --git a/ui/app/components/ui/unit-input/index.scss b/ui/app/components/ui/unit-input/index.scss
index 58a10c9a1..338b3829f 100644
--- a/ui/app/components/ui/unit-input/index.scss
+++ b/ui/app/components/ui/unit-input/index.scss
@@ -38,7 +38,6 @@
font-size: 1rem;
font-family: Roboto;
border: none;
- outline: 0 !important;
max-width: 22ch;
height: 16px;
line-height: 18px;