Skip to content
This repository has been archived by the owner on Nov 17, 2023. It is now read-only.

Commit

Permalink
feat(ui): add Pay components
Browse files Browse the repository at this point in the history
Add components for updated Pay form and build out reference use case in
the storybook environment.
  • Loading branch information
mrfelton committed Nov 2, 2018
1 parent 3d53d70 commit fcafdec
Show file tree
Hide file tree
Showing 22 changed files with 2,138 additions and 6 deletions.
702 changes: 702 additions & 0 deletions app/components/Pay/Pay.js

Large diffs are not rendered by default.

74 changes: 74 additions & 0 deletions app/components/Pay/PayButtons.js
@@ -0,0 +1,74 @@
import React from 'react'
import PropTypes from 'prop-types'
import { FormattedMessage } from 'react-intl'
import { Box, Flex, Text } from 'rebass'
import BigArrowLeft from 'components/Icon/BigArrowLeft'
import { Button } from 'components/UI'
import messages from './messages'

/**
* Buttons for Pay.
*/
class PayButtons extends React.PureComponent {
static propTypes = {
disabled: PropTypes.bool,
nextButtonText: PropTypes.node,
previousStep: PropTypes.func,
processing: PropTypes.bool,
showBack: PropTypes.bool,
showSubmit: PropTypes.bool
}

static defaultProps = {
disabled: false,
nextButtonText: <FormattedMessage {...messages.next} />,
previousStep: () => ({}),
processing: false,
showBack: true,
showSubmit: true
}

render() {
const {
disabled,
nextButtonText,
previousStep,
processing,
showBack,
showSubmit,
...rest
} = this.props
return (
<Flex {...rest} justifyContent="space-between" alignItems="center">
<Box width={1 / 5}>
{showBack && (
<Button
type="button"
variant="secondary"
onClick={previousStep}
px={0}
disabled={processing}
>
<Flex>
<Text>
<BigArrowLeft />
</Text>
<Text ml={1}>
<FormattedMessage {...messages.back} />
</Text>
</Flex>
</Button>
)}
</Box>
{showSubmit && (
<Button type="submit" mx="auto" disabled={disabled || processing} processing={processing}>
{nextButtonText}
</Button>
)}
<Box width={1 / 5} />
</Flex>
)
}
}

export default PayButtons
37 changes: 37 additions & 0 deletions app/components/Pay/PayHeader.js
@@ -0,0 +1,37 @@
import React from 'react'
import PropTypes from 'prop-types'
import { Box } from 'rebass'
import { Heading, Text } from 'components/UI'
import Lightning from 'components/Icon/Lightning'
import Onchain from 'components/Icon/Onchain'
import PaperPlane from 'components/Icon/PaperPlane'

/**
* Header for opayment form.
*/
class PayHeader extends React.PureComponent {
static propTypes = {
title: PropTypes.string.isRequired,
type: PropTypes.oneOf(['onchain', 'offchain'])
}

render() {
const { title, type } = this.props
return (
<Text textAlign="center">
<Box mx="auto" css={{ height: '55px' }}>
{type === 'offchain' && <Lightning height="45px" width="45px" />}
{type === 'onchain' && <Onchain height="45px" width="45px" />}
{!type && <PaperPlane height="35px" width="35px" />}
</Box>
<Heading.h1 mx="auto">{title}</Heading.h1>
<Heading.h4 mx="auto">
&nbsp;
{type === 'onchain' && 'On-Chain Payment'} {type === 'offchain' && 'Lightning Payment'}
</Heading.h4>
</Text>
)
}
}

export default PayHeader
163 changes: 163 additions & 0 deletions app/components/Pay/PaySummaryLightning.js
@@ -0,0 +1,163 @@
import React from 'react'
import PropTypes from 'prop-types'
import { Box, Flex } from 'rebass'
import { FormattedNumber, FormattedMessage } from 'react-intl'
import lightningPayReq from 'bolt11'
import { satoshisToFiat } from 'lib/utils/btc'
import { getNodeAlias } from 'lib/utils/crypto'
import BigArrowRight from 'components/Icon/BigArrowRight'
import { Bar, Dropdown, Spinner, Text, Truncate } from 'components/UI'
import Value from 'components/Value'
import { PaySummaryRow } from '.'
import messages from './messages'

class PaySummaryLightning extends React.PureComponent {
static propTypes = {
/** Current ticker data as provided by blockchain.info */
currentTicker: PropTypes.object.isRequired,
/** Currently selected cryptocurrency (key). */
cryptoCurrency: PropTypes.string.isRequired,
/** Ticker symbol of the currently selected cryptocurrency. */
cryptoCurrencyTicker: PropTypes.string.isRequired,
/** List of supported cryptocurrencies. */
cryptoCurrencies: PropTypes.arrayOf(
PropTypes.shape({
key: PropTypes.string.isRequired,
name: PropTypes.string.isRequired
})
).isRequired,
/** Currently selected fiat currency (key). */
fiatCurrency: PropTypes.string.isRequired,
/** Boolean indicating wether routing information is currently being fetched. */
isQueryingRoutes: PropTypes.bool,
/** Maximum fee for the payment */
maxFee: PropTypes.number,
/** Minimumfee for the payment */
minFee: PropTypes.number,
/** List of nodes as returned by lnd */
nodes: PropTypes.array,
/** Lightning Payment request */
payReq: PropTypes.string.isRequired,

/** Set the current cryptocurrency. */
setCryptoCurrency: PropTypes.func.isRequired
}

static defaultProps = {
isQueryingRoutes: false,
minFee: null,
maxFee: null,
nodes: []
}

render() {
const {
cryptoCurrency,
cryptoCurrencyTicker,
cryptoCurrencies,
currentTicker,
fiatCurrency,
isQueryingRoutes,
maxFee,
minFee,
nodes,
payReq,
setCryptoCurrency
} = this.props

let invoice
try {
invoice = lightningPayReq.decode(payReq)
} catch (e) {
return null
}

const { satoshis, payeeNodeKey } = invoice
const descriptionTag = invoice.tags.find(tag => tag.tagName === 'description') || {}
const memo = descriptionTag.data
const fiatAmount = satoshisToFiat(satoshis, currentTicker[fiatCurrency].last)
const nodeAlias = getNodeAlias(payeeNodeKey, nodes)

return (
<React.Fragment>
<Box pb={2}>
<Flex alignItems="center">
<Box width={5 / 11}>
<Flex flexWrap="wrap" alignItems="baseline">
<Box>
<Text textAlign="left" fontSize={6}>
<Value value={satoshis} currency={cryptoCurrency} />
</Text>
</Box>
<Dropdown
activeKey={cryptoCurrency}
items={cryptoCurrencies}
onChange={setCryptoCurrency}
ml={2}
/>
</Flex>
<Text color="gray">
{'≈ '}
<FormattedNumber currency={fiatCurrency} style="currency" value={fiatAmount} />
</Text>
</Box>
<Box width={1 / 11}>
<Text textAlign="center" color="lightningOrange">
<BigArrowRight width="40px" height="28px" />
</Text>
</Box>
<Box width={5 / 11}>
<Text textAlign="right" className="hint--bottom-left" data-hint={payeeNodeKey}>
{<Truncate text={nodeAlias || payeeNodeKey} />}
</Text>
</Box>
</Flex>
</Box>

<Bar />

<PaySummaryRow
left={<FormattedMessage {...messages.fee} />}
right={
isQueryingRoutes ? (
<Flex ml="auto" alignItems="center" justifyContent="flex-end">
<Text mr={2}>
<FormattedMessage {...messages.searching_routes} />
&hellip;
</Text>
<Spinner color="lightningOrange" />
</Flex>
) : minFee === null || maxFee === null ? (
<FormattedMessage {...messages.unknown} />
) : (
<FormattedMessage {...messages.fee_range} values={{ minFee, maxFee }} />
)
}
/>

<Bar />

<PaySummaryRow
left={<FormattedMessage {...messages.total} />}
right={
<React.Fragment>
<Value value={satoshis} currency={cryptoCurrency} /> {cryptoCurrencyTicker}
{!isQueryingRoutes &&
maxFee && (
<Text fontSize="s">
(+ <FormattedMessage {...messages.upto} /> {maxFee} msats)
</Text>
)}
</React.Fragment>
}
/>

<Bar />

{memo && <PaySummaryRow left={<FormattedMessage {...messages.memo} />} right={memo} />}
</React.Fragment>
)
}
}

export default PaySummaryLightning

0 comments on commit fcafdec

Please sign in to comment.