diff --git a/src/components/HSMStatusBanner.js b/src/components/HSMStatusBanner.js new file mode 100644 index 00000000..94606f72 --- /dev/null +++ b/src/components/HSMStatusBanner.js @@ -0,0 +1,171 @@ +// @flow + +import React, { PureComponent } from 'react' +import { warnings } from '@ledgerhq/live-common/lib/api/socket' +import { translate } from 'react-i18next' +import styled from 'styled-components' + +import { colors } from 'styles/theme' +import uniqueId from 'lodash/uniqueId' +import { openURL } from 'helpers/linking' +import IconCross from 'icons/Cross' +import IconExclamationCircle from 'icons/ExclamationCircle' +import IconChevronRight from 'icons/ChevronRight' + +import Box from 'components/base/Box' +import { SHOW_MOCK_HSMWARNINGS } from '../config/constants' +import { urls } from '../config/urls' + +const CloseIconContainer = styled.div` + position: absolute; + top: 0; + right: 0; + display: flex; + align-items: center; + justify-content: center; + padding: 10px; + border-bottom-left-radius: 4px; +` + +const CloseIcon = (props: *) => ( + + + +) + +type Props = { + t: *, +} + +type State = { + pendingMessages: HSMStatus[], +} + +type HSMStatus = { + id: string, + message: string, +} + +class HSMStatusBanner extends PureComponent { + state = { + pendingMessages: SHOW_MOCK_HSMWARNINGS + ? [ + { + id: 'mock1', + message: 'Lorem Ipsum dolor sit amet #1', + }, + ] + : [], + } + + componentDidMount() { + this.warningSub = warnings.subscribe({ + next: message => { + this.setState(prevState => ({ + pendingMessages: [...prevState.pendingMessages, { id: uniqueId(), message }], + })) + }, + }) + } + + componentWillUnmount() { + if (this.warningSub) { + this.warningSub.unsubscribe() + } + } + + warningSub = null + + dismiss = dismissedItem => + this.setState(prevState => ({ + pendingMessages: prevState.pendingMessages.filter(item => item.id !== dismissedItem.id), + })) + + render() { + const { t } = this.props + const { pendingMessages } = this.state + + if (!pendingMessages.length) return null + const item = pendingMessages[0] + + return ( + + + + ) + } +} + +class BannerItem extends PureComponent<{ + item: HSMStatus, + onItemDismiss: HSMStatus => void, + t: *, +}> { + onLinkClick = () => openURL(urls.contactSupport) + dismiss = () => this.props.onItemDismiss(this.props.item) + + render() { + const { item, t } = this.props + return ( + + + + + + {item.message} + + + + + ) + } +} + +const UnderlinedLink = styled.span` + border-bottom: 1px solid transparent; + &:hover { + border-bottom-color: white; + } +` + +const BannerItemLink = ({ t, onClick }: { t: *, onClick: void => * }) => ( + + + {t('common.learnMore')} + +) + +const styles = { + container: { + position: 'fixed', + left: 32, + bottom: 32, + zIndex: 100, + }, + banner: { + background: colors.orange, + overflow: 'hidden', + borderRadius: 4, + fontSize: 13, + paddingTop: 17, + padding: 15, + color: 'white', + fontWeight: 'bold', + paddingRight: 30, + width: 350, + }, + message: { + marginTop: -3, + }, +} + +export default translate()(HSMStatusBanner) diff --git a/src/components/TopBar/index.js b/src/components/TopBar/index.js index b18914c5..7944d958 100644 --- a/src/components/TopBar/index.js +++ b/src/components/TopBar/index.js @@ -25,6 +25,7 @@ import CurrenciesStatusBanner from 'components/CurrenciesStatusBanner' import ActivityIndicator from './ActivityIndicator' import ItemContainer from './ItemContainer' +import HSMStatusBanner from '../HSMStatusBanner' const Container = styled(Box).attrs({ px: 6, diff --git a/src/components/layout/Default.js b/src/components/layout/Default.js index f79744ac..02830da4 100644 --- a/src/components/layout/Default.js +++ b/src/components/layout/Default.js @@ -35,6 +35,7 @@ import SideBar from 'components/MainSideBar' import TopBar from 'components/TopBar' import SyncBackground from 'components/SyncBackground' import SyncContinuouslyPendingOperations from '../SyncContinouslyPendingOperations' +import HSMStatusBanner from '../HSMStatusBanner' const Main = styled(GrowScroll).attrs({ px: 6, @@ -106,6 +107,7 @@ class Default extends Component { +
(this._scrollContainer = n)} tabIndex={-1}> diff --git a/src/config/constants.js b/src/config/constants.js index 76f8af9c..8194e649 100644 --- a/src/config/constants.js +++ b/src/config/constants.js @@ -78,6 +78,7 @@ export const LEDGER_DEBUG_ALL_LANGS = boolFromEnv('LEDGER_DEBUG_ALL_LANGS') export const SKIP_GENUINE = boolFromEnv('SKIP_GENUINE') export const SKIP_ONBOARDING = boolFromEnv('SKIP_ONBOARDING') export const SHOW_LEGACY_NEW_ACCOUNT = boolFromEnv('SHOW_LEGACY_NEW_ACCOUNT') +export const SHOW_MOCK_HSMWARNINGS = boolFromEnv('SHOW_MOCK_HSMWARNINGS') export const HIGHLIGHT_I18N = boolFromEnv('HIGHLIGHT_I18N') export const DISABLE_ACTIVITY_INDICATORS = boolFromEnv('DISABLE_ACTIVITY_INDICATORS') export const EXPERIMENTAL_CENTER_MODAL = boolFromEnv('EXPERIMENTAL_CENTER_MODAL') diff --git a/src/styles/theme.js b/src/styles/theme.js index ff165f59..f726919e 100644 --- a/src/styles/theme.js +++ b/src/styles/theme.js @@ -77,6 +77,7 @@ export const colors = { lightFog: '#eeeeee', lightGraphite: '#fafafa', lightGrey: '#f9f9f9', + orange: '#ffa726', positiveGreen: '#66be54', smoke: '#666666', wallet: '#6490f1',