1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 01:39:44 +01:00

Add new alert modals

This commit is contained in:
Alexander Tseung 2018-05-30 16:17:40 -07:00 committed by Alexander Tseung
parent f4d833cb09
commit cc73d869fe
21 changed files with 309 additions and 178 deletions

View File

@ -523,6 +523,9 @@
"networks": { "networks": {
"message": "Networks" "message": "Networks"
}, },
"nevermind": {
"message": "Nevermind"
},
"newAccount": { "newAccount": {
"message": "New Account" "message": "New Account"
}, },
@ -637,9 +640,15 @@
"rejected": { "rejected": {
"message": "Rejected" "message": "Rejected"
}, },
"reset": {
"message": "Reset"
},
"resetAccount": { "resetAccount": {
"message": "Reset Account" "message": "Reset Account"
}, },
"resetAccountDescription": {
"message": "Resetting your account will clear your transaction history."
},
"restoreFromSeed": { "restoreFromSeed": {
"message": "Restore account?" "message": "Restore account?"
}, },
@ -897,7 +906,7 @@
"message": "Welcome to the New UI (Beta)" "message": "Welcome to the New UI (Beta)"
}, },
"uiWelcomeMessage": { "uiWelcomeMessage": {
"message": "You are now using the new Metamask UI. Take a look around, try out new features like sending tokens, and let us know if you have any issues." "message": "You are now using the new Metamask UI."
}, },
"unapproved": { "unapproved": {
"message": "Unapproved" "message": "Unapproved"

View File

@ -43,7 +43,7 @@ async function runAddTokenFlowTest (assert, done) {
assert.equal(addTokenTitle[0].textContent, 'Add Tokens', 'add token title is correct') assert.equal(addTokenTitle[0].textContent, 'Add Tokens', 'add token title is correct')
// Cancel Add Token // Cancel Add Token
const cancelAddTokenButton = await queryAsync($, 'button.btn-secondary--lg.page-container__footer-button') const cancelAddTokenButton = await queryAsync($, 'button.btn-default.btn--large.page-container__footer-button')
assert.ok(cancelAddTokenButton[0], 'cancel add token button present') assert.ok(cancelAddTokenButton[0], 'cancel add token button present')
cancelAddTokenButton.click() cancelAddTokenButton.click()
@ -75,15 +75,15 @@ async function runAddTokenFlowTest (assert, done) {
tokenWrapper[0].click() tokenWrapper[0].click()
// Click Next button // Click Next button
let nextButton = await queryAsync($, 'button.btn-primary--lg') let nextButton = await queryAsync($, 'button.btn-primary.btn--large')
assert.equal(nextButton[0].textContent, 'Next', 'next button rendered') assert.equal(nextButton[0].textContent, 'Next', 'next button rendered')
nextButton[0].click() nextButton[0].click()
// Confirm Add token // Confirm Add token
const confirmAddToken = await queryAsync($, '.confirm-add-token') const confirmAddToken = await queryAsync($, '.confirm-add-token')
assert.ok(confirmAddToken[0], 'confirm add token rendered') assert.ok(confirmAddToken[0], 'confirm add token rendered')
assert.ok($('button.btn-primary--lg')[0], 'confirm add token button found') assert.ok($('button.btn-primary.btn--large')[0], 'confirm add token button found')
$('button.btn-primary--lg')[0].click() $('button.btn-primary.btn--large')[0].click()
// Verify added token image // Verify added token image
let heroBalance = await queryAsync($, '.hero-balance') let heroBalance = await queryAsync($, '.hero-balance')
@ -120,7 +120,7 @@ async function runAddTokenFlowTest (assert, done) {
const errorMessage = await queryAsync($, '#custom-symbol-helper-text') const errorMessage = await queryAsync($, '#custom-symbol-helper-text')
assert.ok(errorMessage[0], 'error rendered') assert.ok(errorMessage[0], 'error rendered')
$('button.btn-secondary--lg')[0].click() $('button.btn-default.btn--large')[0].click()
// await timeout(100000) // await timeout(100000)

View File

@ -38,7 +38,7 @@ async function runConfirmSigRequestsTest(assert, done) {
let confirmSigRowValue = await queryAsync($, '.request-signature__row-value') let confirmSigRowValue = await queryAsync($, '.request-signature__row-value')
assert.equal(confirmSigRowValue[0].textContent, '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0') assert.equal(confirmSigRowValue[0].textContent, '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0')
let confirmSigSignButton = await queryAsync($, 'button.btn-primary--lg') let confirmSigSignButton = await queryAsync($, 'button.btn-primary.btn--large')
confirmSigSignButton[0].click() confirmSigSignButton[0].click()
confirmSigHeadline = await queryAsync($, '.request-signature__headline') confirmSigHeadline = await queryAsync($, '.request-signature__headline')
@ -47,7 +47,7 @@ async function runConfirmSigRequestsTest(assert, done) {
confirmSigRowValue = await queryAsync($, '.request-signature__row-value') confirmSigRowValue = await queryAsync($, '.request-signature__row-value')
assert.ok(confirmSigRowValue[0].textContent.match(/^\#\sTerms\sof\sUse/)) assert.ok(confirmSigRowValue[0].textContent.match(/^\#\sTerms\sof\sUse/))
confirmSigSignButton = await queryAsync($, 'button.btn-primary--lg') confirmSigSignButton = await queryAsync($, 'button.btn-primary.btn--large')
confirmSigSignButton[0].click() confirmSigSignButton[0].click()
confirmSigHeadline = await queryAsync($, '.request-signature__headline') confirmSigHeadline = await queryAsync($, '.request-signature__headline')
@ -57,7 +57,7 @@ async function runConfirmSigRequestsTest(assert, done) {
assert.equal(confirmSigRowValue[0].textContent, 'Hi, Alice!') assert.equal(confirmSigRowValue[0].textContent, 'Hi, Alice!')
assert.equal(confirmSigRowValue[1].textContent, '1337') assert.equal(confirmSigRowValue[1].textContent, '1337')
confirmSigSignButton = await queryAsync($, 'button.btn-primary--lg') confirmSigSignButton = await queryAsync($, 'button.btn-primary.btn--large')
confirmSigSignButton[0].click() confirmSigSignButton[0].click()
const txView = await queryAsync($, '.tx-view') const txView = await queryAsync($, '.tx-view')

View File

@ -129,7 +129,7 @@ async function runSendFlowTest(assert, done) {
await customizeGas(assert, 0, 21000, '0', '$0.00 USD') await customizeGas(assert, 0, 21000, '0', '$0.00 USD')
await customizeGas(assert, 500, 60000, '0.003', '$3.60 USD') await customizeGas(assert, 500, 60000, '0.003', '$3.60 USD')
const sendButton = await queryAsync($, 'button.btn-primary--lg.page-container__footer-button') const sendButton = await queryAsync($, 'button.btn-primary.btn--large.page-container__footer-button')
assert.equal(sendButton[0].textContent, 'Next', 'next button rendered') assert.equal(sendButton[0].textContent, 'Next', 'next button rendered')
sendButton[0].click() sendButton[0].click()
await timeout() await timeout()
@ -169,13 +169,13 @@ async function runSendFlowTest(assert, done) {
sendAmountFieldInputInEdit.val('1.0') sendAmountFieldInputInEdit.val('1.0')
reactTriggerChange(sendAmountFieldInputInEdit[0]) reactTriggerChange(sendAmountFieldInputInEdit[0])
const sendButtonInEdit = await queryAsync($, '.btn-primary--lg.page-container__footer-button') const sendButtonInEdit = await queryAsync($, '.btn-primary.btn--large.page-container__footer-button')
assert.equal(sendButtonInEdit[0].textContent, 'Next', 'next button in edit rendered') assert.equal(sendButtonInEdit[0].textContent, 'Next', 'next button in edit rendered')
selectState.val('send new ui') selectState.val('send new ui')
reactTriggerChange(selectState[0]) reactTriggerChange(selectState[0])
const cancelButtonInEdit = await queryAsync($, '.btn-secondary--lg.page-container__footer-button') const cancelButtonInEdit = await queryAsync($, '.btn-default.btn--large.page-container__footer-button')
cancelButtonInEdit[0].click() cancelButtonInEdit[0].click()
// sendButtonInEdit[0].click() // sendButtonInEdit[0].click()

View File

@ -163,7 +163,7 @@ async function captureAllScreens() {
await delay(300) await delay(300)
await captureLanguageScreenShots('metamask account detail export private key screen - password entered') await captureLanguageScreenShots('metamask account detail export private key screen - password entered')
await driver.findElement(By.css('.btn-primary--lg.export-private-key__button')).click() await driver.findElement(By.css('.btn-primary.btn--large.export-private-key__button')).click()
await delay(300) await delay(300)
await captureLanguageScreenShots('metamask account detail export private key screen - reveal key') await captureLanguageScreenShots('metamask account detail export private key screen - reveal key')

View File

@ -503,15 +503,21 @@ function requestRevealSeedWords (password) {
} }
function resetAccount () { function resetAccount () {
return (dispatch) => { return dispatch => {
dispatch(actions.showLoadingIndication())
return new Promise((resolve, reject) => {
background.resetAccount((err, account) => { background.resetAccount((err, account) => {
dispatch(actions.hideLoadingIndication()) dispatch(actions.hideLoadingIndication())
if (err) { if (err) {
dispatch(actions.displayWarning(err.message)) dispatch(actions.displayWarning(err.message))
return reject(err)
} }
log.info('Transaction history reset for ' + account) log.info('Transaction history reset for ' + account)
dispatch(actions.showAccountsPage()) dispatch(actions.showAccountsPage())
resolve(account)
})
}) })
} }
} }

View File

@ -0,0 +1,54 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Button from '../../button'
class ConfirmResetAccount extends Component {
static propTypes = {
hideModal: PropTypes.func.isRequired,
resetAccount: PropTypes.func.isRequired,
}
static contextTypes = {
t: PropTypes.func,
}
handleReset () {
this.props.resetAccount()
.then(() => this.props.hideModal())
}
render () {
const { t } = this.context
return (
<div className="modal-container">
<div className="modal-container__content">
<div className="modal-container__title">
{ `${t('resetAccount')}?` }
</div>
<div className="modal-container__description">
{ t('resetAccountDescription') }
</div>
</div>
<div className="modal-container__footer">
<Button
type="default"
className="modal-container__footer-button"
onClick={() => this.props.hideModal()}
>
{ t('nevermind') }
</Button>
<Button
type="secondary"
className="modal-container__footer-button"
onClick={() => this.handleReset()}
>
{ t('reset') }
</Button>
</div>
</div>
)
}
}
export default ConfirmResetAccount

View File

@ -0,0 +1,13 @@
import { connect } from 'react-redux'
import ConfirmResetAccount from './confirm-reset-account.component'
const { hideModal, resetAccount } = require('../../../actions')
const mapDispatchToProps = dispatch => {
return {
hideModal: () => dispatch(hideModal()),
resetAccount: () => dispatch(resetAccount()),
}
}
export default connect(null, mapDispatchToProps)(ConfirmResetAccount)

View File

@ -0,0 +1,2 @@
import ConfirmResetAccount from './confirm-reset-account.container'
module.exports = ConfirmResetAccount

View File

@ -1 +1,52 @@
@import './transaction-confirmed/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;
}
&__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 {
min-width: 0;
margin-right: 16px;
&:last-of-type {
margin-right: 0;
}
}
}
}

View File

@ -19,8 +19,30 @@ 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('./notification-modals/confirm-reset-account') const ConfirmResetAccount = require('./confirm-reset-account')
const TransactionConfirmed = require('./transaction-confirmed') const TransactionConfirmed = require('./transaction-confirmed')
const WelcomeBeta = require('./welcome-beta')
const Notification = require('./notification')
const modalContainerBaseStyle = {
transform: 'translate3d(-50%, 0, 0px)',
border: '1px solid #CCCFD1',
borderRadius: '8px',
backgroundColor: '#FFFFFF',
boxShadow: '0 2px 22px 0 rgba(0,0,0,0.2)',
}
const modalContainerLaptopStyle = {
...modalContainerBaseStyle,
width: '344px',
top: '15%',
}
const modalContainerMobileStyle = {
...modalContainerBaseStyle,
width: '309px',
top: '12.5%',
}
const accountModalStyle = { const accountModalStyle = {
mobileModalStyle: { mobileModalStyle: {
@ -174,18 +196,18 @@ const MODALS = {
BETA_UI_NOTIFICATION_MODAL: { BETA_UI_NOTIFICATION_MODAL: {
contents: [ contents: [
h(NotifcationModal, { h(Notification, [
header: 'uiWelcome', h(WelcomeBeta),
message: 'uiWelcomeMessage', ]),
}),
], ],
mobileModalStyle: { mobileModalStyle: {
width: '95%', ...modalContainerMobileStyle,
top: getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP ? '52vh' : '36.5vh',
}, },
laptopModalStyle: { laptopModalStyle: {
width: '449px', ...modalContainerLaptopStyle,
top: 'calc(33% + 45px)', },
contentStyle: {
borderRadius: '8px',
}, },
}, },
@ -209,12 +231,13 @@ const MODALS = {
CONFIRM_RESET_ACCOUNT: { CONFIRM_RESET_ACCOUNT: {
contents: h(ConfirmResetAccount), contents: h(ConfirmResetAccount),
mobileModalStyle: { mobileModalStyle: {
width: '95%', ...modalContainerMobileStyle,
top: getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP ? '52vh' : '36.5vh',
}, },
laptopModalStyle: { laptopModalStyle: {
width: '473px', ...modalContainerLaptopStyle,
top: 'calc(33% + 45px)', },
contentStyle: {
borderRadius: '8px',
}, },
}, },
@ -269,31 +292,18 @@ const MODALS = {
TRANSACTION_CONFIRMED: { TRANSACTION_CONFIRMED: {
disableBackdropClick: true, disableBackdropClick: true,
contents: [ contents: [
h(TransactionConfirmed, {}, []), h(Notification, [
h(TransactionConfirmed),
]),
], ],
mobileModalStyle: { mobileModalStyle: {
width: '100%', ...modalContainerMobileStyle,
height: '100%',
transform: 'none',
left: '0',
right: '0',
margin: '0 auto',
boxShadow: '0 0 7px 0 rgba(0,0,0,0.08)',
top: '0',
display: 'flex',
}, },
laptopModalStyle: { laptopModalStyle: {
width: '344px', ...modalContainerLaptopStyle,
transform: 'translate3d(-50%, 0, 0px)',
top: '15%',
border: '1px solid #CCCFD1',
borderRadius: '8px',
backgroundColor: '#FFFFFF',
boxShadow: '0 2px 22px 0 rgba(0,0,0,0.2)',
}, },
contentStyle: { contentStyle: {
borderRadius: '8px', borderRadius: '8px',
height: '100%',
}, },
}, },

View File

@ -1,46 +0,0 @@
const { Component } = require('react')
const PropTypes = require('prop-types')
const h = require('react-hyperscript')
const connect = require('react-redux').connect
const actions = require('../../../actions')
const NotifcationModal = require('../notification-modal')
class ConfirmResetAccount extends Component {
render () {
const { resetAccount } = this.props
return h(NotifcationModal, {
header: 'Are you sure you want to reset account?',
message: h('div', [
h('span', `Resetting is for developer use only. This button wipes the current account's transaction history,
which is used to calculate the current account nonce. `),
h('a.notification-modal__link', {
href: 'http://metamask.helpscoutdocs.com/article/36-resetting-an-account',
target: '_blank',
onClick (event) { global.platform.openWindow({ url: event.target.href }) },
}, 'Read more.'),
]),
showCancelButton: true,
showConfirmButton: true,
onConfirm: resetAccount,
})
}
}
ConfirmResetAccount.propTypes = {
resetAccount: PropTypes.func,
}
const mapDispatchToProps = dispatch => {
return {
resetAccount: () => {
dispatch(actions.resetAccount())
},
}
}
module.exports = connect(null, mapDispatchToProps)(ConfirmResetAccount)

View File

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

View File

@ -0,0 +1,30 @@
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

View File

@ -0,0 +1,38 @@
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)

View File

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

View File

@ -1,21 +0,0 @@
.transaction-confirmed {
display: flex;
flex-direction: column;
align-items: center;
padding: 32px;
&__title {
font-size: 2rem;
padding: 16px 0;
}
&__description {
text-align: center;
font-size: .875rem;
line-height: 1.5rem;
}
@media screen and (max-width: 575px) {
justify-content: center;
}
}

View File

@ -1,42 +1,20 @@
import React, { Component } from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import Button from '../../button'
class TransactionConfirmed extends Component { const TransactionConfirmed = (props, context) => {
render () { const { t } = context
const { t } = this.context
return ( return (
<div className="page-container page-container--full-width page-container--full-height"> <div className="modal-container__content">
<div className="page-container__content transaction-confirmed">
<img src="images/check-icon.svg" /> <img src="images/check-icon.svg" />
<div className="transaction-confirmed__title"> <div className="modal-container__title">
{ `${t('confirmed')}!` } { `${t('confirmed')}!` }
</div> </div>
<div className="transaction-confirmed__description"> <div className="modal-container__description">
{ t('initialTransactionConfirmed') } { t('initialTransactionConfirmed') }
</div> </div>
</div> </div>
<div className="page-container__footer">
<Button
type="primary"
className="page-container__footer-button"
onClick={() => {
this.props.hideModal()
this.props.onHide()
}}
>
{ t('ok') }
</Button>
</div>
</div>
) )
}
}
TransactionConfirmed.propTypes = {
hideModal: PropTypes.func.isRequired,
onHide: PropTypes.func.isRequired,
} }
TransactionConfirmed.contextTypes = { TransactionConfirmed.contextTypes = {

View File

@ -1,20 +0,0 @@
import { connect } from 'react-redux'
import TransactionConfirmed from './transaction-confirmed.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()),
}
}
export default connect(mapStateToProps, mapDispatchToProps)(TransactionConfirmed)

View File

@ -0,0 +1,2 @@
import WelcomeBeta from './welcome-beta.component'
module.exports = WelcomeBeta

View File

@ -0,0 +1,23 @@
import React from 'react'
import PropTypes from 'prop-types'
const TransactionConfirmed = (props, context) => {
const { t } = context
return (
<div className="modal-container__content">
<div className="modal-container__title">
{ `${t('uiWelcome')}` }
</div>
<div className="modal-container__description">
{ t('uiWelcomeMessage') }
</div>
</div>
)
}
TransactionConfirmed.contextTypes = {
t: PropTypes.func,
}
export default TransactionConfirmed