Browse Source

Merge pull request #283 from loeck/master

Better flow for modal Send
master
Loëck Vézien 7 years ago
committed by GitHub
parent
commit
eaeb4cc317
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 14
      package.json
  2. 29
      src/components/AccountPage/index.js
  3. 8
      src/components/BalanceSummary/BalanceInfos.js
  4. 36
      src/components/CounterValue/__tests__/__snapshots__/CounterValue.test.js.snap
  5. 1
      src/components/DashboardPage/AccountCard.js
  6. 6
      src/components/OperationsList/ConfirmationCheck.js
  7. 4
      src/components/SelectAccount/index.js
  8. 3
      src/components/base/DropDown/index.js
  9. 36
      src/components/base/FormattedVal/__tests__/__snapshots__/FormattedVal.test.js.snap
  10. 6
      src/components/base/FormattedVal/index.js
  11. 4
      src/components/base/Modal/ModalBody.js
  12. 150
      src/components/base/StepperNumber/index.js
  13. 45
      src/components/base/StepperNumber/stories.js
  14. 2
      src/components/modals/AddAccount/index.js
  15. 37
      src/components/modals/PrevButton.js
  16. 25
      src/components/modals/Receive/index.js
  17. 26
      src/components/modals/Send/01-step-amount.js
  18. 37
      src/components/modals/Send/02-step-connect-device.js
  19. 4
      src/components/modals/Send/Footer.js
  20. 155
      src/components/modals/Send/index.js
  21. 1
      static/i18n/en/common.yml
  22. 1
      static/i18n/en/send.yml
  23. 183
      yarn.lock

14
package.json

@ -59,16 +59,16 @@
"cross-env": "^5.1.4",
"d3": "^5.0.0",
"debug": "^3.1.0",
"downshift": "^1.31.6",
"downshift": "^1.31.7",
"electron-store": "^1.3.0",
"electron-updater": "^2.21.4",
"fuse.js": "^3.2.0",
"history": "^4.7.2",
"i18next": "^11.1.1",
"i18next": "^11.2.2",
"i18next-node-fs-backend": "^1.0.0",
"ledger-test-library": "KhalilBellakrid/ledger-test-library-nodejs#7d37482",
"lodash": "^4.17.5",
"moment": "^2.22.0",
"moment": "^2.22.1",
"object-path": "^0.11.4",
"qrcode": "^1.2.0",
"qs": "^6.5.1",
@ -77,7 +77,7 @@
"react": "^16.3.1",
"react-dom": "^16.3.1",
"react-flip-ticker": "^0.3.0",
"react-i18next": "^7.5.1",
"react-i18next": "^7.6.0",
"react-mortal": "^3.2.0",
"react-motion": "^0.5.2",
"react-qr-reader": "^2.1.0",
@ -94,7 +94,7 @@
"source-map-support": "^0.5.4",
"styled-components": "^3.2.5",
"styled-system": "^2.2.1",
"tippy.js": "^2.5.0",
"tippy.js": "^2.5.2",
"ws": "^5.1.1"
},
"devDependencies": {
@ -111,7 +111,7 @@
"@storybook/addons": "^3.4.1",
"@storybook/react": "^3.4.1",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "^8.2.1",
"babel-eslint": "^8.2.3",
"babel-jest": "^22.4.3",
"babel-loader": "^8.0.0-beta.2",
"babel-plugin-module-resolver": "^3.1.1",
@ -129,7 +129,7 @@
"eslint-config-airbnb": "^16.1.0",
"eslint-config-prettier": "^2.9.0",
"eslint-import-resolver-babel-module": "^5.0.0-beta.0",
"eslint-plugin-flowtype": "^2.46.0",
"eslint-plugin-flowtype": "^2.46.2",
"eslint-plugin-import": "^2.11.0",
"eslint-plugin-jsx-a11y": "^6.0.3",
"eslint-plugin-react": "^7.7.0",

29
src/components/AccountPage/index.js

@ -85,7 +85,9 @@ class AccountPage extends PureComponent<Props, State> {
return
}
if (process.platform === 'darwin') {
if (process.platform === 'darwin' && this._cacheBalance !== data.totalBalance) {
this._cacheBalance = data.totalBalance
ipcRenderer.send('touch-bar-update', {
text: account.name,
color: account.currency.color,
@ -107,6 +109,8 @@ class AccountPage extends PureComponent<Props, State> {
daysCount: item.value,
})
_cacheBalance = null
render() {
const { account, openModal, t, counterValue } = this.props
const { selectedTime, daysCount } = this.state
@ -117,7 +121,8 @@ class AccountPage extends PureComponent<Props, State> {
}
return (
<Box>
// Force re-render account page, for avoid animation
<Box key={account.id}>
<Box horizontal mb={5}>
<AccountHeader account={account} />
<Box horizontal alignItems="center" justifyContent="flex-end" grow flow={2}>
@ -153,17 +158,15 @@ class AccountPage extends PureComponent<Props, State> {
<Box flow={4} mb={2}>
<Box horizontal>
<BalanceTotal totalBalance={account.balance} unit={account.unit}>
<Box mt={1}>
<FormattedVal
animateTicker
alwaysShowSign={false}
color="warmGrey"
fiat={counterValue}
fontSize={6}
showCode
val={totalBalance}
/>
</Box>
<FormattedVal
animateTicker
alwaysShowSign={false}
color="warmGrey"
fiat={counterValue}
fontSize={6}
showCode
val={totalBalance}
/>
</BalanceTotal>
<Box>
<PillsDaysCount

8
src/components/BalanceSummary/BalanceInfos.js

@ -7,13 +7,11 @@ import type { Unit } from '@ledgerhq/currencies'
import type { T } from 'types/common'
import Box from 'components/base/Box'
import Text from 'components/base/Text'
import FormattedVal from 'components/base/FormattedVal'
const Sub = styled(Text).attrs({
const Sub = styled(Box).attrs({
ff: 'Open Sans',
fontSize: 4,
mt: 1,
})`
text-transform: lowercase;
`
@ -73,7 +71,7 @@ export function BalanceSinceDiff(props: Props) {
export function BalanceTotal(props: BalanceTotalProps) {
const { counterValue, totalBalance, children, unit } = props
return (
<Box grow>
<Box grow {...props}>
<FormattedVal
animateTicker
color="dark"
@ -97,7 +95,7 @@ BalanceTotal.defaultProps = {
function BalanceInfos(props: Props) {
const { t, totalBalance, since, sinceBalance, refBalance, counterValue } = props
return (
<Box horizontal alignItems="flex-end" flow={7}>
<Box horizontal alignItems="center" flow={7}>
<BalanceTotal counterValue={counterValue} totalBalance={totalBalance}>
<Sub>{t('dashboard:totalBalance')}</Sub>
</BalanceTotal>

36
src/components/CounterValue/__tests__/__snapshots__/CounterValue.test.js.snap

@ -1,55 +1,55 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`components CounterValue basic 1`] = `
<span
className="s1c17x4y-0 jqghir s8vzclq-0 hjqlvj"
<div
className="s1c17x4y-0 jLdFhK s1xoa5y3-0 cCejoE"
color="#66be54"
>
+ USD 10.00
</span>
</div>
`;
exports[`components CounterValue specifying ticker different from default 1`] = `
<span
className="s1c17x4y-0 jqghir s8vzclq-0 hjqlvj"
<div
className="s1c17x4y-0 jLdFhK s1xoa5y3-0 cCejoE"
color="#66be54"
>
+ USD 5.00
</span>
</div>
`;
exports[`components CounterValue using countervalue different from default 1`] = `
<span
className="s1c17x4y-0 jqghir s8vzclq-0 hjqlvj"
<div
className="s1c17x4y-0 jLdFhK s1xoa5y3-0 cCejoE"
color="#66be54"
>
+ EUR 0.42
</span>
</div>
`;
exports[`components CounterValue with time travel whith date in countervalues 1`] = `
<span
className="s1c17x4y-0 jqghir s8vzclq-0 hjqlvj"
<div
className="s1c17x4y-0 jLdFhK s1xoa5y3-0 cCejoE"
color="#66be54"
>
+ USD 20.00
</span>
</div>
`;
exports[`components CounterValue with time travel whith date not in countervalues 1`] = `
<span
className="s1c17x4y-0 jqghir s8vzclq-0 hjqlvj"
<div
className="s1c17x4y-0 jLdFhK s1xoa5y3-0 cCejoE"
color="#66be54"
>
+ USD 0.00
</span>
</div>
`;
exports[`components CounterValue without countervalues populated 1`] = `
<span
className="s1c17x4y-0 jqghir s8vzclq-0 hjqlvj"
<div
className="s1c17x4y-0 jLdFhK s1xoa5y3-0 cCejoE"
color="#66be54"
>
+ USD 0.00
</span>
</div>
`;

1
src/components/DashboardPage/AccountCard.js

@ -72,6 +72,7 @@ const AccountCard = ({
<Box flow={2} horizontal>
<Box justifyContent="center">
<FormattedVal
animateTicker
fiat={counterValue}
val={totalBalance}
alwaysShowSign={false}

6
src/components/OperationsList/ConfirmationCheck.js

@ -7,9 +7,9 @@ import { rgba } from 'styles/helpers'
import type { T } from 'types/common'
import IconArrowDown from 'icons/ArrowDown'
import IconArrowUp from 'icons/ArrowUp'
import IconClock from 'icons/Clock'
import IconReceive from 'icons/Receive'
import IconSend from 'icons/Send'
import Box from 'components/base/Box'
import Tooltip from 'components/base/Tooltip'
@ -64,7 +64,7 @@ const ConfirmationCheck = ({
const renderContent = () => (
<Container type={type} isConfirmed={isConfirmed} {...props}>
{type === 'from' ? <IconArrowDown size={12} /> : <IconArrowUp size={12} />}
{type === 'from' ? <IconReceive size={12} /> : <IconSend size={12} />}
{!isConfirmed && (
<WrapperClock>
<IconClock size={10} />

4
src/components/SelectAccount/index.js

@ -5,8 +5,8 @@ import { connect } from 'react-redux'
import { translate } from 'react-i18next'
import noop from 'lodash/noop'
import { getIconByCoinType } from '@ledgerhq/currencies/react'
import type { Account } from '@ledgerhq/wallet-common/lib/types'
import type { Account } from '@ledgerhq/wallet-common/lib/types'
import type { T } from 'types/common'
import { getVisibleAccounts } from 'reducers/accounts'
@ -56,7 +56,7 @@ const RawSelectAccount = ({ accounts, onChange, value, t, ...props }: Props) =>
renderSelected={renderItem}
renderItem={renderItem}
keyProp="id"
items={accounts}
items={accounts.sort((a, b) => (a.name < b.name ? -1 : 1))}
placeholder={t('common:selectAccount')}
fontSize={4}
onChange={onChange}

3
src/components/base/DropDown/index.js

@ -19,8 +19,9 @@ const Drop = styled(Box).attrs({
p: 2,
})`
position: absolute;
top: 100%;
right: 0;
top: 100%;
z-index: 1;
`
export const DropDownItem = styled(Box).attrs({

36
src/components/base/FormattedVal/__tests__/__snapshots__/FormattedVal.test.js.snap

@ -1,55 +1,55 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`components FormattedVal renders a fiat 1`] = `
<span
className="s1c17x4y-0 jqghir s8vzclq-0 hjqlvj"
<div
className="s1c17x4y-0 jLdFhK s1xoa5y3-0 cCejoE"
color="#66be54"
>
20.00
</span>
</div>
`;
exports[`components FormattedVal renders a formatted val 1`] = `
<span
className="s1c17x4y-0 jqghir s8vzclq-0 hjqlvj"
<div
className="s1c17x4y-0 jLdFhK s1xoa5y3-0 cCejoE"
color="#66be54"
>
4
</span>
</div>
`;
exports[`components FormattedVal renders a percent 1`] = `
<span
className="s1c17x4y-0 jqghir s8vzclq-0 hjqlvj"
<div
className="s1c17x4y-0 jLdFhK s1xoa5y3-0 cCejoE"
color="#66be54"
>
30 %
</span>
</div>
`;
exports[`components FormattedVal shows code 1`] = `
<span
className="s1c17x4y-0 jqghir s8vzclq-0 hjqlvj"
<div
className="s1c17x4y-0 jLdFhK s1xoa5y3-0 cCejoE"
color="#66be54"
>
BTC 4
</span>
</div>
`;
exports[`components FormattedVal shows sign 1`] = `
<span
className="s1c17x4y-0 jqghir s8vzclq-0 hjqlvj"
<div
className="s1c17x4y-0 jLdFhK s1xoa5y3-0 cCejoE"
color="#66be54"
>
+ 4
</span>
</div>
`;
exports[`components FormattedVal shows sign 2`] = `
<span
className="s1c17x4y-0 jqghir s8vzclq-0 hENkfw"
<div
className="s1c17x4y-0 jLdFhK s1xoa5y3-0 kwFiWV"
color="#ea2e49"
>
- 4
</span>
</div>
`;

6
src/components/base/FormattedVal/index.js

@ -11,13 +11,13 @@ import type { Unit } from '@ledgerhq/currencies'
import { formatCurrencyUnit, getFiatUnit } from '@ledgerhq/currencies'
import Box from 'components/base/Box'
import Text from 'components/base/Text'
import IconBottom from 'icons/Bottom'
import IconTop from 'icons/Top'
const T = styled(Text).attrs({
const T = styled(Box).attrs({
ff: 'Rubik',
horizontal: true,
color: p =>
p.withIcon
? p.theme.colors.dark
@ -25,7 +25,7 @@ const T = styled(Text).attrs({
? p.theme.colors.alertRed
: p.theme.colors.positiveGreen,
})`
line-height: 0.9;
line-height: 1.2;
white-space: pre;
`

4
src/components/base/Modal/ModalBody.js

@ -73,7 +73,9 @@ const Body = styled(Box).attrs({
bg: p => p.theme.colors.white,
relative: true,
borderRadius: 1,
})``
})`
box-shadow: 0 10px 20px 0 rgba(0, 0, 0, 0.2);
`
const appear = keyframes`
from { opacity: 0; }

150
src/components/base/StepperNumber/index.js

@ -0,0 +1,150 @@
// @flow
import React, { PureComponent } from 'react'
import styled from 'styled-components'
import debounce from 'lodash/debounce'
import noop from 'lodash/noop'
import Box from 'components/base/Box'
const Container = styled(Box).attrs({
horizontal: true,
flow: 1,
alignItems: 'center',
justifyContent: 'center',
fontSize: 4,
ff: 'Rubik',
color: 'smoke',
})`
background-color: rgba(100, 144, 241, 0.1);
border-radius: 12px;
display: inline-flex;
height: 24px;
padding: 0 3px;
`
const Btn = styled(Box).attrs({
bg: p => (p.disabled ? 'rgba(100, 144, 241, 0.5)' : 'wallet'),
color: 'white',
alignItems: 'center',
justifyContent: 'center',
})`
border-radius: 50%;
cursor: ${p => (p.disabled ? 'default' : 'pointer')};
height: 18px;
width: 18px;
`
const Num = styled(Box).attrs({
alignItems: 'center',
justifyContent: 'center',
})`
min-width: 20px;
`
const DELAY_CLICK = 150
const DEBOUNCE_ON_CHANGE = 250
type Props = {
max: number,
min: number,
onChange: Function,
step: number,
value: number,
}
type State = {
value: number,
}
class StepperNumber extends PureComponent<Props, State> {
static defaultProps = {
max: 10,
min: 0,
onChange: noop,
step: 1,
value: 0,
}
state = {
value: this.props.value,
}
_timeout = undefined
isMax = (v: number) => v >= this.props.max
isMin = (v: number) => v <= this.props.min
emitChange = (v: number) => {
this.setState({
value: v,
})
this.debounceOnChange(v)
}
debounceOnChange = debounce(v => this.props.onChange(v), DEBOUNCE_ON_CHANGE)
decrement = () => {
const { step, min } = this.props
const { value } = this.state
const newValue = value - step
if (newValue !== value) {
const isMin = this.isMin(newValue)
const v = isMin ? min : newValue
this.emitChange(v)
if (!isMin) {
this._timeout = setTimeout(this.decrement, DELAY_CLICK)
}
}
}
increment = () => {
const { step, max } = this.props
const { value } = this.state
const newValue = value + step
if (newValue !== value) {
const isMax = this.isMax(newValue)
const v = isMax ? max : newValue
this.emitChange(v)
if (!isMax) {
this._timeout = setTimeout(this.increment, DELAY_CLICK)
}
}
}
handleMouseUp = () => clearTimeout(this._timeout)
render() {
const { value } = this.state
const isMin = this.isMin(value)
const isMax = this.isMax(value)
return (
<Container>
<Btn
onMouseDown={!isMin ? this.decrement : undefined}
onMouseUp={this.handleMouseUp}
disabled={isMin}
>
-
</Btn>
<Num>{value}</Num>
<Btn
onMouseDown={!isMax ? this.increment : undefined}
onMouseUp={this.handleMouseUp}
disabled={isMax}
>
+
</Btn>
</Container>
)
}
}
export default StepperNumber

45
src/components/base/StepperNumber/stories.js

@ -0,0 +1,45 @@
// @flow
import React, { Component } from 'react'
import { storiesOf } from '@storybook/react'
import { action } from '@storybook/addon-actions'
import { number } from '@storybook/addon-knobs'
import StepperNumber from 'components/base/StepperNumber'
const stories = storiesOf('Components/base', module)
class Wrapper extends Component<any, any> {
state = {
value: 0,
}
handleChange = value => {
action('onChange')(value)
this.setState({ value })
}
render() {
const { render } = this.props
const { value } = this.state
return render({
onChange: this.handleChange,
value,
})
}
}
stories.add('StepperNumber', () => (
<Wrapper
render={({ value, onChange }) => (
<StepperNumber
min={number('min', 0)}
max={number('max', 10)}
step={number('step', 1)}
onChange={onChange}
value={value}
/>
)}
/>
))

2
src/components/modals/AddAccount/index.js

@ -362,7 +362,7 @@ class AddAccountModal extends PureComponent<Props, State> {
<ModalBody onClose={onClose}>
<ModalTitle>{t('addAccount:title')}</ModalTitle>
<ModalContent>
<Breadcrumb mb={5} currentStep={stepIndex} items={this._steps} />
<Breadcrumb mb={6} currentStep={stepIndex} items={this._steps} />
{this.renderStep()}
</ModalContent>
{stepIndex !== 2 && (

37
src/components/modals/PrevButton.js

@ -0,0 +1,37 @@
// @flow
import React from 'react'
import { translate } from 'react-i18next'
import styled from 'styled-components'
import type { T } from 'types/common'
import Button from 'components/base/Button'
import Box from 'components/base/Box'
import IconAngleLeft from 'icons/AngleLeft'
const Wrapper = styled(Button).attrs({
fontSize: 4,
ml: 4,
})`
left: 0;
margin-top: -18px;
position: absolute;
top: 50%;
`
type Props = {
t: T,
}
const PrevButton = ({ t, ...props }: Props) => (
<Wrapper {...props}>
<Box horizontal alignItems="center">
<IconAngleLeft size={16} />
{t('common:back')}
</Box>
</Wrapper>
)
export default translate()(PrevButton)

25
src/components/modals/Receive/index.js

@ -1,7 +1,6 @@
// @flow
import React, { Fragment, PureComponent } from 'react'
import styled from 'styled-components'
import { translate } from 'react-i18next'
import type { Account } from '@ledgerhq/wallet-common/lib/types'
@ -10,25 +9,16 @@ import type { T, Device } from 'types/common'
import { MODAL_RECEIVE } from 'config/constants'
import Box from 'components/base/Box'
import Button from 'components/base/Button'
import Breadcrumb from 'components/Breadcrumb'
import Button from 'components/base/Button'
import Modal, { ModalBody, ModalTitle, ModalContent, ModalFooter } from 'components/base/Modal'
import PrevButton from 'components/modals/PrevButton'
import StepConnectDevice from 'components/modals/StepConnectDevice'
import IconAngleLeft from 'icons/AngleLeft'
import StepAccount from './01-step-account'
import StepConfirmAddress from './03-step-confirm-address'
import StepReceiveFunds from './04-step-receive-funds'
const PrevButton = styled(Button).attrs({
fontSize: 4,
ml: 4,
})`
position: absolute;
left: 0;
`
type Props = {
t: T,
}
@ -286,19 +276,12 @@ class ReceiveModal extends PureComponent<Props, State> {
render={({ onClose }) => (
<ModalBody onClose={canClose ? onClose : undefined}>
<ModalTitle>
{canPrev && (
<PrevButton onClick={this.handlePrevStep}>
<Box horizontal alignItems="center">
<IconAngleLeft size={16} />
{t('common:back')}
</Box>
</PrevButton>
)}
{canPrev && <PrevButton onClick={this.handlePrevStep} />}
{t('receive:title')}
</ModalTitle>
<ModalContent>
<Breadcrumb
mb={5}
mb={6}
currentStep={stepIndex}
stepsErrors={stepsErrors}
stepsDisabled={stepsDisabled}

26
src/components/modals/Send/01-step-amount.js

@ -38,21 +38,21 @@ function StepAmount(props: PropsStepAmount) {
<SelectAccount onChange={onChange('account')} value={account} />
</Box>
{/* RECIPIENT ADDRESS */}
<Box flow={1}>
<Label>
<span>{t('send:steps.amount.recipientAddress')}</span>
<LabelInfoTooltip ml={1} text={t('send:steps.amount.recipientAddress')} />
</Label>
<RecipientAddress
withQrCode
value={recipientAddress}
onChange={onChange('recipientAddress')}
/>
</Box>
{account && (
<Fragment>
{/* RECIPIENT ADDRESS */}
<Box flow={1}>
<Label>
<span>{t('send:steps.amount.recipientAddress')}</span>
<LabelInfoTooltip ml={1} text={t('send:steps.amount.recipientAddress')} />
</Label>
<RecipientAddress
withQrCode
value={recipientAddress}
onChange={onChange('recipientAddress')}
/>
</Box>
{/* AMOUNT */}
<Box flow={1}>
<Label>{t('send:steps.amount.amount')}</Label>

37
src/components/modals/Send/02-step-connect-device.js

@ -1,37 +0,0 @@
// @flow
import React from 'react'
import type { Account } from '@ledgerhq/wallet-common/lib/types'
import DeviceMonit from 'components/DeviceMonit'
type Props = {
account: Account | null,
isDeviceReady: boolean,
onChange: Function,
}
function StepConnectDevice(props: Props) {
const { account, isDeviceReady, onChange } = props
const setReady = onChange('isDeviceReady')
if (!account) {
return null
}
return (
<div>
<DeviceMonit
account={account}
onStatusChange={status => {
if (status === 'appOpened' && !isDeviceReady) {
setReady(true)
}
if (status !== 'appOpened' && isDeviceReady) {
setReady(false)
}
}}
/>
</div>
)
}
export default StepConnectDevice

4
src/components/modals/Send/Footer.js

@ -7,10 +7,10 @@ import type { T } from 'types/common'
import { ModalFooter } from 'components/base/Modal'
import Box from 'components/base/Box'
import Label from 'components/base/Label'
import Button from 'components/base/Button'
import CounterValue from 'components/CounterValue'
import FormattedVal from 'components/base/FormattedVal'
import Button from 'components/base/Button'
import Label from 'components/base/Label'
import Text from 'components/base/Text'
type Props = {

155
src/components/modals/Send/index.js

@ -2,35 +2,42 @@
import React, { PureComponent } from 'react'
import { translate } from 'react-i18next'
import get from 'lodash/get'
import { connect } from 'react-redux'
import { compose } from 'redux'
import type { Account } from '@ledgerhq/wallet-common/lib/types'
import type { T, Device } from 'types/common'
import type { T } from 'types/common'
import { getVisibleAccounts } from 'reducers/accounts'
import { MODAL_SEND } from 'config/constants'
import Breadcrumb from 'components/Breadcrumb'
import Modal, { ModalBody, ModalTitle, ModalContent } from 'components/base/Modal'
import Button from 'components/base/Button'
import Modal, { ModalFooter, ModalBody, ModalTitle, ModalContent } from 'components/base/Modal'
import PrevButton from 'components/modals/PrevButton'
import StepConnectDevice from 'components/modals/StepConnectDevice'
import Footer from './Footer'
import StepAmount from './01-step-amount'
import StepConnectDevice from './02-step-connect-device'
import StepVerification from './03-step-verification'
import StepConfirmation from './04-step-confirmation'
type Props = {
accounts: Account[],
t: T,
}
type State = {
stepIndex: number,
isDeviceReady: boolean,
account: Account | null,
amount: number,
appStatus: null | string,
deviceSelected: Device | null,
fees: number,
account: Account | null,
recipientAddress: string,
isRBF: boolean,
recipientAddress: string,
stepIndex: number,
}
const GET_STEPS = t => [
@ -40,35 +47,52 @@ const GET_STEPS = t => [
{ label: t('send:steps.confirmation.title'), Comp: StepConfirmation },
]
const mapStateToProps = state => ({
accounts: getVisibleAccounts(state).sort((a, b) => (a.name < b.name ? -1 : 1)),
})
const INITIAL_STATE = {
stepIndex: 0,
isDeviceReady: false,
account: null,
recipientAddress: '',
amount: 0,
appStatus: null,
deviceSelected: null,
fees: 0,
isRBF: false,
recipientAddress: '',
stepIndex: 0,
}
class SendModal extends PureComponent<Props, State> {
state = INITIAL_STATE
_steps = GET_STEPS(this.props.t)
_account: Account | null = null
_steps = GET_STEPS(this.props.t)
canNext = account => {
canNext = () => {
const { stepIndex } = this.state
// informations
if (stepIndex === 0) {
const { amount, recipientAddress } = this.state
return !!amount && !!recipientAddress && !!account
return !!amount && !!recipientAddress && !!this._account
}
if (stepIndex === 1) {
const { deviceSelected, appStatus } = this.state
return deviceSelected !== null && appStatus === 'success'
}
// connect device
if (stepIndex === 2) {
return true
}
return false
}
canPrev = () => {
const { stepIndex } = this.state
if (stepIndex === 1) {
const { isDeviceReady } = this.state
return !!isDeviceReady
return true
}
return false
@ -84,6 +108,34 @@ class SendModal extends PureComponent<Props, State> {
this.setState({ stepIndex: stepIndex + 1 })
}
handleChangeDevice = d => this.setState({ deviceSelected: d })
handleChangeStatus = (deviceStatus, appStatus) => this.setState({ appStatus })
handlePrevStep = () => {
const { stepIndex } = this.state
let newStepIndex
switch (stepIndex) {
default:
case 1:
newStepIndex = 0
break
case 2:
case 3:
newStepIndex = 1
break
}
this.setState({
appStatus: null,
deviceSelected: null,
stepIndex: newStepIndex,
})
}
createChangeHandler = key => value => {
const patch = { [key]: value }
// ensure max is always restecped when changing fees
@ -104,54 +156,75 @@ class SendModal extends PureComponent<Props, State> {
this.setState(patch)
}
renderStep = acc => {
const { stepIndex, account, amount, ...othersState } = this.state
renderStep = () => {
const { t } = this.props
const { stepIndex, amount, deviceSelected, ...otherState } = this.state
const step = this._steps[stepIndex]
if (!step) {
return null
}
const { Comp } = step
const props = (predicate, props) => (predicate ? props : {})
const stepProps = {
...othersState,
...otherState,
t,
amount,
account: account || acc,
account: this._account,
...props(stepIndex === 1, {
accountName: this._account ? this._account.name : undefined,
deviceSelected,
onChangeDevice: this.handleChangeDevice,
onStatusChange: this.handleChangeStatus,
}),
}
return <Comp onChange={this.createChangeHandler} {...stepProps} {...this.props} />
}
render() {
const { t } = this.props
const { accounts, t } = this.props
const { stepIndex, amount, account, fees } = this.state
const canNext = this.canNext()
const canPrev = this.canPrev()
return (
<Modal
name={MODAL_SEND}
onHide={this.handleReset}
render={({ data, onClose }) => {
const acc = account || get(data, 'account', null)
const canNext = this.canNext(acc)
// hack: access the selected account, living in modal data, outside
// of the modal render function
this._account = acc
this._account = account || (data && data.account) || accounts[0]
return (
<ModalBody onClose={onClose} deferHeight={acc ? 630 : 355}>
<ModalTitle>{t('send:title')}</ModalTitle>
<ModalBody onClose={onClose}>
<ModalTitle>
{canPrev && <PrevButton onClick={this.handlePrevStep} />}
{t('send:title')}
</ModalTitle>
<ModalContent>
<Breadcrumb mb={5} currentStep={stepIndex} items={this._steps} />
{this.renderStep(acc)}
<Breadcrumb mb={6} currentStep={stepIndex} items={this._steps} />
{this.renderStep()}
</ModalContent>
{acc && (
<Footer
canNext={canNext}
onNext={this.handleNextStep}
account={acc}
amount={amount}
fees={fees}
t={t}
/>
{this._account &&
stepIndex !== 3 && (
<Footer
canNext={canNext}
onNext={this.handleNextStep}
account={this._account}
amount={amount}
fees={fees}
t={t}
/>
)}
{stepIndex === 3 && (
<ModalFooter horizontal alignItems="center" justifyContent="flex-end" flow={2}>
<Button onClick={onClose}>{t('common:close')}</Button>
<Button primary>{t('send:steps.confirmation.cta')}</Button>
</ModalFooter>
)}
</ModalBody>
)
@ -161,4 +234,4 @@ class SendModal extends PureComponent<Props, State> {
}
}
export default translate()(SendModal)
export default compose(connect(mapStateToProps), translate())(SendModal)

1
static/i18n/en/common.yml

@ -13,3 +13,4 @@ max: Max
next: Next
back: Back
retry: Retry
close: Close

1
static/i18n/en/send.yml

@ -17,3 +17,4 @@ steps:
title: Verification
confirmation:
title: Confirmation
cta: View operation details

183
yarn.lock

@ -26,18 +26,24 @@
version "0.0.6"
resolved "https://registry.yarnpkg.com/7zip/-/7zip-0.0.6.tgz#9cafb171af82329490353b4816f03347aa150a30"
"@babel/code-frame@7.0.0-beta.40", "@babel/code-frame@^7.0.0-beta.35", "@babel/code-frame@^7.0.0-beta.40":
version "7.0.0-beta.40"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.40.tgz#37e2b0cf7c56026b4b21d3927cadf81adec32ac6"
dependencies:
"@babel/highlight" "7.0.0-beta.40"
"@babel/code-frame@7.0.0-beta.42":
version "7.0.0-beta.42"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.42.tgz#a9c83233fa7cd06b39dc77adbb908616ff4f1962"
dependencies:
"@babel/highlight" "7.0.0-beta.42"
"@babel/code-frame@7.0.0-beta.44":
version "7.0.0-beta.44"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz#2a02643368de80916162be70865c97774f3adbd9"
dependencies:
"@babel/highlight" "7.0.0-beta.44"
"@babel/code-frame@^7.0.0-beta.35":
version "7.0.0-beta.40"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.40.tgz#37e2b0cf7c56026b4b21d3927cadf81adec32ac6"
dependencies:
"@babel/highlight" "7.0.0-beta.40"
"@babel/core@7.0.0-beta.42", "@babel/core@^7.0.0-beta.42":
version "7.0.0-beta.42"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.0.0-beta.42.tgz#b3a838fddbd19663369a0b4892189fd8d3f82001"
@ -58,21 +64,21 @@
semver "^5.4.1"
source-map "^0.5.0"
"@babel/generator@7.0.0-beta.40":
version "7.0.0-beta.40"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.40.tgz#ab61f9556f4f71dbd1138949c795bb9a21e302ea"
"@babel/generator@7.0.0-beta.42":
version "7.0.0-beta.42"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.42.tgz#777bb50f39c94a7e57f73202d833141f8159af33"
dependencies:
"@babel/types" "7.0.0-beta.40"
"@babel/types" "7.0.0-beta.42"
jsesc "^2.5.1"
lodash "^4.2.0"
source-map "^0.5.0"
trim-right "^1.0.1"
"@babel/generator@7.0.0-beta.42":
version "7.0.0-beta.42"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.42.tgz#777bb50f39c94a7e57f73202d833141f8159af33"
"@babel/generator@7.0.0-beta.44":
version "7.0.0-beta.44"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.44.tgz#c7e67b9b5284afcf69b309b50d7d37f3e5033d42"
dependencies:
"@babel/types" "7.0.0-beta.42"
"@babel/types" "7.0.0-beta.44"
jsesc "^2.5.1"
lodash "^4.2.0"
source-map "^0.5.0"
@ -127,14 +133,6 @@
"@babel/traverse" "7.0.0-beta.42"
"@babel/types" "7.0.0-beta.42"
"@babel/helper-function-name@7.0.0-beta.40":
version "7.0.0-beta.40"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.40.tgz#9d033341ab16517f40d43a73f2d81fc431ccd7b6"
dependencies:
"@babel/helper-get-function-arity" "7.0.0-beta.40"
"@babel/template" "7.0.0-beta.40"
"@babel/types" "7.0.0-beta.40"
"@babel/helper-function-name@7.0.0-beta.42":
version "7.0.0-beta.42"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.42.tgz#b38b8f4f85168d1812c543dd700b5d549b0c4658"
@ -143,11 +141,13 @@
"@babel/template" "7.0.0-beta.42"
"@babel/types" "7.0.0-beta.42"
"@babel/helper-get-function-arity@7.0.0-beta.40":
version "7.0.0-beta.40"
resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.40.tgz#ac0419cf067b0ec16453e1274f03878195791c6e"
"@babel/helper-function-name@7.0.0-beta.44":
version "7.0.0-beta.44"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz#e18552aaae2231100a6e485e03854bc3532d44dd"
dependencies:
"@babel/types" "7.0.0-beta.40"
"@babel/helper-get-function-arity" "7.0.0-beta.44"
"@babel/template" "7.0.0-beta.44"
"@babel/types" "7.0.0-beta.44"
"@babel/helper-get-function-arity@7.0.0-beta.42":
version "7.0.0-beta.42"
@ -155,6 +155,12 @@
dependencies:
"@babel/types" "7.0.0-beta.42"
"@babel/helper-get-function-arity@7.0.0-beta.44":
version "7.0.0-beta.44"
resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz#d03ca6dd2b9f7b0b1e6b32c56c72836140db3a15"
dependencies:
"@babel/types" "7.0.0-beta.44"
"@babel/helper-hoist-variables@7.0.0-beta.42":
version "7.0.0-beta.42"
resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.0.0-beta.42.tgz#6e51d75192923d96972a24c223b81126a7fabca1"
@ -235,6 +241,12 @@
dependencies:
"@babel/types" "7.0.0-beta.42"
"@babel/helper-split-export-declaration@7.0.0-beta.44":
version "7.0.0-beta.44"
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz#c0b351735e0fbcb3822c8ad8db4e583b05ebd9dc"
dependencies:
"@babel/types" "7.0.0-beta.44"
"@babel/helper-wrap-function@7.0.0-beta.42":
version "7.0.0-beta.42"
resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.0.0-beta.42.tgz#5ffc6576902aa2a10fe6666e063bd45029c36db3"
@ -268,6 +280,14 @@
esutils "^2.0.2"
js-tokens "^3.0.0"
"@babel/highlight@7.0.0-beta.44":
version "7.0.0-beta.44"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.44.tgz#18c94ce543916a80553edcdcf681890b200747d5"
dependencies:
chalk "^2.0.0"
esutils "^2.0.2"
js-tokens "^3.0.0"
"@babel/plugin-proposal-async-generator-functions@7.0.0-beta.42":
version "7.0.0-beta.42"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.0.0-beta.42.tgz#81465d19b6f5559092d9be4d11d6351131d08696"
@ -849,15 +869,6 @@
"@babel/plugin-syntax-dynamic-import" "7.0.0-beta.42"
"@babel/plugin-syntax-import-meta" "7.0.0-beta.42"
"@babel/template@7.0.0-beta.40":
version "7.0.0-beta.40"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.40.tgz#034988c6424eb5c3268fe6a608626de1f4410fc8"
dependencies:
"@babel/code-frame" "7.0.0-beta.40"
"@babel/types" "7.0.0-beta.40"
babylon "7.0.0-beta.40"
lodash "^4.2.0"
"@babel/template@7.0.0-beta.42":
version "7.0.0-beta.42"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.42.tgz#7186d4e70d44cdec975049ba0a73bdaf5cdee052"
@ -867,6 +878,15 @@
babylon "7.0.0-beta.42"
lodash "^4.2.0"
"@babel/template@7.0.0-beta.44":
version "7.0.0-beta.44"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.44.tgz#f8832f4fdcee5d59bf515e595fc5106c529b394f"
dependencies:
"@babel/code-frame" "7.0.0-beta.44"
"@babel/types" "7.0.0-beta.44"
babylon "7.0.0-beta.44"
lodash "^4.2.0"
"@babel/traverse@7.0.0-beta.42":
version "7.0.0-beta.42"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.42.tgz#f4bf4d1e33d41baf45205e2d0463591d57326285"
@ -882,16 +902,17 @@
invariant "^2.2.0"
lodash "^4.2.0"
"@babel/traverse@^7.0.0-beta.40":
version "7.0.0-beta.40"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.40.tgz#d140e449b2e093ef9fe1a2eecc28421ffb4e521e"
"@babel/traverse@7.0.0-beta.44":
version "7.0.0-beta.44"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.44.tgz#a970a2c45477ad18017e2e465a0606feee0d2966"
dependencies:
"@babel/code-frame" "7.0.0-beta.40"
"@babel/generator" "7.0.0-beta.40"
"@babel/helper-function-name" "7.0.0-beta.40"
"@babel/types" "7.0.0-beta.40"
babylon "7.0.0-beta.40"
debug "^3.0.1"
"@babel/code-frame" "7.0.0-beta.44"
"@babel/generator" "7.0.0-beta.44"
"@babel/helper-function-name" "7.0.0-beta.44"
"@babel/helper-split-export-declaration" "7.0.0-beta.44"
"@babel/types" "7.0.0-beta.44"
babylon "7.0.0-beta.44"
debug "^3.1.0"
globals "^11.1.0"
invariant "^2.2.0"
lodash "^4.2.0"
@ -904,7 +925,7 @@
lodash "^4.2.0"
to-fast-properties "^2.0.0"
"@babel/types@7.0.0-beta.40", "@babel/types@^7.0.0-beta.40":
"@babel/types@7.0.0-beta.40":
version "7.0.0-beta.40"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.40.tgz#25c3d7aae14126abe05fcb098c65a66b6d6b8c14"
dependencies:
@ -920,6 +941,14 @@
lodash "^4.2.0"
to-fast-properties "^2.0.0"
"@babel/types@7.0.0-beta.44":
version "7.0.0-beta.44"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.44.tgz#6b1b164591f77dec0a0342aca995f2d046b3a757"
dependencies:
esutils "^2.0.2"
lodash "^4.2.0"
to-fast-properties "^2.0.0"
"@ledgerhq/currencies@^4.10.1":
version "4.10.1"
resolved "https://registry.yarnpkg.com/@ledgerhq/currencies/-/currencies-4.10.1.tgz#462081005e3e37e0737bad9aba189eef1663e96a"
@ -1737,14 +1766,14 @@ babel-core@^6.0.0, babel-core@^6.26.0:
slash "^1.0.0"
source-map "^0.5.6"
babel-eslint@^8.2.1:
version "8.2.2"
resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.2.2.tgz#1102273354c6f0b29b4ea28a65f97d122296b68b"
babel-eslint@^8.2.3:
version "8.2.3"
resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.2.3.tgz#1a2e6681cc9bc4473c32899e59915e19cd6733cf"
dependencies:
"@babel/code-frame" "^7.0.0-beta.40"
"@babel/traverse" "^7.0.0-beta.40"
"@babel/types" "^7.0.0-beta.40"
babylon "^7.0.0-beta.40"
"@babel/code-frame" "7.0.0-beta.44"
"@babel/traverse" "7.0.0-beta.44"
"@babel/types" "7.0.0-beta.44"
babylon "7.0.0-beta.44"
eslint-scope "~3.7.1"
eslint-visitor-keys "^1.0.0"
@ -2689,14 +2718,14 @@ babylon@7.0.0-beta.31:
version "7.0.0-beta.31"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.31.tgz#7ec10f81e0e456fd0f855ad60fa30c2ac454283f"
babylon@7.0.0-beta.40, babylon@^7.0.0-beta.40:
version "7.0.0-beta.40"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.40.tgz#91fc8cd56d5eb98b28e6fde41045f2957779940a"
babylon@7.0.0-beta.42, babylon@^7.0.0-beta.30:
version "7.0.0-beta.42"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.42.tgz#67cfabcd4f3ec82999d29031ccdea89d0ba99657"
babylon@7.0.0-beta.44:
version "7.0.0-beta.44"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.44.tgz#89159e15e6e30c5096e22d738d8c0af8a0e8ca1d"
babylon@^6.17.3, babylon@^6.18.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
@ -4366,7 +4395,7 @@ debug@2.6.9, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.5.1, debug@^2.6.
dependencies:
ms "2.0.0"
debug@^3.0.0, debug@^3.0.1, debug@^3.1.0:
debug@^3.0.0, debug@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
dependencies:
@ -4671,9 +4700,9 @@ dotenv@^5.0.0, dotenv@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-5.0.1.tgz#a5317459bd3d79ab88cff6e44057a6a3fbb1fcef"
downshift@^1.31.6:
version "1.31.6"
resolved "https://registry.yarnpkg.com/downshift/-/downshift-1.31.6.tgz#467ef5bb81e68d2377c7ed2c602a43f81e68478f"
downshift@^1.31.7:
version "1.31.7"
resolved "https://registry.yarnpkg.com/downshift/-/downshift-1.31.7.tgz#65cad48fa6e4add9d6fd82cc9b9b5120e74d4604"
duplexer2@~0.1.4:
version "0.1.4"
@ -5217,9 +5246,9 @@ eslint-module-utils@^2.2.0:
debug "^2.6.8"
pkg-dir "^1.0.0"
eslint-plugin-flowtype@^2.46.0:
version "2.46.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.46.1.tgz#c4f81d580cd89c82bc3a85a1ccf4ae3a915143a4"
eslint-plugin-flowtype@^2.46.2:
version "2.46.2"
resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.46.2.tgz#8749fddda6f6c30d0672011151bea726765b5753"
dependencies:
lodash "^4.15.0"
@ -6715,9 +6744,9 @@ i18next-node-fs-backend@^1.0.0:
js-yaml "3.5.4"
json5 "0.5.0"
i18next@^11.1.1:
version "11.1.1"
resolved "https://registry.yarnpkg.com/i18next/-/i18next-11.1.1.tgz#df3a683542d7756a8aa8d6b884b61141239c394a"
i18next@^11.2.2:
version "11.2.2"
resolved "https://registry.yarnpkg.com/i18next/-/i18next-11.2.2.tgz#88b88bda08789841faa9c32b5266be63777be0cd"
iconv-lite@0.4, iconv-lite@0.4.19, iconv-lite@^0.4.17, iconv-lite@^0.4.19, iconv-lite@~0.4.13:
version "0.4.19"
@ -8577,10 +8606,14 @@ mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkd
dependencies:
minimist "0.0.8"
moment@^2.21.0, moment@^2.22.0:
moment@^2.21.0:
version "2.22.0"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.0.tgz#7921ade01017dd45186e7fee5f424f0b8663a730"
moment@^2.22.1:
version "2.22.1"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.1.tgz#529a2e9bf973f259c9643d237fda84de3a26e8ad"
move-concurrently@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
@ -9402,7 +9435,7 @@ pngjs@^3.3.0:
version "3.3.2"
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.3.2.tgz#097c3c2a75feb223eadddea6bc9f0050cf830bc3"
popper.js@^1.14.2:
popper.js@^1.14.3:
version "1.14.3"
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.14.3.tgz#1438f98d046acf7b4d78cd502bf418ac64d4f095"
@ -10146,9 +10179,9 @@ react-html-attributes@^1.3.0:
dependencies:
html-element-attributes "^1.0.0"
react-i18next@^7.5.1:
version "7.5.1"
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-7.5.1.tgz#5fe4cdfd2ecba22cc967213d880ab4cdd2c2ce61"
react-i18next@^7.6.0:
version "7.6.0"
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-7.6.0.tgz#abdb44b9dee5b43b4340590e25a6f7b04e2df6bc"
dependencies:
hoist-non-react-statics "^2.3.1"
html-parse-stringify2 "2.0.1"
@ -11953,11 +11986,11 @@ tinycolor2@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8"
tippy.js@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-2.5.0.tgz#393826b42aa1750268e0d2a4d6f047abe4c96d50"
tippy.js@^2.5.2:
version "2.5.2"
resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-2.5.2.tgz#01de112a80219032a3cf06ac2d29a4d69480705d"
dependencies:
popper.js "^1.14.2"
popper.js "^1.14.3"
tmp@^0.0.33:
version "0.0.33"

Loading…
Cancel
Save