diff options
author | Dan J Miller <danjm.com@gmail.com> | 2019-08-03 04:31:26 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-08-03 04:31:26 +0800 |
commit | 9d5be5d29fcdab1273e30810f87de4624b8622a1 (patch) | |
tree | 60d59d7c4d72c2af25c711c7c805142e94d28989 /ui/app | |
parent | dadda918b4f2b82c6da82c6d0605d9134868202f (diff) | |
download | tangerine-wallet-browser-9d5be5d29fcdab1273e30810f87de4624b8622a1.tar.gz tangerine-wallet-browser-9d5be5d29fcdab1273e30810f87de4624b8622a1.tar.zst tangerine-wallet-browser-9d5be5d29fcdab1273e30810f87de4624b8622a1.zip |
New notification fixes (#6955)
* Replace use of backup-notification with use of home notification
* Pin notifications relative to window
* Remove unneeded isRequired condition on some home.component properties
* Refactor rendering of home notifications
* UX for multiple notifications
* Adds dismissal to provider request notification.
* Fix test failures
The e2e tests have been updated to reference `home-notification`
classnames instead of the removed `background-notification`. The
active tab proptypes and default values were updated as well.
Diffstat (limited to 'ui/app')
13 files changed, 200 insertions, 173 deletions
diff --git a/ui/app/components/app/backup-notification/backup-notification.component.js b/ui/app/components/app/backup-notification/backup-notification.component.js deleted file mode 100644 index dba79186c..000000000 --- a/ui/app/components/app/backup-notification/backup-notification.component.js +++ /dev/null @@ -1,50 +0,0 @@ -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' -import Button from '../../ui/button' -import { - INITIALIZE_SEED_PHRASE_ROUTE, -} from '../../../helpers/constants/routes' - -export default class BackupNotification extends PureComponent { - static propTypes = { - history: PropTypes.object, - showSeedPhraseBackupAfterOnboarding: PropTypes.func, - } - - static contextTypes = { - t: PropTypes.func, - metricsEvent: PropTypes.func, - } - - handleSubmit = () => { - const { history, showSeedPhraseBackupAfterOnboarding } = this.props - showSeedPhraseBackupAfterOnboarding() - history.push(INITIALIZE_SEED_PHRASE_ROUTE) - } - - render () { - const { t } = this.context - - return ( - <div className="backup-notification"> - <div className="backup-notification__header"> - <img - className="backup-notification__icon" - src="images/meta-shield.svg" - /> - <div className="backup-notification__text">Backup your Secret Recovery code to keep your wallet and funds secure.</div> - <i className="fa fa-info-circle"></i> - </div> - <div className="backup-notification__buttons"> - <Button - type="primary" - className="backup-notification__submit-button" - onClick={this.handleSubmit} - > - { t('backupNow') } - </Button> - </div> - </div> - ) - } -} diff --git a/ui/app/components/app/backup-notification/backup-notification.container.js b/ui/app/components/app/backup-notification/backup-notification.container.js deleted file mode 100644 index 6996770bc..000000000 --- a/ui/app/components/app/backup-notification/backup-notification.container.js +++ /dev/null @@ -1,16 +0,0 @@ -import { connect } from 'react-redux' -import { withRouter } from 'react-router-dom' -import { compose } from 'recompose' -import BackupNotification from './backup-notification.component' -import { showSeedPhraseBackupAfterOnboarding } from '../../../store/actions' - -const mapDispatchToProps = dispatch => { - return { - showSeedPhraseBackupAfterOnboarding: () => dispatch(showSeedPhraseBackupAfterOnboarding()), - } -} - -export default compose( - withRouter, - connect(null, mapDispatchToProps) -)(BackupNotification) diff --git a/ui/app/components/app/backup-notification/index.js b/ui/app/components/app/backup-notification/index.js deleted file mode 100644 index a1cbfe75a..000000000 --- a/ui/app/components/app/backup-notification/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './backup-notification.container' diff --git a/ui/app/components/app/backup-notification/index.scss b/ui/app/components/app/backup-notification/index.scss deleted file mode 100644 index 2d76c6ce4..000000000 --- a/ui/app/components/app/backup-notification/index.scss +++ /dev/null @@ -1,75 +0,0 @@ -.backup-notification { - background: rgba(36, 41, 46, 0.9); - box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.12); - border-radius: 8px; - height: 116px; - padding: 16px; - margin: 8px; - - display: flex; - flex-flow: column; - justify-content: space-between; - - position: absolute; - right: 0; - bottom: 0; - - &__header { - display: flex; - } - - &__text { - font-family: Roboto; - font-style: normal; - font-weight: normal; - font-size: 12px; - color: #FFFFFF; - 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: rgba(36, 41, 46, 0.9); - height: 34px; - width: 155px; - padding: 0; - - &:hover { - border-color: #6A737D; - background-color: #6A737D; - } - } - - &__submit-button { - border: 2px solid #6A737D; - box-sizing: border-box; - border-radius: 6px; - color: $white; - background-color: rgba(36, 41, 46, 0.9); - height: 34px; - width: 155px; - padding: 0; - - &:hover { - background-color: #3b4046; - } - - &:active { - background-color:#141618; - } - } - - &__buttons { - display: flex; - width: 130px; - align-self: flex-end; - } -}
\ No newline at end of file diff --git a/ui/app/components/app/home-notification/home-notification.component.js b/ui/app/components/app/home-notification/home-notification.component.js index cc46eb53a..cc86ef6d8 100644 --- a/ui/app/components/app/home-notification/home-notification.component.js +++ b/ui/app/components/app/home-notification/home-notification.component.js @@ -1,4 +1,5 @@ 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' @@ -22,6 +23,7 @@ export default class HomeNotification extends PureComponent { onIgnore: PropTypes.func, descriptionText: PropTypes.string.isRequired, infoText: PropTypes.string, + classNames: PropTypes.array, } handleAccept = () => { @@ -33,10 +35,10 @@ export default class HomeNotification extends PureComponent { } render () { - const { descriptionText, acceptText, onAccept, ignoreText, onIgnore, infoText } = this.props + const { descriptionText, acceptText, onAccept, ignoreText, onIgnore, infoText, classNames = [] } = this.props return ( - <div className="home-notification"> + <div className={classnames('home-notification', ...classNames)}> <div className="home-notification__header"> <div className="home-notification__header-container"> <img diff --git a/ui/app/components/app/home-notification/index.scss b/ui/app/components/app/home-notification/index.scss index 9cc868d46..c855a0814 100644 --- a/ui/app/components/app/home-notification/index.scss +++ b/ui/app/components/app/home-notification/index.scss @@ -10,7 +10,10 @@ border-radius: 8px; height: 116px; padding: 16px; - margin: 8px; + + @media screen and (min-width: 576px) { + min-width: 472px; + } display: flex; flex-flow: column; @@ -50,6 +53,10 @@ width: 155px; padding: 0; + @media screen and (max-width: 575px) { + width: 135px; + } + &:hover { border-color: #6A737D; background-color: #6A737D; @@ -69,6 +76,11 @@ height: 34px; width: 155px; padding: 0; + margin-left: 4px; + + @media screen and (max-width: 575px) { + width: 135px; + } &:hover { border-color: #6A737D; @@ -83,7 +95,7 @@ &__buttons { display: flex; width: 100%; - justify-content: space-between; + justify-content: flex-start; flex-direction: row-reverse; } } diff --git a/ui/app/components/app/index.scss b/ui/app/components/app/index.scss index 09a97ac28..1ccb6a94a 100644 --- a/ui/app/components/app/index.scss +++ b/ui/app/components/app/index.scss @@ -84,4 +84,4 @@ @import 'home-notification/index'; -@import 'backup-notification/index'; +@import 'multiple-notifications/index'; 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..e3ee39a74 --- /dev/null +++ b/ui/app/components/app/multiple-notifications/index.scss @@ -0,0 +1,80 @@ +.home-notification-wrapper--show-all, +.home-notification-wrapper--show-first { + display: flex; + flex-direction: column; + width: 472px; + height: 116px; + 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 { + height: 356px;; + 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..95dbb5c9a --- /dev/null +++ b/ui/app/components/app/multiple-notifications/multiple-notifications.component.js @@ -0,0 +1,39 @@ +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 + + return (<div + className={classnames(...classNames, { + 'home-notification-wrapper--show-all': showAll, + 'home-notification-wrapper--show-first': !showAll, + })} + > + {notifications + .filter(notificationConfig => notificationConfig.shouldBeRendered) + .map(notificationConfig => notificationConfig.component) + } + <div + className="home-notification-wrapper__i-container" + onClick={() => this.setState({ showAll: !showAll })} + > + {notifications.length > 1 ? <i className={classnames('fa fa-sm fa-sort-amount-asc', { + 'flipped': !showAll, + })} /> : null} + </div> + </div>) + } +} diff --git a/ui/app/css/itcss/generic/index.scss b/ui/app/css/itcss/generic/index.scss index 771008205..aaf6c7c0e 100644 --- a/ui/app/css/itcss/generic/index.scss +++ b/ui/app/css/itcss/generic/index.scss @@ -130,3 +130,14 @@ input.form-control { overflow: hidden; text-overflow: ellipsis; } + +.pinned-to-bottom { + position: absolute; + bottom: 0px; +} + +.pinned-to-bottom-right { + position: absolute; + bottom: 0px; + right: 0; +} diff --git a/ui/app/pages/home/home.component.js b/ui/app/pages/home/home.component.js index e59106537..dca4c8540 100644 --- a/ui/app/pages/home/home.component.js +++ b/ui/app/pages/home/home.component.js @@ -3,15 +3,16 @@ import PropTypes from 'prop-types' import Media from 'react-media' import { Redirect } from 'react-router-dom' import HomeNotification from '../../components/app/home-notification' +import MultipleNotifications from '../../components/app/multiple-notifications' import WalletView from '../../components/app/wallet-view' import TransactionView from '../../components/app/transaction-view' import ProviderApproval from '../provider-approval' -import BackupNotification from '../../components/app/backup-notification' import { RESTORE_VAULT_ROUTE, CONFIRM_TRANSACTION_ROUTE, CONFIRM_ADD_SUGGESTED_TOKEN_ROUTE, + INITIALIZE_SEED_PHRASE_ROUTE, } from '../../helpers/constants/routes' export default class Home extends PureComponent { @@ -20,15 +21,17 @@ export default class Home extends PureComponent { } static defaultProps = { - activeTab: null, + activeTab: {}, unsetMigratedPrivacyMode: null, forceApproveProviderRequestByOrigin: null, } static propTypes = { activeTab: PropTypes.shape({ - title: PropTypes.string.isRequired, - url: PropTypes.string.isRequired, + origin: PropTypes.string, + protocol: PropTypes.string, + title: PropTypes.string, + url: PropTypes.string, }), history: PropTypes.object, forgottenPassword: PropTypes.bool, @@ -40,6 +43,8 @@ export default class Home extends PureComponent { viewingUnconnectedDapp: PropTypes.bool.isRequired, forceApproveProviderRequestByOrigin: PropTypes.func, shouldShowSeedPhraseReminder: PropTypes.bool, + showSeedPhraseBackupAfterOnboarding: PropTypes.bool, + rejectProviderRequestByOrigin: PropTypes.func, } componentWillMount () { @@ -77,6 +82,8 @@ export default class Home extends PureComponent { viewingUnconnectedDapp, forceApproveProviderRequestByOrigin, shouldShowSeedPhraseReminder, + showSeedPhraseBackupAfterOnboarding, + rejectProviderRequestByOrigin, } = this.props if (forgottenPassword) { @@ -98,39 +105,49 @@ export default class Home extends PureComponent { { !history.location.pathname.match(/^\/confirm-transaction/) ? ( <TransactionView> - { - showPrivacyModeNotification - ? ( - <HomeNotification + <MultipleNotifications + className + notifications={[ + { + shouldBeRendered: showPrivacyModeNotification, + component: <HomeNotification descriptionText={t('privacyModeDefault')} acceptText={t('learnMore')} onAccept={() => { window.open('https://medium.com/metamask/42549d4870fa', '_blank', 'noopener') unsetMigratedPrivacyMode() }} - /> - ) - : null - } - { - viewingUnconnectedDapp - ? ( - <HomeNotification + key="home-privacyModeDefault" + />, + }, + { + shouldBeRendered: viewingUnconnectedDapp, + component: <HomeNotification descriptionText={t('shareAddressToConnect', [activeTab.origin])} acceptText={t('shareAddress')} onAccept={() => { forceApproveProviderRequestByOrigin(activeTab.origin) }} + ignoreText={t('dismiss')} + onIgnore={() => rejectProviderRequestByOrigin(activeTab.origin)} infoText={t('shareAddressInfo', [activeTab.origin])} - /> - ) - : null - } - { - shouldShowSeedPhraseReminder - ? (<BackupNotification />) - : null - } + key="home-shareAddressToConnect" + />, + }, + { + shouldBeRendered: shouldShowSeedPhraseReminder, + component: <HomeNotification + descriptionText={t('backupApprovalNotice')} + acceptText={t('backupNow')} + onAccept={() => { + showSeedPhraseBackupAfterOnboarding() + history.push(INITIALIZE_SEED_PHRASE_ROUTE) + }} + infoText={t('backupApprovalInfo')} + key="home-backupApprovalNotice" + />, + }, + ]}/> </TransactionView> ) : null } diff --git a/ui/app/pages/home/home.container.js b/ui/app/pages/home/home.container.js index 064c914cd..434d4b7e3 100644 --- a/ui/app/pages/home/home.container.js +++ b/ui/app/pages/home/home.container.js @@ -7,6 +7,8 @@ import { getCurrentEthBalance } from '../../selectors/selectors' import { forceApproveProviderRequestByOrigin, unsetMigratedPrivacyMode, + showSeedPhraseBackupAfterOnboarding, + rejectProviderRequestByOrigin, } from '../../store/actions' import { getEnvironmentType } from '../../../../app/scripts/lib/util' import { ENVIRONMENT_TYPE_POPUP } from '../../../../app/scripts/lib/enums' @@ -17,6 +19,7 @@ const mapStateToProps = state => { const { activeTab, metamask, appState } = state const { approvedOrigins, + dismissedOrigins, lostAccounts, suggestedTokens, providerRequests, @@ -34,7 +37,8 @@ const mapStateToProps = state => { activeTab && activeTabDappProtocols.includes(activeTab.protocol) && privacyMode && - !approvedOrigins[activeTab.origin] + !approvedOrigins[activeTab.origin] && + !dismissedOrigins[activeTab.origin] ) const isPopup = getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP @@ -48,12 +52,15 @@ const mapStateToProps = state => { activeTab, viewingUnconnectedDapp: isUnconnected && isPopup, shouldShowSeedPhraseReminder: !seedPhraseBackedUp && (parseInt(accountBalance, 16) > 0 || tokens.length > 0), + isPopup, } } const mapDispatchToProps = (dispatch) => ({ unsetMigratedPrivacyMode: () => dispatch(unsetMigratedPrivacyMode()), forceApproveProviderRequestByOrigin: (origin) => dispatch(forceApproveProviderRequestByOrigin(origin)), + rejectProviderRequestByOrigin: origin => dispatch(rejectProviderRequestByOrigin(origin)), + showSeedPhraseBackupAfterOnboarding: () => dispatch(showSeedPhraseBackupAfterOnboarding()), }) export default compose( |