Browse Source

Feedback, add errors and warning on BreadCrumb

master
Loëck Vézien 7 years ago
parent
commit
371084ff3c
No known key found for this signature in database GPG Key ID: CBCDCE384E853AC4
  1. 35
      src/components/Breadcrumb/Step.js
  2. 56
      src/components/Breadcrumb/index.js
  3. 8
      src/components/Breadcrumb/stories.js
  4. 20
      src/components/CurrentAddress/index.js
  5. 2
      src/components/CurrentAddress/stories.js
  6. 172
      src/components/DeviceConfirm/index.js
  7. 4
      src/components/layout/Print.js
  8. 2
      src/components/modals/Receive/03-step-confirm-address.js
  9. 2
      src/components/modals/Receive/04-step-receive-funds.js
  10. 18
      src/components/modals/Receive/index.js
  11. 2
      src/styles/theme.js

35
src/components/Breadcrumb/Step.js

@ -5,11 +5,15 @@ import styled from 'styled-components'
import Box from 'components/base/Box'
const RADIUS = 17
import IconCheck from 'icons/Check'
import IconCross from 'icons/Cross'
const RADIUS = 18
const Wrapper = styled(Box).attrs({
alignItems: 'center',
color: p => (p.isActive ? 'wallet' : 'grey'),
color: p =>
['active', 'valid'].includes(p.status) ? 'wallet' : p.status === 'error' ? 'alertRed' : 'grey',
grow: true,
justifyContent: 'center',
})`
@ -19,18 +23,19 @@ const Wrapper = styled(Box).attrs({
font-size: 9px;
`
const Number = styled(Box).attrs({
const StepNumber = styled(Box).attrs({
alignItems: 'center',
justifyContent: 'center',
color: 'white',
bg: p => (p.isActive ? 'wallet' : 'fog'),
bg: p =>
['active', 'valid'].includes(p.status) ? 'wallet' : p.status === 'error' ? 'alertRed' : 'fog',
ff: 'Rubik|Regular',
})`
border-radius: 50%;
font-size: 10px;
height: ${RADIUS}px;
line-height: 10px;
transition: all ease-in-out 0.1s ${p => (p.isActive ? 0.4 : 0)}s;
transition: all ease-in-out 0.1s ${p => (['active', 'valid'].includes(p.status) ? 0.4 : 0)}s;
width: ${RADIUS}px;
`
@ -40,21 +45,29 @@ const Label = styled(Box).attrs({
})`
position: absolute;
margin-top: 23px;
transition: color ease-in-out 0.1s ${p => (p.isActive ? 0.4 : 0)}s;
transition: color ease-in-out 0.1s ${p => (['active', 'valid'].includes(p.status) ? 0.4 : 0)}s;
`
type Props = {
number: number,
isActive: boolean,
status: 'next' | 'active' | 'valid' | 'error' | 'disable',
children: any,
}
function Step(props: Props) {
const { number, isActive, children } = props
const { number, status, children } = props
return (
<Wrapper isActive={isActive}>
<Number isActive={isActive}>{number}</Number>
<Label isActive={isActive}>{children}</Label>
<Wrapper status={status}>
<StepNumber status={status}>
{status === 'active' || status === 'next' ? (
number
) : status === 'valid' ? (
<IconCheck size={10} />
) : (
<IconCross size={10} />
)}
</StepNumber>
<Label status={status}>{children}</Label>
</Wrapper>
)
}

56
src/components/Breadcrumb/index.js

@ -8,11 +8,6 @@ import styled from 'styled-components'
import Box from 'components/base/Box'
import Step from './Step'
type Props = {
items: Array<Object>,
currentStep: number | string,
}
const Wrapper = styled(Box).attrs({
horizontal: true,
alignItems: 'center',
@ -46,24 +41,53 @@ const Bar = styled.div`
}
`
type Props = {
currentStep: number | string,
items: Array<Object>,
stepsDisabled: Array<number>,
stepsErrors: Array<number>,
}
class Breadcrumb extends PureComponent<Props> {
static defaultProps = {
stepsDisabled: [],
stepsErrors: [],
}
render() {
const { items, currentStep, ...props } = this.props
const { items, stepsDisabled, stepsErrors, currentStep, ...props } = this.props
const itemsLength = items.length
const start = 100 / itemsLength / 2
return (
<Box {...props} relative>
<Wrapper>
{items.map((item, i) => (
<Step
key={i}
isActive={i <= parseInt(currentStep, 10)}
isFirst={i === 0}
number={i + 1}
>
{item.label}
</Step>
))}
{items.map((item, i) => {
let status = 'next'
const stepIndex = parseInt(currentStep, 10)
if (i === stepIndex) {
status = 'active'
}
if (i < stepIndex) {
status = 'valid'
}
if (stepsErrors.includes(i)) {
status = 'error'
}
if (stepsDisabled.includes(i)) {
status = 'disable'
}
return (
<Step key={i} status={status} number={i + 1}>
{item.label}
</Step>
)
})}
</Wrapper>
<Bar
start={start}

8
src/components/Breadcrumb/stories.js

@ -2,7 +2,7 @@
import React from 'react'
import { storiesOf } from '@storybook/react'
import { number } from '@storybook/addon-knobs'
import { array, number } from '@storybook/addon-knobs'
import Breadcrumb from 'components/Breadcrumb'
@ -16,9 +16,11 @@ stories.add('Breadcrumb', () => (
>
<Breadcrumb
currentStep={number('currentStep', 1, {
min: 1,
max: 4,
min: 0,
max: 3,
})}
stepsDisabled={array('stepsDisabled', []).map(a => Number(a))}
stepsErrors={array('stepsErrors', []).map(a => Number(a))}
items={[
{ label: 'Amount' },
{ label: 'Summary' },

20
src/components/CurrentAddress/index.js

@ -6,7 +6,6 @@ import styled from 'styled-components'
import noop from 'lodash/noop'
import type { Account } from '@ledgerhq/wallet-common/lib/types'
import type { T } from 'types/common'
import { rgba } from 'styles/helpers'
@ -101,9 +100,9 @@ const FooterButton = ({
)
type Props = {
account: Account,
addressVerified: null | boolean,
amount: null | string,
address: string,
addressVerified?: boolean,
amount?: string,
onCopy: Function,
onPrint: Function,
onShare: Function,
@ -131,7 +130,7 @@ class CurrentAddress extends PureComponent<Props> {
render() {
const {
account,
address,
addressVerified,
amount,
onCopy,
@ -153,10 +152,7 @@ class CurrentAddress extends PureComponent<Props> {
<WrapperAddress notValid={notValid} grow>
{withQRCode && (
<Box mb={4}>
<QRCode
size={150}
data={`bitcoin:${account.address}${amount ? `?amount=${amount}` : ''}`}
/>
<QRCode size={150} data={`bitcoin:${address}${amount ? `?amount=${amount}` : ''}`} />
</Box>
)}
<Label>
@ -164,7 +160,7 @@ class CurrentAddress extends PureComponent<Props> {
<IconInfoCircle size={12} />
</Label>
<Address withQRCode={withQRCode} notValid={notValid}>
{account.address}
{address}
</Address>
</WrapperAddress>
{withBadge && (
@ -184,13 +180,13 @@ class CurrentAddress extends PureComponent<Props> {
<FooterButton icon={<IconCheck size={16} />} label="Verify" onClick={onVerify} />
)}
<CopyToClipboard
data={account.address}
data={address}
render={copy => (
<FooterButton icon={<IconCopy size={16} />} label="Copy" onClick={copy} />
)}
/>
<Print
data={{ account, amount }}
data={{ address, amount }}
render={(print, isLoading) => (
<FooterButton
icon={<IconPrint size={16} />}

2
src/components/CurrentAddress/stories.js

@ -12,7 +12,7 @@ const stories = storiesOf('Components', module)
stories.add('CurrentAddress', () => (
<CurrentAddress
account={accounts[0]}
address={accounts[0].address}
addressVerified={boolean('addressVerified', true)}
withBadge={boolean('withBadge', false)}
withFooter={boolean('withFooter', false)}

172
src/components/DeviceConfirm/index.js

@ -27,23 +27,23 @@ const Wrapper = styled(Box).attrs({
relative: true,
})`
padding-top: ${p => (p.notValid ? 0 : 30)}px;
transition: all ease-in-out 0.1s;
transition: color ease-in-out 0.1s;
`
const WrapperIcon = styled(Box)`
color: ${p => (p.notValid ? p.theme.colors.alertRed : p.theme.colors.positiveGreen)};
position: absolute;
left: 193px;
left: ${p => (p.notValid ? 152 : 193)}px;
bottom: 16px;
svg {
transition: all ease-in-out 0.1s;
transition: color ease-in-out 0.1s;
}
`
const Check = ({ notValid }: { notValid: boolean }) => (
<WrapperIcon notValid={notValid}>
{notValid ? <IconCross size={11} /> : <IconCheck size={11} />}
{notValid ? <IconCross size={10} /> : <IconCheck size={10} />}
</WrapperIcon>
)
@ -77,99 +77,97 @@ type Props = {
notValid: boolean,
}
const DeviceConfirm = (props: Props) => (
<Wrapper {...props}>
{!props.notValid && <PushButton />}
<Check notValid={props.notValid} />
<svg width="365" height="44">
<defs>
<rect id="a" width="41.7112299" height="238.383838" rx="4.00000006" />
const SVG = (
<svg width="365" height="44">
<defs>
<rect id="DeviceConfirm-a" width="41.7112299" height="238.383838" rx="4.00000006" />
<rect
id="DeviceConfirm-b"
width="21.1764706"
height="62.0185596"
x="10.2673797"
y="20.6728532"
rx="1.60000002"
/>
<path
id="DeviceConfirm-c"
d="M20.855615 94.9659194c11.5182381 0 20.8556149 9.3373766 20.8556149 20.8556146v118.562304c0 2.209139-1.790861 4-4 4H4.00000006c-2.20913903 0-4.00000006-1.790861-4.00000006-4V115.821534c0-11.518238 9.33737688-20.8556146 20.855615-20.8556146z"
/>
<linearGradient id="DeviceConfirm-d" x1="50%" x2="50%" y1="0%" y2="100%">
<stop offset="0%" />
<stop offset="100%" stopColor="#FFF" />
</linearGradient>
</defs>
<g fill="none" fillRule="evenodd">
<g transform="rotate(-90 85.0909095 -41.5252525)">
<rect
id="b"
width="21.1764706"
height="62.0185596"
x="10.2673797"
y="20.6728532"
rx="1.60000002"
width="4.49197861"
height="17.1197066"
x="38.3363042"
y="15.5046399"
fill="#142533"
rx="2"
/>
<path
id="c"
d="M20.855615 94.9659194c11.5182381 0 20.8556149 9.3373766 20.8556149 20.8556146v118.562304c0 2.209139-1.790861 4-4 4H4.00000006c-2.20913903 0-4.00000006-1.790861-4.00000006-4V115.821534c0-11.518238 9.33737688-20.8556146 20.855615-20.8556146z"
<rect
width="4.49197861"
height="17.1197066"
x="38.3363042"
y="70.0938929"
fill="#142533"
rx="2"
/>
<linearGradient id="d" x1="50%" x2="50%" y1="0%" y2="100%">
<stop offset="0%" />
<stop offset="100%" stopColor="#FFF" />
</linearGradient>
</defs>
<g fill="none" fillRule="evenodd">
<g transform="rotate(-90 85.0909095 -41.5252525)">
<rect
width="4.49197861"
height="17.1197066"
x="38.3363042"
y="15.5046399"
fill="#142533"
rx="2"
/>
<rect
width="4.49197861"
height="17.1197066"
x="38.3363042"
y="70.0938929"
fill="#142533"
rx="2"
/>
<use fill="#FFF" xlinkHref="#a" />
<use fill="currentColor" fillOpacity=".14999999" xlinkHref="#a" />
<rect
width="39.7112299"
height="236.383838"
x="1"
y="1"
stroke="#142533"
strokeWidth="2"
rx="4.00000006"
/>
<use fill="#FFF" xlinkHref="#b" />
<rect
width="20.1764706"
height="61.0185596"
x="10.7673797"
y="21.1728532"
stroke="currentColor"
rx="1.60000002"
/>
<use fill="#FFF" xlinkHref="#c" />
<path
stroke="#142533"
strokeWidth="2"
d="M20.855615 95.9659194C9.88966163 95.9659194 1 104.855581 1 115.821534v118.562304c0 1.656855 1.34314578 3 3.00000006 3H37.7112299c1.6568543 0 3-1.343145 3-3V115.821534c0-10.965953-8.8896616-19.8556146-19.8556149-19.8556146z"
/>
<ellipse
cx="21.0160428"
cy="116.123293"
stroke="#142533"
rx="10.5695187"
ry="10.6439599"
/>
</g>
<path
stroke="#1D2027"
<use fill="#FFF" xlinkHref="#DeviceConfirm-a" />
<use fill="currentColor" fillOpacity=".14999999" xlinkHref="#DeviceConfirm-a" />
<rect
width="39.7112299"
height="236.383838"
x="1"
y="1"
stroke="#142533"
strokeWidth="2"
d="M126.9617746 31.060606c0 .55228475-.4477153 1-1 1H99.7373741c-2.7614237 0-5-2.23857625-5-5v-8.4856683c0-2.7614238 2.2385763-5 5-5h26.2244005c.5522847 0 1 .4477152 1 1V31.060606z"
rx="4.00000006"
/>
<use fill="#FFF" xlinkHref="#DeviceConfirm-b" />
<rect
width="20.1764706"
height="61.0185596"
x="10.7673797"
y="21.1728532"
stroke="currentColor"
rx="1.60000002"
/>
<use fill="#FFF" xlinkHref="#DeviceConfirm-c" />
<path
stroke="#142533"
strokeWidth="2"
d="M94.3535357 25.85229841H83.4242428V19.4170232h10.9292929v6.43527521z"
/>
<path
fill="url(#d)"
d="M6.83618598 57.9245106h1.61616161v82.6510534H6.83618598V57.9245106zm5.65656562 0h1.6161617v82.6510534h-1.6161617V57.9245106z"
transform="matrix(0 -1 -1 0 140.606061 33.060606)"
d="M20.855615 95.9659194C9.88966163 95.9659194 1 104.855581 1 115.821534v118.562304c0 1.656855 1.34314578 3 3.00000006 3H37.7112299c1.6568543 0 3-1.343145 3-3V115.821534c0-10.965953-8.8896616-19.8556146-19.8556149-19.8556146z"
/>
<ellipse cx="21.0160428" cy="116.123293" stroke="#142533" rx="10.5695187" ry="10.6439599" />
</g>
</svg>
<path
stroke="#1D2027"
strokeWidth="2"
d="M126.9617746 31.060606c0 .55228475-.4477153 1-1 1H99.7373741c-2.7614237 0-5-2.23857625-5-5v-8.4856683c0-2.7614238 2.2385763-5 5-5h26.2244005c.5522847 0 1 .4477152 1 1V31.060606z"
/>
<path
stroke="#142533"
strokeWidth="2"
d="M94.3535357 25.85229841H83.4242428V19.4170232h10.9292929v6.43527521z"
/>
<path
fill="url(#DeviceConfirm-d)"
d="M6.83618598 57.9245106h1.61616161v82.6510534H6.83618598V57.9245106zm5.65656562 0h1.6161617v82.6510534h-1.6161617V57.9245106z"
transform="matrix(0 -1 -1 0 140.606061 33.060606)"
/>
</g>
</svg>
)
const DeviceConfirm = (props: Props) => (
<Wrapper {...props}>
{!props.notValid && <PushButton />}
<Check notValid={props.notValid} />
{SVG}
</Wrapper>
)

4
src/components/layout/Print.js

@ -31,12 +31,12 @@ class Print extends PureComponent<any> {
if (!data) {
return null
}
const { account, amount } = data
const { address, amount } = data
return (
<CurrentAddress
innerRef={n => (this._node = n)}
amount={amount}
account={account}
address={address}
withQRCode
/>
)

2
src/components/modals/Receive/03-step-confirm-address.js

@ -42,7 +42,7 @@ export default (props: Props) => (
<Title>{props.t('receive:steps.confirmAddress.action')}</Title>
<Text>{props.t('receive:steps.confirmAddress.text')}</Text>
{props.account && (
<CurrentAddress addressVerified={props.addressVerified} account={props.account} />
<CurrentAddress addressVerified={props.addressVerified} address={props.account.address} />
)}
{props.device &&
props.account && (

2
src/components/modals/Receive/04-step-receive-funds.js

@ -36,7 +36,7 @@ export default (props: Props) => (
/>
</Box>
<CurrentAddress
account={props.account}
address={props.account && props.account.address}
addressVerified={props.addressVerified}
amount={props.amount}
onVerify={props.onVerify}

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

@ -35,11 +35,13 @@ type Props = {
type State = {
account: Account | null,
amount: string | number,
addressVerified: null | boolean,
amount: string | number,
appStatus: null | string,
deviceSelected: Device | null,
stepIndex: number,
stepsDisabled: Array<number>,
stepsErrors: Array<number>,
}
const GET_STEPS = t => [
@ -56,6 +58,8 @@ const INITIAL_STATE = {
appStatus: null,
deviceSelected: null,
stepIndex: 0,
stepsDisabled: [],
stepsErrors: [],
}
class ReceiveModal extends PureComponent<Props, State> {
@ -137,6 +141,7 @@ class ReceiveModal extends PureComponent<Props, State> {
deviceSelected: null,
appStatus: null,
addressVerified: null,
stepsErrors: [],
stepIndex: newStepIndex,
})
}
@ -150,6 +155,7 @@ class ReceiveModal extends PureComponent<Props, State> {
handleCheckAddress = isVerified => {
this.setState({
addressVerified: isVerified,
stepsErrors: isVerified === false ? [2] : [],
})
if (isVerified === true) {
@ -172,6 +178,7 @@ class ReceiveModal extends PureComponent<Props, State> {
handleSkipStep = () =>
this.setState({
addressVerified: false,
stepsErrors: [],
stepIndex: this._steps.length - 1, // last step
})
@ -252,7 +259,7 @@ class ReceiveModal extends PureComponent<Props, State> {
render() {
const { t } = this.props
const { stepIndex } = this.state
const { stepsErrors, stepIndex } = this.state
const canClose = this.canClose()
const canPrev = this.canPrev()
@ -277,7 +284,12 @@ class ReceiveModal extends PureComponent<Props, State> {
{t('receive:title')}
</ModalTitle>
<ModalContent>
<Breadcrumb mb={5} currentStep={stepIndex} items={this._steps} />
<Breadcrumb
mb={5}
currentStep={stepIndex}
stepsErrors={stepsErrors}
items={this._steps}
/>
{this.renderStep()}
</ModalContent>
{stepIndex !== 3 &&

2
src/styles/theme.js

@ -66,7 +66,7 @@ export const colors = {
pearl: '#ff0000',
// new colors
alertRed: '#fa4352',
alertRed: '#ea2e49',
black: '#000000',
dark: '#142533',
fog: '#d8d8d8',

Loading…
Cancel
Save