Switch existing modals from using Notification to Modal. Remove Notification component. Add CancelTransaction modal

feature/default_network_editable
Alexander Tseung 6 years ago
parent 3e470fee8a
commit 5a6c333506
  1. 15
      app/_locales/en/messages.json
  2. 5
      app/scripts/controllers/transactions/index.js
  3. 32
      ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/cancel-transaction-gas-fee.component.js
  4. 1
      ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/index.js
  5. 17
      ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/index.scss
  6. 71
      ui/app/components/modals/cancel-transaction/cancel-transaction.component.js
  7. 55
      ui/app/components/modals/cancel-transaction/cancel-transaction.container.js
  8. 1
      ui/app/components/modals/cancel-transaction/index.js
  9. 18
      ui/app/components/modals/cancel-transaction/index.scss
  10. 57
      ui/app/components/modals/confirm-remove-account/confirm-remove-account.component.js
  11. 8
      ui/app/components/modals/confirm-remove-account/confirm-remove-account.container.js
  12. 3
      ui/app/components/modals/confirm-remove-account/index.js
  13. 58
      ui/app/components/modals/confirm-remove-account/index.scss
  14. 46
      ui/app/components/modals/confirm-reset-account/confirm-reset-account.component.js
  15. 11
      ui/app/components/modals/confirm-reset-account/confirm-reset-account.container.js
  16. 3
      ui/app/components/modals/confirm-reset-account/index.js
  17. 109
      ui/app/components/modals/index.scss
  18. 40
      ui/app/components/modals/modal.js
  19. 2
      ui/app/components/modals/notification/index.js
  20. 30
      ui/app/components/modals/notification/notification.component.js
  21. 38
      ui/app/components/modals/notification/notification.container.js
  22. 3
      ui/app/components/modals/transaction-confirmed/index.js
  23. 22
      ui/app/components/modals/transaction-confirmed/index.scss
  24. 45
      ui/app/components/modals/transaction-confirmed/transaction-confirmed.component.js
  25. 4
      ui/app/components/modals/transaction-confirmed/transaction-confirmed.container.js
  26. 3
      ui/app/components/modals/welcome-beta/index.js
  27. 23
      ui/app/components/modals/welcome-beta/welcome-beta.component.js
  28. 4
      ui/app/components/modals/welcome-beta/welcome-beta.container.js
  29. 5
      ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js
  30. 4
      ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js
  31. 22
      ui/app/components/transaction-list-item-details/transaction-list-item-details.component.js
  32. 28
      ui/app/components/transaction-list-item/transaction-list-item.component.js
  33. 5
      ui/app/components/transaction-list-item/transaction-list-item.container.js
  34. 5
      ui/app/components/transaction-list/transaction-list.component.js
  35. 2
      ui/app/conf-tx.js
  36. 1
      ui/app/constants/transactions.js
  37. 12
      ui/app/helpers/conversions.util.js
  38. 7
      ui/app/helpers/transactions.util.js

@ -61,6 +61,12 @@
"attemptingConnect": { "attemptingConnect": {
"message": "Attempting to connect to blockchain." "message": "Attempting to connect to blockchain."
}, },
"attemptToCancel": {
"message": "Attempt to Cancel?"
},
"attemptToCancelDescription": {
"message": "Attempting to cancel does not guarantee your original transaction will be cancelled. If cancelled, you are still required to pay a transaction fee to the network."
},
"attributions": { "attributions": {
"message": "Attributions" "message": "Attributions"
}, },
@ -116,6 +122,12 @@
"cancel": { "cancel": {
"message": "Cancel" "message": "Cancel"
}, },
"cancelAttempt": {
"message": "Cancel Attempt"
},
"cancellationGasFee": {
"message": "Cancellation Gas Fee"
},
"classicInterface": { "classicInterface": {
"message": "Use classic interface" "message": "Use classic interface"
}, },
@ -1228,6 +1240,9 @@
"whatsThis": { "whatsThis": {
"message": "What's this?" "message": "What's this?"
}, },
"yesLetsTry": {
"message": "yes, let's try"
},
"youNeedToAllowCameraAccess": { "youNeedToAllowCameraAccess": {
"message": "You need to allow camera access to use this feature." "message": "You need to allow camera access to use this feature."
}, },

@ -18,7 +18,7 @@ const {
TRANSACTION_STATUS_APPROVED, TRANSACTION_STATUS_APPROVED,
} = require('./enums') } = require('./enums')
const { hexToBn, bnToHex } = require('../../lib/util') const { hexToBn, bnToHex, BnMultiplyByFraction } = require('../../lib/util')
/** /**
Transaction Controller is an aggregate of sub-controllers and trackers Transaction Controller is an aggregate of sub-controllers and trackers
@ -244,7 +244,8 @@ class TransactionController extends EventEmitter {
const originalTxMeta = this.txStateManager.getTx(originalTxId) const originalTxMeta = this.txStateManager.getTx(originalTxId)
const { txParams } = originalTxMeta const { txParams } = originalTxMeta
const { gasPrice: lastGasPrice, from, nonce } = txParams const { gasPrice: lastGasPrice, from, nonce } = txParams
const newGasPrice = customGasPrice || bnToHex(hexToBn(lastGasPrice).mul(1.1))
const newGasPrice = customGasPrice || bnToHex(BnMultiplyByFraction(hexToBn(lastGasPrice), 11, 10))
const newTxMeta = this.txStateManager.generateTxMeta({ const newTxMeta = this.txStateManager.generateTxMeta({
txParams: { txParams: {
from, from,

@ -0,0 +1,32 @@
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import CurrencyDisplay from '../../../currency-display'
import { ETH } from '../../../../constants/common'
export default class CancelTransaction extends PureComponent {
static propTypes = {
className: PropTypes.string,
value: PropTypes.string,
}
render () {
const { className, value } = this.props
console.log('VALUE', value)
return (
<div className={classnames('cancel-transaction-gas-fee', className)}>
<CurrencyDisplay
className="cancel-transaction-gas-fee__eth"
currency={ETH}
value={value}
numberOfDecimals={6}
/>
<CurrencyDisplay
className="cancel-transaction-gas-fee__fiat"
value={value}
/>
</div>
)
}
}

@ -0,0 +1 @@
export { default } from './cancel-transaction-gas-fee.component'

@ -0,0 +1,17 @@
.cancel-transaction-gas-fee {
background: #F1F4F9;
padding: 16px;
display: flex;
flex-direction: column;
align-items: center;
padding: 12px;
&__eth {
font-size: 1.5rem;
font-weight: 500;
}
&__fiat {
font-size: .75rem;
}
}

@ -0,0 +1,71 @@
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import Modal from '../../modal'
import CancelTransactionGasFee from './cancel-transaction-gas-fee'
import { SUBMITTED_STATUS } from '../../../constants/transactions'
import { decimalToHex } from '../../../helpers/conversions.util'
import { getHexGasTotal } from '../../../helpers/confirm-transaction/util'
export default class CancelTransaction extends PureComponent {
static contextTypes = {
t: PropTypes.func,
}
static propTypes = {
createCancelTransaction: PropTypes.func,
hideModal: PropTypes.func,
showTransactionConfirmedModal: PropTypes.func,
transactionStatus: PropTypes.string,
defaultNewGasPrice: PropTypes.string,
}
componentDidUpdate () {
const { transactionStatus, showTransactionConfirmedModal } = this.props
if (transactionStatus !== SUBMITTED_STATUS) {
showTransactionConfirmedModal()
return
}
}
handleSubmit = async () => {
const { createCancelTransaction, hideModal } = this.props
await createCancelTransaction()
hideModal()
}
handleCancel = () => {
this.props.hideModal()
}
render () {
const { t } = this.context
const { defaultNewGasPrice: gasPrice } = this.props
const newGasFee = getHexGasTotal({ gasPrice, gasLimit: decimalToHex(21000) })
return (
<Modal
headerText={t('attemptToCancel')}
onSubmit={this.handleSubmit}
onCancel={this.handleCancel}
submitText={t('yesLetsTry')}
cancelText={t('nevermind')}
submitType="secondary"
>
<div>
<div className="cancel-transaction__title">
{ t('cancellationGasFee') }
</div>
<CancelTransactionGasFee
className="cancel-transaction__cancel-transaction-gas-fee-container"
value={newGasFee}
/>
<div className="cancel-transaction__description">
{ t('attemptToCancelDescription') }
</div>
</div>
</Modal>
)
}
}

@ -0,0 +1,55 @@
import { connect } from 'react-redux'
import { compose } from 'recompose'
import R from 'ramda'
import { multiplyCurrencies } from '../../../conversion-util'
import { bnToHex } from '../../../helpers/conversions.util'
import withModalProps from '../../../higher-order-components/with-modal-props'
import CancelTransaction from './cancel-transaction.component'
import { showModal, hideModal, createCancelTransaction } from '../../../actions'
const mapStateToProps = (state, ownProps) => {
const { metamask } = state
const { transactionId, originalGasPrice } = ownProps
const { selectedAddressTxList } = metamask
const transaction = R.find(({ id }) => id === transactionId)(selectedAddressTxList)
const transactionStatus = transaction ? transaction.status : ''
const defaultNewGasPrice = bnToHex(multiplyCurrencies(originalGasPrice, 1.1))
return {
transactionId,
transactionStatus,
originalGasPrice,
defaultNewGasPrice,
}
}
const mapDispatchToProps = dispatch => {
return {
hideModal: () => dispatch(hideModal()),
createCancelTransaction: txId => dispatch(createCancelTransaction(txId)),
showTransactionConfirmedModal: () => dispatch(showModal({ name: 'TRANSACTION_CONFIRMED' })),
}
}
const mergeProps = (stateProps, dispatchProps, ownProps) => {
const { transactionId, ...restStateProps } = stateProps
const {
createCancelTransaction: dispatchCreateCancelTransaction,
...restDispatchProps
} = dispatchProps
return {
...restStateProps,
...restDispatchProps,
...ownProps,
createCancelTransaction: newGasPrice => {
return dispatchCreateCancelTransaction(transactionId, newGasPrice)
},
}
}
export default compose(
withModalProps,
connect(mapStateToProps, mapDispatchToProps, mergeProps),
)(CancelTransaction)

@ -0,0 +1 @@
export { default } from './cancel-transaction.container'

@ -0,0 +1,18 @@
@import './cancel-transaction-gas-fee/index';
.cancel-transaction {
&__title {
font-weight: 500;
padding-bottom: 16px;
text-align: center;
}
&__description {
text-align: center;
font-size: .875rem;
}
&__cancel-transaction-gas-fee-container {
margin-bottom: 16px;
}
}

@ -1,6 +1,6 @@
import React, { Component } from 'react' import React, { Component } from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import Button from '../../button' import Modal from '../../modal'
import { addressSummary } from '../../../util' import { addressSummary } from '../../../util'
import Identicon from '../../identicon' import Identicon from '../../identicon'
import genAccountLink from '../../../../lib/account-link' import genAccountLink from '../../../../lib/account-link'
@ -25,22 +25,22 @@ class ConfirmRemoveAccount extends Component {
renderSelectedAccount () { renderSelectedAccount () {
const { identity } = this.props const { identity } = this.props
return ( return (
<div className="modal-container__account"> <div className="confirm-remove-account__account">
<div className="modal-container__account__identicon"> <div className="confirm-remove-account__account__identicon">
<Identicon <Identicon
address={identity.address} address={identity.address}
diameter={32} diameter={32}
/> />
</div> </div>
<div className="modal-container__account__name"> <div className="confirm-remove-account__account__name">
<span className="modal-container__account__label">Name</span> <span className="confirm-remove-account__account__label">Name</span>
<span className="account_value">{identity.name}</span> <span className="account_value">{identity.name}</span>
</div> </div>
<div className="modal-container__account__address"> <div className="confirm-remove-account__account__address">
<span className="modal-container__account__label">Public Address</span> <span className="confirm-remove-account__account__label">Public Address</span>
<span className="account_value">{ addressSummary(identity.address, 4, 4) }</span> <span className="account_value">{ addressSummary(identity.address, 4, 4) }</span>
</div> </div>
<div className="modal-container__account__link"> <div className="confirm-remove-account__account__link">
<a <a
className="" className=""
href={genAccountLink(identity.address, this.props.network)} href={genAccountLink(identity.address, this.props.network)}
@ -58,34 +58,27 @@ class ConfirmRemoveAccount extends Component {
const { t } = this.context const { t } = this.context
return ( return (
<div className="modal-container"> <Modal
<div className="modal-container__content"> headerText={`${t('removeAccount')}?`}
<div className="modal-container__title"> onSubmit={() => this.handleRemove()}
{ `${t('removeAccount')}` }? onCancel={() => this.props.hideModal()}
</div> submitText={t('remove')}
cancelText={t('nevermind')}
submitType="secondary"
>
<div>
{ this.renderSelectedAccount() } { this.renderSelectedAccount() }
<div className="modal-container__description"> <div className="confirm-remove-account__description">
{ t('removeAccountDescription') } { t('removeAccountDescription') }
<a className="modal-container__link" rel="noopener noreferrer" target="_blank" href="https://consensys.zendesk.com/hc/en-us/articles/360004180111-What-are-imported-accounts-New-UI-">{ t('learnMore') }</a> <a
</div> className="confirm-remove-account__link"
</div> rel="noopener noreferrer"
<div className="modal-container__footer"> target="_blank" href="https://consensys.zendesk.com/hc/en-us/articles/360004180111-What-are-imported-accounts-New-UI-">
<Button { t('learnMore') }
type="default" </a>
className="modal-container__footer-button"
onClick={() => this.props.hideModal()}
>
{ t('nevermind') }
</Button>
<Button
type="secondary"
className="modal-container__footer-button"
onClick={() => this.handleRemove()}
>
{ t('remove') }
</Button>
</div> </div>
</div> </div>
</Modal>
) )
} }
} }

@ -1,11 +1,12 @@
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { compose } from 'recompose'
import ConfirmRemoveAccount from './confirm-remove-account.component' import ConfirmRemoveAccount from './confirm-remove-account.component'
import withModalProps from '../../../higher-order-components/with-modal-props'
const { hideModal, removeAccount } = require('../../../actions') const { hideModal, removeAccount } = require('../../../actions')
const mapStateToProps = state => { const mapStateToProps = state => {
return { return {
identity: state.appState.modal.modalState.props.identity,
network: state.metamask.network, network: state.metamask.network,
} }
} }
@ -17,4 +18,7 @@ const mapDispatchToProps = dispatch => {
} }
} }
export default connect(mapStateToProps, mapDispatchToProps)(ConfirmRemoveAccount) export default compose(
withModalProps,
connect(mapStateToProps, mapDispatchToProps)
)(ConfirmRemoveAccount)

@ -1,2 +1 @@
import ConfirmRemoveAccount from './confirm-remove-account.container' export { default } from './confirm-remove-account.container'
module.exports = ConfirmRemoveAccount

@ -0,0 +1,58 @@
.confirm-remove-account {
&__description {
text-align: center;
font-size: .875rem;
}
&__account {
border: 1px solid #b7b7b7;
border-radius: 4px;
padding: 10px;
display: flex;
margin-top: 10px;
margin-bottom: 20px;
width: 100%;
&__identicon {
margin-right: 10px;
}
&__name,
&__address {
margin-right: 10px;
font-size: 14px;
}
&__name {
width: 100px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
&__label {
font-size: 11px;
display: block;
color: #9b9b9b;
}
&__link {
margin-top: 14px;
img {
width: 15px;
height: 15px;
}
}
@media screen and (max-width: 575px) {
&__name {
width: 90px;
}
}
}
&__link {
color: #2f9ae0;
}
}

@ -1,8 +1,8 @@
import React, { Component } from 'react' import React, { PureComponent } from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import Button from '../../button' import Modal, { ModalContent } from '../../modal'
class ConfirmResetAccount extends Component { export default class ConfirmResetAccount extends PureComponent {
static propTypes = { static propTypes = {
hideModal: PropTypes.func.isRequired, hideModal: PropTypes.func.isRequired,
resetAccount: PropTypes.func.isRequired, resetAccount: PropTypes.func.isRequired,
@ -12,7 +12,7 @@ class ConfirmResetAccount extends Component {
t: PropTypes.func, t: PropTypes.func,
} }
handleReset () { handleReset = () => {
this.props.resetAccount() this.props.resetAccount()
.then(() => this.props.hideModal()) .then(() => this.props.hideModal())
} }
@ -21,34 +21,18 @@ class ConfirmResetAccount extends Component {
const { t } = this.context const { t } = this.context
return ( return (
<div className="modal-container"> <Modal
<div className="modal-container__content"> onSubmit={this.handleReset}
<div className="modal-container__title"> onCancel={() => this.props.hideModal()}
{ `${t('resetAccount')}?` } submitText={t('reset')}
</div> cancelText={t('nevermind')}
<div className="modal-container__description"> submitType="secondary"
{ t('resetAccountDescription') }
</div>
</div>
<div className="modal-container__footer">
<Button
type="default"
className="modal-container__footer-button"
onClick={() => this.props.hideModal()}
> >
{ t('nevermind') } <ModalContent
</Button> title={`${t('resetAccount')}?`}
<Button description={t('resetAccountDescription')}
type="secondary" />
className="modal-container__footer-button" </Modal>
onClick={() => this.handleReset()}
>
{ t('reset') }
</Button>
</div>
</div>
) )
} }
} }
export default ConfirmResetAccount

@ -1,13 +1,16 @@
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { compose } from 'recompose'
import withModalProps from '../../../higher-order-components/with-modal-props'
import ConfirmResetAccount from './confirm-reset-account.component' import ConfirmResetAccount from './confirm-reset-account.component'
import { resetAccount } from '../../../actions'
const { hideModal, resetAccount } = require('../../../actions')
const mapDispatchToProps = dispatch => { const mapDispatchToProps = dispatch => {
return { return {
hideModal: () => dispatch(hideModal()),
resetAccount: () => dispatch(resetAccount()), resetAccount: () => dispatch(resetAccount()),
} }
} }
export default connect(null, mapDispatchToProps)(ConfirmResetAccount) export default compose(
withModalProps,
connect(null, mapDispatchToProps)
)(ConfirmResetAccount)

@ -1,2 +1 @@
import ConfirmResetAccount from './confirm-reset-account.container' export { default } from './confirm-reset-account.container'
module.exports = ConfirmResetAccount

@ -1,108 +1,9 @@
@import './customize-gas/index'; @import './cancel-transaction/index';
@import './qr-scanner/index';
.modal-container {
width: 100%;
height: 100%;
background-color: #fff;
display: flex;
flex-flow: column;
border-radius: 8px;
&__title {
font-size: 1.5rem;
font-weight: 500;
padding: 16px 0;
text-align: center;
}
&__description {
text-align: center;
font-size: .875rem;
}
&__account {
border: 1px solid #b7b7b7;
border-radius: 4px;
padding: 10px;
display: flex;
margin-top: 10px;
margin-bottom: 20px;
width: 100%;
&__identicon {
margin-right: 10px;
}
&__name,
&__address {
margin-right: 10px;
font-size: 14px;
}
&__name { @import './confirm-remove-account/index';
width: 100px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
&__label { @import './customize-gas/index';
font-size: 11px;
display: block;
color: #9b9b9b;
}
&__link {
margin-top: 14px;
img {
width: 15px;
height: 15px;
}
}
@media screen and (max-width: 575px) {
&__name {
width: 90px;
}
}
}
&__link {
color: #2f9ae0;
}
&__content {
overflow-y: auto;
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
padding: 32px;
@media screen and (max-width: 575px) {
justify-content: center;
padding: 28px 20px;
}
}
&__footer {
display: flex;
flex-flow: row;
justify-content: center;
border-top: 1px solid #d2d8dd;
padding: 16px;
flex: 0 0 auto;
&-button { @import './qr-scanner/index';
min-width: 0;
margin-right: 16px;
&:last-of-type { @import './transaction-confirmed/index';
margin-right: 0;
}
}
}
}

@ -19,14 +19,14 @@ const ShapeshiftDepositTxModal = require('./shapeshift-deposit-tx-modal.js')
const HideTokenConfirmationModal = require('./hide-token-confirmation-modal') const HideTokenConfirmationModal = require('./hide-token-confirmation-modal')
const CustomizeGasModal = require('../customize-gas-modal') const CustomizeGasModal = require('../customize-gas-modal')
const NotifcationModal = require('./notification-modal') const NotifcationModal = require('./notification-modal')
const ConfirmResetAccount = require('./confirm-reset-account')
const ConfirmRemoveAccount = require('./confirm-remove-account')
const QRScanner = require('./qr-scanner') const QRScanner = require('./qr-scanner')
const TransactionConfirmed = require('./transaction-confirmed')
const WelcomeBeta = require('./welcome-beta')
const Notification = require('./notification')
import ConfirmRemoveAccount from './confirm-remove-account'
import ConfirmResetAccount from './confirm-reset-account'
import TransactionConfirmed from './transaction-confirmed'
import ConfirmCustomizeGasModal from './customize-gas' import ConfirmCustomizeGasModal from './customize-gas'
import CancelTransaction from './cancel-transaction'
import WelcomeBeta from './welcome-beta'
const modalContainerBaseStyle = { const modalContainerBaseStyle = {
transform: 'translate3d(-50%, 0, 0px)', transform: 'translate3d(-50%, 0, 0px)',
@ -199,11 +199,7 @@ const MODALS = {
}, },
BETA_UI_NOTIFICATION_MODAL: { BETA_UI_NOTIFICATION_MODAL: {
contents: [ contents: h(WelcomeBeta),
h(Notification, [
h(WelcomeBeta),
]),
],
mobileModalStyle: { mobileModalStyle: {
...modalContainerMobileStyle, ...modalContainerMobileStyle,
}, },
@ -307,9 +303,7 @@ const MODALS = {
}, },
CONFIRM_CUSTOMIZE_GAS: { CONFIRM_CUSTOMIZE_GAS: {
contents: [ contents: h(ConfirmCustomizeGasModal),
h(ConfirmCustomizeGasModal),
],
mobileModalStyle: { mobileModalStyle: {
width: '100vw', width: '100vw',
height: '100vh', height: '100vh',
@ -332,11 +326,7 @@ const MODALS = {
TRANSACTION_CONFIRMED: { TRANSACTION_CONFIRMED: {
disableBackdropClick: true, disableBackdropClick: true,
contents: [ contents: h(TransactionConfirmed),
h(Notification, [
h(TransactionConfirmed),
]),
],
mobileModalStyle: { mobileModalStyle: {
...modalContainerMobileStyle, ...modalContainerMobileStyle,
}, },
@ -347,6 +337,7 @@ const MODALS = {
borderRadius: '8px', borderRadius: '8px',
}, },
}, },
QR_SCANNER: { QR_SCANNER: {
contents: h(QRScanner), contents: h(QRScanner),
mobileModalStyle: { mobileModalStyle: {
@ -360,6 +351,19 @@ const MODALS = {
}, },
}, },
CANCEL_TRANSACTION: {
contents: h(CancelTransaction),
mobileModalStyle: {
...modalContainerMobileStyle,
},
laptopModalStyle: {
...modalContainerLaptopStyle,
},
contentStyle: {
borderRadius: '8px',
},
},
DEFAULT: { DEFAULT: {
contents: [], contents: [],
mobileModalStyle: {}, mobileModalStyle: {},

@ -1,2 +0,0 @@
import Notification from './notification.container'
module.exports = Notification

@ -1,30 +0,0 @@
import React from 'react'
import PropTypes from 'prop-types'
import Button from '../../button'
const Notification = (props, context) => {
return (
<div className="modal-container">
{ props.children }
<div className="modal-container__footer">
<Button
type="primary"
onClick={() => props.onHide()}
>
{ context.t('ok') }
</Button>
</div>
</div>
)
}
Notification.propTypes = {
onHide: PropTypes.func.isRequired,
children: PropTypes.element,
}
Notification.contextTypes = {
t: PropTypes.func,
}
export default Notification

@ -1,38 +0,0 @@
import { connect } from 'react-redux'
import Notification from './notification.component'
const { hideModal } = require('../../../actions')
const mapStateToProps = state => {
const { appState: { modal: { modalState: { props } } } } = state
const { onHide } = props
return {
onHide,
}
}
const mapDispatchToProps = dispatch => {
return {
hideModal: () => dispatch(hideModal()),
}
}
const mergeProps = (stateProps, dispatchProps, ownProps) => {
const { onHide, ...otherStateProps } = stateProps
const { hideModal, ...otherDispatchProps } = dispatchProps
return {
...otherStateProps,
...otherDispatchProps,
...ownProps,
onHide: () => {
hideModal()
if (onHide && typeof onHide === 'function') {
onHide()
}
},
}
}
export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(Notification)

@ -1,2 +1 @@
import TransactionConfirmed from './transaction-confirmed.component' export { default } from './transaction-confirmed.container'
module.exports = TransactionConfirmed

@ -0,0 +1,22 @@
.transaction-confirmed {
&__title {
font-size: 1.5rem;
font-weight: 500;
padding: 16px 0;
text-align: center;
}
&__description {
text-align: center;
font-size: .875rem;
}
&__content {
overflow-y: auto;
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
padding: 16px;
}
}

@ -1,24 +1,45 @@
import React from 'react' import React, { PureComponent } from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import Modal from '../../modal'
const TransactionConfirmed = (props, context) => { export default class TransactionConfirmed extends PureComponent {
const { t } = context static contextTypes = {
t: PropTypes.func,
}
static propTypes = {
onSubmit: PropTypes.func,
hideModal: PropTypes.func,
}
handleSubmit = () => {
const { hideModal, onSubmit } = this.props
hideModal()
if (onSubmit && typeof onSubmit === 'function') {
onSubmit()
}
}
render () {
const { t } = this.context
return ( return (
<div className="modal-container__content"> <Modal
onSubmit={this.handleSubmit}
submitText={t('ok')}
>
<div className="transaction-confirmed__content">
<img src="images/check-icon.svg" /> <img src="images/check-icon.svg" />
<div className="modal-container__title"> <div className="transaction-confirmed__title">
{ `${t('confirmed')}!` } { `${t('confirmed')}!` }
</div> </div>
<div className="modal-container__description"> <div className="transaction-confirmed__description">
{ t('initialTransactionConfirmed') } { t('initialTransactionConfirmed') }
</div> </div>
</div> </div>
</Modal>
) )
}
} }
TransactionConfirmed.contextTypes = {
t: PropTypes.func,
}
export default TransactionConfirmed

@ -0,0 +1,4 @@
import TransactionConfirmed from './transaction-confirmed.component'
import withModalProps from '../../../higher-order-components/with-modal-props'
export default withModalProps(TransactionConfirmed)

@ -1,2 +1 @@
import WelcomeBeta from './welcome-beta.component' export { default } from './welcome-beta.container'
module.exports = WelcomeBeta

@ -1,18 +1,21 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import Modal, { ModalContent } from '../../modal'
const TransactionConfirmed = (props, context) => { const TransactionConfirmed = (props, context) => {
const { t } = context const { t } = context
const { hideModal } = props
return ( return (
<div className="modal-container__content"> <Modal
<div className="modal-container__title"> onSubmit={() => hideModal()}
{ `${t('uiWelcome')}` } submitText={t('ok')}
</div> >
<div className="modal-container__description"> <ModalContent
{ t('uiWelcomeMessage') } title={t('uiWelcome')}
</div> description={t('uiWelcomeMessage')}
</div> />
</Modal>
) )
} }
@ -20,4 +23,8 @@ TransactionConfirmed.contextTypes = {
t: PropTypes.func, t: PropTypes.func,
} }
TransactionConfirmed.propTypes = {
hideModal: PropTypes.func,
}
export default TransactionConfirmed export default TransactionConfirmed

@ -0,0 +1,4 @@
import WelcomeBeta from './welcome-beta.component'
import withModalProps from '../../../higher-order-components/with-modal-props'
export default withModalProps(WelcomeBeta)

@ -8,6 +8,7 @@ import {
INSUFFICIENT_FUNDS_ERROR_KEY, INSUFFICIENT_FUNDS_ERROR_KEY,
TRANSACTION_ERROR_KEY, TRANSACTION_ERROR_KEY,
} from '../../../constants/error-keys' } from '../../../constants/error-keys'
import { CONFIRMED_STATUS, DROPPED_STATUS } from '../../../constants/transactions'
export default class ConfirmTransactionBase extends Component { export default class ConfirmTransactionBase extends Component {
static contextTypes = { static contextTypes = {
@ -85,9 +86,9 @@ export default class ConfirmTransactionBase extends Component {
clearConfirmTransaction, clearConfirmTransaction,
} = this.props } = this.props
if (transactionStatus === 'dropped') { if (transactionStatus === DROPPED_STATUS || transactionStatus === CONFIRMED_STATUS) {
showTransactionConfirmedModal({ showTransactionConfirmedModal({
onHide: () => { onSubmit: () => {
clearConfirmTransaction() clearConfirmTransaction()
history.push(DEFAULT_ROUTE) history.push(DEFAULT_ROUTE)
}, },

@ -97,8 +97,8 @@ const mapDispatchToProps = dispatch => {
return { return {
clearConfirmTransaction: () => dispatch(clearConfirmTransaction()), clearConfirmTransaction: () => dispatch(clearConfirmTransaction()),
clearSend: () => dispatch(clearSend()), clearSend: () => dispatch(clearSend()),
showTransactionConfirmedModal: ({ onHide }) => { showTransactionConfirmedModal: ({ onSubmit }) => {
return dispatch(showModal({ name: 'TRANSACTION_CONFIRMED', onHide })) return dispatch(showModal({ name: 'TRANSACTION_CONFIRMED', onSubmit }))
}, },
showCustomizeGasModal: ({ txData, onSubmit, validate }) => { showCustomizeGasModal: ({ txData, onSubmit, validate }) => {
return dispatch(showModal({ name: 'CONFIRM_CUSTOMIZE_GAS', txData, onSubmit, validate })) return dispatch(showModal({ name: 'CONFIRM_CUSTOMIZE_GAS', txData, onSubmit, validate }))

@ -13,7 +13,9 @@ export default class TransactionListItemDetails extends PureComponent {
} }
static propTypes = { static propTypes = {
onCancel: PropTypes.func,
onRetry: PropTypes.func, onRetry: PropTypes.func,
showCancel: PropTypes.bool,
showRetry: PropTypes.bool, showRetry: PropTypes.bool,
transaction: PropTypes.object, transaction: PropTypes.object,
} }
@ -27,6 +29,13 @@ export default class TransactionListItemDetails extends PureComponent {
this.setState({ showTransactionDetails: true }) this.setState({ showTransactionDetails: true })
} }
handleCancel = event => {
const { onCancel } = this.props
event.stopPropagation()
onCancel()
}
handleRetry = event => { handleRetry = event => {
const { onRetry } = this.props const { onRetry } = this.props
@ -36,7 +45,7 @@ export default class TransactionListItemDetails extends PureComponent {
render () { render () {
const { t } = this.context const { t } = this.context
const { transaction, showRetry } = this.props const { transaction, showCancel, showRetry } = this.props
const { txParams: { to, from } = {} } = transaction const { txParams: { to, from } = {} } = transaction
return ( return (
@ -55,6 +64,17 @@ export default class TransactionListItemDetails extends PureComponent {
</Button> </Button>
) )
} }
{
showCancel && (
<Button
type="raised"
onClick={this.handleCancel}
className="transaction-list-item-details__header-button"
>
{ t('cancel') }
</Button>
)
}
<Button <Button
type="raised" type="raised"
onClick={this.handleEtherscanClick} onClick={this.handleEtherscanClick}

@ -12,17 +12,19 @@ import { ETH } from '../../constants/common'
export default class TransactionListItem extends PureComponent { export default class TransactionListItem extends PureComponent {
static propTypes = { static propTypes = {
assetImages: PropTypes.object,
history: PropTypes.object, history: PropTypes.object,
transaction: PropTypes.object,
value: PropTypes.string,
methodData: PropTypes.object, methodData: PropTypes.object,
showRetry: PropTypes.bool, nonceAndDate: PropTypes.string,
retryTransaction: PropTypes.func, retryTransaction: PropTypes.func,
setSelectedToken: PropTypes.func, setSelectedToken: PropTypes.func,
nonceAndDate: PropTypes.string, showCancelModal: PropTypes.func,
showCancel: PropTypes.bool,
showRetry: PropTypes.bool,
token: PropTypes.object, token: PropTypes.object,
assetImages: PropTypes.object,
tokenData: PropTypes.object, tokenData: PropTypes.object,
transaction: PropTypes.object,
value: PropTypes.string,
} }
state = { state = {
@ -42,6 +44,11 @@ export default class TransactionListItem extends PureComponent {
this.setState({ showTransactionDetails: !showTransactionDetails }) this.setState({ showTransactionDetails: !showTransactionDetails })
} }
handleCancel = () => {
const { transaction: { id, txParams: { gasPrice } } = {}, showCancelModal } = this.props
showCancelModal(id, gasPrice)
}
handleRetry = () => { handleRetry = () => {
const { const {
transaction: { txParams: { to } = {} }, transaction: { txParams: { to } = {} },
@ -100,12 +107,13 @@ export default class TransactionListItem extends PureComponent {
render () { render () {
const { const {
transaction, assetImages,
methodData, methodData,
showRetry,
nonceAndDate, nonceAndDate,
assetImages, showCancel,
showRetry,
tokenData, tokenData,
transaction,
} = this.props } = this.props
const { txParams = {} } = transaction const { txParams = {} } = transaction
const { showTransactionDetails } = this.state const { showTransactionDetails } = this.state
@ -153,8 +161,10 @@ export default class TransactionListItem extends PureComponent {
<div className="transaction-list-item__details-container"> <div className="transaction-list-item__details-container">
<TransactionListItemDetails <TransactionListItemDetails
transaction={transaction} transaction={transaction}
showRetry={showRetry && methodData.done}
onRetry={this.handleRetry} onRetry={this.handleRetry}
showRetry={showRetry && methodData.done}
onCancel={this.handleCancel}
showCancel={showCancel}
/> />
</div> </div>
) )

@ -3,7 +3,7 @@ import { withRouter } from 'react-router-dom'
import { compose } from 'recompose' import { compose } from 'recompose'
import withMethodData from '../../higher-order-components/with-method-data' import withMethodData from '../../higher-order-components/with-method-data'
import TransactionListItem from './transaction-list-item.component' import TransactionListItem from './transaction-list-item.component'
import { setSelectedToken, retryTransaction } from '../../actions' import { setSelectedToken, retryTransaction, showModal } from '../../actions'
import { hexToDecimal } from '../../helpers/conversions.util' import { hexToDecimal } from '../../helpers/conversions.util'
import { getTokenData } from '../../helpers/transactions.util' import { getTokenData } from '../../helpers/transactions.util'
import { formatDate } from '../../util' import { formatDate } from '../../util'
@ -25,6 +25,9 @@ const mapDispatchToProps = dispatch => {
return { return {
setSelectedToken: tokenAddress => dispatch(setSelectedToken(tokenAddress)), setSelectedToken: tokenAddress => dispatch(setSelectedToken(tokenAddress)),
retryTransaction: transactionId => dispatch(retryTransaction(transactionId)), retryTransaction: transactionId => dispatch(retryTransaction(transactionId)),
showCancelModal: (transactionId, originalGasPrice) => {
return dispatch(showModal({ name: 'CANCEL_TRANSACTION', transactionId, originalGasPrice }))
},
} }
} }

@ -56,7 +56,7 @@ export default class TransactionList extends PureComponent {
</div> </div>
{ {
pendingTransactions.map((transaction, index) => ( pendingTransactions.map((transaction, index) => (
this.renderTransaction(transaction, index) this.renderTransaction(transaction, index, true)
)) ))
} }
</div> </div>
@ -78,7 +78,7 @@ export default class TransactionList extends PureComponent {
) )
} }
renderTransaction (transaction, index) { renderTransaction (transaction, index, showCancel) {
const { selectedToken, assetImages } = this.props const { selectedToken, assetImages } = this.props
return transaction.key === TRANSACTION_TYPE_SHAPESHIFT return transaction.key === TRANSACTION_TYPE_SHAPESHIFT
@ -92,6 +92,7 @@ export default class TransactionList extends PureComponent {
transaction={transaction} transaction={transaction}
key={transaction.id} key={transaction.id}
showRetry={this.shouldShowRetry(transaction)} showRetry={this.shouldShowRetry(transaction)}
showCancel={showCancel}
token={selectedToken} token={selectedToken}
assetImages={assetImages} assetImages={assetImages}
/> />

@ -104,7 +104,7 @@ ConfirmTxScreen.prototype.componentDidUpdate = function (prevProps) {
if (prevTx && prevTx.status === 'dropped') { if (prevTx && prevTx.status === 'dropped') {
this.props.dispatch(actions.showModal({ this.props.dispatch(actions.showModal({
name: 'TRANSACTION_CONFIRMED', name: 'TRANSACTION_CONFIRMED',
onHide: () => history.push(DEFAULT_ROUTE), onSubmit: () => history.push(DEFAULT_ROUTE),
})) }))
return return

@ -18,5 +18,6 @@ export const SEND_TOKEN_ACTION_KEY = 'sentTokens'
export const TRANSFER_FROM_ACTION_KEY = 'transferFrom' export const TRANSFER_FROM_ACTION_KEY = 'transferFrom'
export const SIGNATURE_REQUEST_KEY = 'signatureRequest' export const SIGNATURE_REQUEST_KEY = 'signatureRequest'
export const UNKNOWN_FUNCTION_KEY = 'unknownFunction' export const UNKNOWN_FUNCTION_KEY = 'unknownFunction'
export const CANCEL_ATTEMPT_ACTION_KEY = 'cancelAttempt'
export const TRANSACTION_TYPE_SHAPESHIFT = 'shapeshift' export const TRANSACTION_TYPE_SHAPESHIFT = 'shapeshift'

@ -1,6 +1,11 @@
import ethUtil from 'ethereumjs-util'
import { conversionUtil } from '../conversion-util' import { conversionUtil } from '../conversion-util'
import { ETH, GWEI, WEI } from '../constants/common' import { ETH, GWEI, WEI } from '../constants/common'
export function bnToHex (inputBn) {
return ethUtil.addHexPrefix(inputBn.toString(16))
}
export function hexToDecimal (hexValue) { export function hexToDecimal (hexValue) {
return conversionUtil(hexValue, { return conversionUtil(hexValue, {
fromNumericBase: 'hex', fromNumericBase: 'hex',
@ -8,6 +13,13 @@ export function hexToDecimal (hexValue) {
}) })
} }
export function decimalToHex (decimal) {
return conversionUtil(decimal, {
fromNumericBase: 'dec',
toNumericBase: 'hex',
})
}
export function getEthConversionFromWeiHex ({ value, conversionRate, numberOfDecimals = 6 }) { export function getEthConversionFromWeiHex ({ value, conversionRate, numberOfDecimals = 6 }) {
const denominations = [ETH, GWEI, WEI] const denominations = [ETH, GWEI, WEI]

@ -14,6 +14,7 @@ import {
TRANSFER_FROM_ACTION_KEY, TRANSFER_FROM_ACTION_KEY,
SIGNATURE_REQUEST_KEY, SIGNATURE_REQUEST_KEY,
UNKNOWN_FUNCTION_KEY, UNKNOWN_FUNCTION_KEY,
CANCEL_ATTEMPT_ACTION_KEY,
} from '../constants/transactions' } from '../constants/transactions'
import { addCurrencies } from '../conversion-util' import { addCurrencies } from '../conversion-util'
@ -44,7 +45,11 @@ export function isConfirmDeployContract (txData = {}) {
} }
export async function getTransactionActionKey (transaction, methodData) { export async function getTransactionActionKey (transaction, methodData) {
const { txParams: { data, to } = {}, msgParams } = transaction const { txParams: { data, to } = {}, msgParams, type } = transaction
if (type === 'cancel') {
return CANCEL_ATTEMPT_ACTION_KEY
}
if (msgParams) { if (msgParams) {
return SIGNATURE_REQUEST_KEY return SIGNATURE_REQUEST_KEY

Loading…
Cancel
Save