5 changed files with 722 additions and 0 deletions
@ -0,0 +1,368 @@ |
|||
import React from 'react' |
|||
import PropTypes from 'prop-types' |
|||
import { Box, Flex } from 'rebass' |
|||
import { FormattedMessage, injectIntl } from 'react-intl' |
|||
import { convert } from 'lib/utils/btc' |
|||
import { |
|||
Bar, |
|||
Button, |
|||
CryptoAmountInput, |
|||
Dropdown, |
|||
FiatAmountInput, |
|||
Form, |
|||
Header, |
|||
Label, |
|||
Panel, |
|||
Text, |
|||
TextArea |
|||
} from 'components/UI' |
|||
import Lightning from 'components/Icon/Lightning' |
|||
import { RequestSummary } from '.' |
|||
import messages from './messages' |
|||
|
|||
/** |
|||
* Request form. |
|||
*/ |
|||
class Request extends React.Component { |
|||
state = { |
|||
currentStep: 'form' |
|||
} |
|||
|
|||
static propTypes = { |
|||
/** Human readable chain name */ |
|||
cryptoName: PropTypes.string.isRequired, |
|||
/** 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, |
|||
/** List of supported fiat currencies. */ |
|||
fiatCurrencies: PropTypes.array.isRequired, |
|||
/** Currently selected fiat currency (key). */ |
|||
fiatCurrency: PropTypes.string.isRequired, |
|||
/** Boolean indicating wether the form is being processed. If true, form buttons are disabled. */ |
|||
isProcessing: PropTypes.bool, |
|||
/** Boolean indicating wether the invoice has already been paid. */ |
|||
isPaid: PropTypes.bool, |
|||
/** Lightning Payment request. */ |
|||
payReq: PropTypes.string, |
|||
/** Set the current cryptocurrency. */ |
|||
setCryptoCurrency: PropTypes.func.isRequired, |
|||
/** Set the current fiat currency */ |
|||
setFiatCurrency: PropTypes.func.isRequired, |
|||
/** Create an invoice using the supplied details */ |
|||
createInvoice: PropTypes.func.isRequired |
|||
} |
|||
|
|||
static defaultProps = { |
|||
isProcessing: false, |
|||
isPaid: false, |
|||
payReq: null |
|||
} |
|||
|
|||
amountInput = React.createRef() |
|||
|
|||
componentDidMount() { |
|||
this.focusAmountInput() |
|||
} |
|||
|
|||
componentDidUpdate(prevProps) { |
|||
const { payReq } = this.props |
|||
const { currentStep } = this.state |
|||
if (payReq !== prevProps.payReq && currentStep === 'form') { |
|||
this.nextStep() |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Liost of enabled form steps. |
|||
*/ |
|||
steps = () => { |
|||
return ['form', 'summary'] |
|||
} |
|||
|
|||
/** |
|||
* Go back to previous form step. |
|||
*/ |
|||
previousStep = () => { |
|||
const { currentStep } = this.state |
|||
const nextStep = Math.max(this.steps().indexOf(currentStep) - 1, 0) |
|||
if (currentStep !== nextStep) { |
|||
this.setState({ currentStep: this.steps()[nextStep] }) |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Progress to next form step. |
|||
*/ |
|||
nextStep = () => { |
|||
const { currentStep } = this.state |
|||
const nextStep = Math.min(this.steps().indexOf(currentStep) + 1, this.steps().length - 1) |
|||
if (currentStep !== nextStep) { |
|||
this.setState({ currentStep: this.steps()[nextStep] }) |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Form submit handler. |
|||
* @param {Object} values submitted form values. |
|||
*/ |
|||
onSubmit = values => { |
|||
const { cryptoCurrency, createInvoice } = this.props |
|||
createInvoice(values.amountCrypto, cryptoCurrency, values.memo) |
|||
} |
|||
|
|||
/** |
|||
* Store the formApi on the component context to make it available at this.formApi. |
|||
*/ |
|||
setFormApi = formApi => { |
|||
this.formApi = formApi |
|||
} |
|||
|
|||
/** |
|||
* Focus the amount input. |
|||
*/ |
|||
focusAmountInput = () => { |
|||
if (this.amountInput.current) { |
|||
this.amountInput.current.focus() |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* set the amountFiat field whenever the crypto amount changes. |
|||
*/ |
|||
handleAmountCryptoChange = e => { |
|||
const { cryptoCurrency, currentTicker, fiatCurrency } = this.props |
|||
const lastPrice = currentTicker[fiatCurrency].last |
|||
const value = convert(cryptoCurrency, 'fiat', e.target.value, lastPrice) |
|||
this.formApi.setValue('amountFiat', value) |
|||
} |
|||
|
|||
/** |
|||
* set the amountCrypto field whenever the fiat amount changes. |
|||
*/ |
|||
handleAmountFiatChange = e => { |
|||
const { cryptoCurrency, currentTicker, fiatCurrency } = this.props |
|||
const lastPrice = currentTicker[fiatCurrency].last |
|||
const value = convert('fiat', cryptoCurrency, e.target.value, lastPrice) |
|||
this.formApi.setValue('amountCrypto', value) |
|||
} |
|||
|
|||
/** |
|||
* Handle changes from the crypto currency dropdown. |
|||
*/ |
|||
handleCryptoCurrencyChange = value => { |
|||
const { setCryptoCurrency } = this.props |
|||
setCryptoCurrency(value) |
|||
} |
|||
|
|||
/** |
|||
* Handle changes from the fiat currency dropdown. |
|||
*/ |
|||
handleFiatCurrencyChange = value => { |
|||
const { setFiatCurrency } = this.props |
|||
setFiatCurrency(value) |
|||
} |
|||
|
|||
renderHelpText = () => { |
|||
return ( |
|||
<Box mb={4}> |
|||
<Text textAlign="justify"> |
|||
<FormattedMessage {...messages.description} /> |
|||
</Text> |
|||
</Box> |
|||
) |
|||
} |
|||
|
|||
renderAmountFields = () => { |
|||
const { |
|||
cryptoCurrency, |
|||
cryptoCurrencies, |
|||
currentTicker, |
|||
fiatCurrency, |
|||
fiatCurrencies |
|||
} = this.props |
|||
|
|||
return ( |
|||
<Box> |
|||
<Label htmlFor="amountCrypto" pb={2}> |
|||
<FormattedMessage {...messages.amount} /> |
|||
</Label> |
|||
|
|||
<Flex justifyContent="space-between" alignItems="flex-start" mb={3}> |
|||
<Flex width={6 / 13}> |
|||
<Box width={150}> |
|||
<CryptoAmountInput |
|||
field="amountCrypto" |
|||
name="amountCrypto" |
|||
currency={cryptoCurrency} |
|||
required |
|||
width={150} |
|||
validateOnChange |
|||
validateOnBlur |
|||
onChange={this.handleAmountCryptoChange} |
|||
forwardedRef={this.amountInput} |
|||
/> |
|||
</Box> |
|||
<Dropdown |
|||
activeKey={cryptoCurrency} |
|||
items={cryptoCurrencies} |
|||
onChange={this.handleCryptoCurrencyChange} |
|||
mt={3} |
|||
ml={2} |
|||
/> |
|||
</Flex> |
|||
<Text textAlign="center" mt={3} width={1 / 11}> |
|||
= |
|||
</Text> |
|||
<Flex width={6 / 13}> |
|||
<Box width={150} ml="auto"> |
|||
<FiatAmountInput |
|||
field="amountFiat" |
|||
name="amountFiat" |
|||
currency={fiatCurrency} |
|||
currentTicker={currentTicker} |
|||
width={150} |
|||
onChange={this.handleAmountFiatChange} |
|||
/> |
|||
</Box> |
|||
|
|||
<Dropdown |
|||
activeKey={fiatCurrency} |
|||
items={fiatCurrencies} |
|||
onChange={this.handleFiatCurrencyChange} |
|||
mt={3} |
|||
ml={2} |
|||
/> |
|||
</Flex> |
|||
</Flex> |
|||
</Box> |
|||
) |
|||
} |
|||
|
|||
renderMemoField = () => { |
|||
const { intl } = this.props |
|||
return ( |
|||
<Box> |
|||
<Box pb={2}> |
|||
<Label htmlFor="memo"> |
|||
<FormattedMessage {...messages.memo} /> |
|||
</Label> |
|||
</Box> |
|||
|
|||
<TextArea |
|||
field="memo" |
|||
name="memo" |
|||
validateOnBlur |
|||
validateOnChange |
|||
placeholder={intl.formatMessage({ ...messages.memo_placeholder })} |
|||
width={1} |
|||
rows={3} |
|||
css={{ resize: 'vertical', 'min-height': '48px' }} |
|||
/> |
|||
</Box> |
|||
) |
|||
} |
|||
|
|||
/** |
|||
* Form renderer. |
|||
*/ |
|||
render() { |
|||
const { |
|||
createInvoice, |
|||
cryptoCurrency, |
|||
cryptoCurrencyTicker, |
|||
cryptoCurrencies, |
|||
currentTicker, |
|||
cryptoName, |
|||
fiatCurrencies, |
|||
fiatCurrency, |
|||
intl, |
|||
isProcessing, |
|||
isPaid, |
|||
payReq, |
|||
setCryptoCurrency, |
|||
setFiatCurrency, |
|||
...rest |
|||
} = this.props |
|||
const { currentStep } = this.state |
|||
return ( |
|||
<Form |
|||
width={1} |
|||
css={{ height: '100%' }} |
|||
{...rest} |
|||
getApi={this.setFormApi} |
|||
onSubmit={this.onSubmit} |
|||
> |
|||
{({ formState }) => { |
|||
// Determine what the text should be for the next button.
|
|||
let nextButtonText = intl.formatMessage({ ...messages.button_text }) |
|||
if (formState.values.amountCrypto) { |
|||
nextButtonText = `${intl.formatMessage({ |
|||
...messages.button_text |
|||
})} ${formState.values.amountCrypto} ${cryptoCurrencyTicker}` |
|||
} |
|||
|
|||
return ( |
|||
<Panel> |
|||
<Panel.Header> |
|||
<Header |
|||
title={`${intl.formatMessage({ |
|||
...messages.title |
|||
})} ${cryptoName} (${cryptoCurrencyTicker})`}
|
|||
subtitle={<FormattedMessage {...messages.subtitle} />} |
|||
logo={<Lightning height="45px" width="45px" />} |
|||
/> |
|||
</Panel.Header> |
|||
<Bar /> |
|||
<Panel.Body> |
|||
{currentStep == 'form' ? ( |
|||
<React.Fragment> |
|||
{this.renderHelpText()} |
|||
{this.renderAmountFields()} |
|||
{this.renderMemoField()} |
|||
</React.Fragment> |
|||
) : ( |
|||
<RequestSummary |
|||
mt={-3} |
|||
// State
|
|||
cryptoCurrency={cryptoCurrency} |
|||
cryptoCurrencies={cryptoCurrencies} |
|||
currentTicker={currentTicker} |
|||
payReq={payReq} |
|||
isPaid={isPaid} |
|||
// Dispatch
|
|||
setCryptoCurrency={setCryptoCurrency} |
|||
setFiatCurrency={setFiatCurrency} |
|||
/> |
|||
)} |
|||
</Panel.Body> |
|||
{currentStep == 'form' && ( |
|||
<Panel.Footer> |
|||
<Button |
|||
type="submit" |
|||
disabled={formState.pristine || formState.invalid || isProcessing} |
|||
processing={isProcessing} |
|||
mx="auto" |
|||
> |
|||
{nextButtonText} |
|||
</Button> |
|||
</Panel.Footer> |
|||
)} |
|||
</Panel> |
|||
) |
|||
}} |
|||
</Form> |
|||
) |
|||
} |
|||
} |
|||
|
|||
export default injectIntl(Request) |
@ -0,0 +1,179 @@ |
|||
import React from 'react' |
|||
import PropTypes from 'prop-types' |
|||
import { Box, Flex } from 'rebass' |
|||
import { FormattedMessage, FormattedRelative, injectIntl } from 'react-intl' |
|||
import { decodePayReq } from 'lib/utils/crypto' |
|||
import { showNotification } from 'lib/utils/notifications' |
|||
import copy from 'copy-to-clipboard' |
|||
import { Bar, Button, Dropdown, QRCode, Text, Truncate } from 'components/UI' |
|||
import Value from 'components/Value' |
|||
import { PaySummaryRow } from '../Pay' |
|||
import messages from './messages' |
|||
|
|||
class RequestSummary extends React.Component { |
|||
state = { |
|||
isExpired: null, |
|||
timer: null |
|||
} |
|||
|
|||
static propTypes = { |
|||
/** Currently selected cryptocurrency (key). */ |
|||
cryptoCurrency: PropTypes.string.isRequired, |
|||
/** List of supported cryptocurrencies. */ |
|||
cryptoCurrencies: PropTypes.arrayOf( |
|||
PropTypes.shape({ |
|||
key: PropTypes.string.isRequired, |
|||
name: PropTypes.string.isRequired |
|||
}) |
|||
).isRequired, |
|||
/** Boolean indicating wether the invoice has already been paid. */ |
|||
isPaid: PropTypes.bool, |
|||
/** Lightning Payment request. */ |
|||
payReq: PropTypes.string.isRequired, |
|||
/** Set the current cryptocurrency. */ |
|||
setCryptoCurrency: PropTypes.func.isRequired |
|||
} |
|||
|
|||
static defaultProps = { |
|||
isPaid: false |
|||
} |
|||
|
|||
componentDidMount() { |
|||
const { payReq } = this.props |
|||
|
|||
let invoice |
|||
try { |
|||
invoice = decodePayReq(payReq) |
|||
const expiresIn = invoice.timeExpireDate * 1000 - Date.now() |
|||
if (expiresIn >= 0) { |
|||
this.setState({ isExpired: false }) |
|||
const timer = setInterval(() => this.setState({ isExpired: true }), expiresIn) |
|||
this.setState({ timer }) |
|||
} else { |
|||
this.setState({ isExpired: true }) |
|||
} |
|||
} catch (e) { |
|||
return null |
|||
} |
|||
} |
|||
|
|||
componentWillUnmount() { |
|||
const { timer } = this.state |
|||
clearInterval(timer) |
|||
} |
|||
|
|||
copyPaymentRequest = () => { |
|||
const { intl, payReq } = this.props |
|||
copy(payReq) |
|||
showNotification( |
|||
intl.formatMessage({ ...messages.address_notification_title }), |
|||
intl.formatMessage({ ...messages.copied_notification_description }) |
|||
) |
|||
} |
|||
|
|||
render() { |
|||
const { |
|||
cryptoCurrency, |
|||
cryptoCurrencies, |
|||
isPaid, |
|||
payReq, |
|||
setCryptoCurrency, |
|||
...rest |
|||
} = this.props |
|||
const { isExpired } = this.state |
|||
let invoice |
|||
try { |
|||
invoice = decodePayReq(payReq) |
|||
} catch (e) { |
|||
return null |
|||
} |
|||
|
|||
const { satoshis } = invoice |
|||
const descriptionTag = invoice.tags.find(tag => tag.tagName === 'description') || {} |
|||
const memo = descriptionTag.data |
|||
|
|||
return ( |
|||
<Box {...rest}> |
|||
{memo && ( |
|||
<React.Fragment> |
|||
<PaySummaryRow left={<FormattedMessage {...messages.memo} />} right={memo} /> <Bar />{' '} |
|||
</React.Fragment> |
|||
)} |
|||
|
|||
<PaySummaryRow |
|||
left={<FormattedMessage {...messages.amount} />} |
|||
right={ |
|||
<Flex alignItems="center" justifyContent="flex-end"> |
|||
<Value value={satoshis} currency={cryptoCurrency} /> |
|||
<Dropdown |
|||
activeKey={cryptoCurrency} |
|||
items={cryptoCurrencies} |
|||
onChange={setCryptoCurrency} |
|||
justify="right" |
|||
ml={2} |
|||
/> |
|||
</Flex> |
|||
} |
|||
/> |
|||
|
|||
<Bar /> |
|||
|
|||
<PaySummaryRow |
|||
left={<FormattedMessage {...messages.qrcode} />} |
|||
right={ |
|||
<Text> |
|||
<QRCode value={payReq} size="125px" /> |
|||
</Text> |
|||
} |
|||
/> |
|||
|
|||
<Bar /> |
|||
|
|||
<PaySummaryRow |
|||
left={<FormattedMessage {...messages.ln_invoice} />} |
|||
right=<React.Fragment> |
|||
<Text |
|||
fontSize="xs" |
|||
fontWeight="normal" |
|||
mb={2} |
|||
css={{ 'word-wrap': 'break-word' }} |
|||
className="hint--bottom-left" |
|||
data-hint={payReq} |
|||
> |
|||
<Truncate text={payReq} maxlen={40} /> |
|||
</Text> |
|||
<Button type="button" size="small" onClick={this.copyPaymentRequest}> |
|||
<FormattedMessage {...messages.copy_button_text} /> |
|||
</Button> |
|||
</React.Fragment> |
|||
/> |
|||
|
|||
<Bar /> |
|||
|
|||
<PaySummaryRow |
|||
left={<FormattedMessage {...messages.status} />} |
|||
right={ |
|||
<React.Fragment> |
|||
<Text color={isPaid || !isExpired ? 'superGreen' : 'superRed'} fontWeight="normal"> |
|||
{isExpired ? 'Expired ' : 'Expires '} |
|||
<FormattedRelative value={invoice.timeExpireDateString} updateInterval={1000} /> |
|||
</Text> |
|||
<Text |
|||
color={isPaid ? 'superGreen' : isExpired ? 'superRed' : 'grey'} |
|||
fontWeight="normal" |
|||
> |
|||
{isPaid ? ( |
|||
<FormattedMessage {...messages.paid} /> |
|||
) : ( |
|||
<FormattedMessage {...messages.not_paid} /> |
|||
)} |
|||
</Text> |
|||
</React.Fragment> |
|||
} |
|||
/> |
|||
</Box> |
|||
) |
|||
} |
|||
} |
|||
|
|||
export default injectIntl(RequestSummary) |
@ -0,0 +1,2 @@ |
|||
export Request from './Request' |
|||
export RequestSummary from './RequestSummary' |
@ -0,0 +1,22 @@ |
|||
import { defineMessages } from 'react-intl' |
|||
|
|||
/* eslint-disable max-len */ |
|||
export default defineMessages({ |
|||
amount: 'Amount', |
|||
button_text: 'Request', |
|||
copy_button_text: 'Copy invoice', |
|||
address_notification_title: 'Address copied', |
|||
copied_notification_description: 'Payment address has been copied to your clipboard', |
|||
ln_invoice: 'Lightning Invoice', |
|||
total: 'Total', |
|||
memo: 'Memo', |
|||
memo_placeholder: 'For example "Dinner last night"', |
|||
not_paid: 'not paid', |
|||
paid: 'paid', |
|||
qrcode: 'QR-Code', |
|||
status: 'Request Status', |
|||
title: 'Request', |
|||
subtitle: 'through the Lightning Network', |
|||
description: |
|||
'You can request Bitcoin (BTC) through the Lightning Network. Just enter the Amount you want to request in the field below. Zap will generate a QR-Code and a Lightning invoice after.' |
|||
}) |
@ -0,0 +1,151 @@ |
|||
/* eslint-disable max-len */ |
|||
|
|||
import React from 'react' |
|||
import { storiesOf } from '@storybook/react' |
|||
import { action } from '@storybook/addon-actions' |
|||
import { text } from '@storybook/addon-knobs' |
|||
import { State, Store } from '@sambego/storybook-state' |
|||
import lightningPayReq from 'bolt11' |
|||
import { convert } from 'lib/utils/btc' |
|||
import { Modal, Page } from 'components/UI' |
|||
import { Request, RequestSummary } from 'components/Request' |
|||
|
|||
const delay = time => new Promise(resolve => setTimeout(() => resolve(), time)) |
|||
|
|||
const store = new Store({ |
|||
chain: 'bitcoin', |
|||
network: 'testnet', |
|||
cryptoName: 'Bitcoin', |
|||
cryptoCurrency: 'btc', |
|||
cryptoCurrencyTicker: 'BTC', |
|||
cryptoCurrencies: [ |
|||
{ |
|||
key: 'btc', |
|||
name: 'BTC' |
|||
}, |
|||
{ |
|||
key: 'bits', |
|||
name: 'bits' |
|||
}, |
|||
{ |
|||
key: 'sats', |
|||
name: 'satoshis' |
|||
} |
|||
], |
|||
|
|||
fiatCurrency: 'USD', |
|||
fiatCurrencies: ['USD', 'EUR', 'GBP'], |
|||
|
|||
currentTicker: { |
|||
USD: { |
|||
last: 6477.78 |
|||
}, |
|||
EUR: { |
|||
last: 5656.01 |
|||
}, |
|||
GBP: { |
|||
last: 5052.73 |
|||
} |
|||
} |
|||
}) |
|||
|
|||
const mockCreateInvoice = async (amount, currency, memo = '') => { |
|||
action('mockCreateInvoice') |
|||
const satoshis = convert(currency, 'sats', amount) |
|||
store.set({ isProcessing: true }) |
|||
await delay(500) |
|||
var encoded = lightningPayReq.encode({ |
|||
coinType: 'bitcoin', |
|||
satoshis, |
|||
tags: [ |
|||
{ |
|||
tagName: 'purpose_commit_hash', |
|||
data: '3925b6f67e2c340036ed12093dd44e0368df1b6ea26c53dbe4811f58fd5db8c1' |
|||
}, |
|||
{ |
|||
tagName: 'payment_hash', |
|||
data: '0001020304050607080900010203040506070809000102030405060708090102' |
|||
}, |
|||
{ |
|||
tagName: 'expire_time', |
|||
data: 30 |
|||
}, |
|||
{ |
|||
tagName: 'description', |
|||
data: memo |
|||
} |
|||
] |
|||
}) |
|||
var privateKeyHex = 'e126f68f7eafcc8b74f54d269fe206be715000f94dac067d1c04a8ca3b2db734' |
|||
var signed = lightningPayReq.sign(encoded, privateKeyHex) |
|||
store.set({ payReq: signed.paymentRequest }) |
|||
store.set({ isProcessing: false }) |
|||
} |
|||
|
|||
const setCryptoCurrency = key => { |
|||
const items = store.get('cryptoCurrencies') |
|||
const item = items.find(i => i.key === key) |
|||
store.set({ cryptoCurrency: item.key }) |
|||
store.set({ cryptoCurrencyTicker: item.name }) |
|||
} |
|||
|
|||
const setFiatCurrency = key => { |
|||
store.set({ fiatCurrency: key }) |
|||
} |
|||
|
|||
storiesOf('Containers.Request', module) |
|||
.add('Request', () => { |
|||
return ( |
|||
<Page css={{ height: 'calc(100vh - 40px)' }}> |
|||
<Modal onClose={action('clicked')}> |
|||
<State store={store}> |
|||
<Request |
|||
width={9 / 16} |
|||
mx="auto" |
|||
// State
|
|||
cryptoCurrency={store.get('cryptoCurrency')} |
|||
cryptoCurrencyTicker={store.get('cryptoCurrencyTicker')} |
|||
cryptoCurrencies={store.get('cryptoCurrencies')} |
|||
currentTicker={store.get('currentTicker')} |
|||
cryptoName={store.get('cryptoName')} |
|||
fiatCurrency={store.get('fiatCurrency')} |
|||
fiatCurrencies={store.get('fiatCurrencies')} |
|||
isProcessing={store.get('isProcessing')} |
|||
isPaid={store.get('isPaid')} |
|||
payReq={store.get('payReq')} |
|||
// Dispatch
|
|||
createInvoice={mockCreateInvoice} |
|||
setCryptoCurrency={setCryptoCurrency} |
|||
setFiatCurrency={setFiatCurrency} |
|||
/> |
|||
</State> |
|||
</Modal> |
|||
</Page> |
|||
) |
|||
}) |
|||
.add('RequestSummary', () => { |
|||
store.set({ |
|||
payReq: text( |
|||
'Lightning Invoice', |
|||
'lntb10170n1pda7tarpp59kjlzct447ttxper43kek78lhwgxk4gy8nfvpjdr7yzkscu2ds5qdzy2pshjmt9de6zqen0wgsrzvp3xus8q6tcv4k8xgrpwss8xct5daeks6tn9ecxcctrv5hqxqzjccqp2yvpzcn2xazu9rt8nrhn2xf6nyrj8fsfw9hafsf0p80trypu4tp58km5mn7wz50uh06kxf4t8kdj64f86u6l5ksl75r500zl7urhacxspcm4ye9' |
|||
) |
|||
}) |
|||
return ( |
|||
<Page css={{ height: 'calc(100vh - 40px)' }}> |
|||
<Modal onClose={action('clicked')}> |
|||
<State store={store}> |
|||
<RequestSummary |
|||
// State
|
|||
cryptoCurrency={store.get('cryptoCurrency')} |
|||
cryptoCurrencies={store.get('cryptoCurrencies')} |
|||
currentTicker={store.get('currentTicker')} |
|||
payReq={store.get('payReq')} |
|||
// Dispatch
|
|||
setCryptoCurrency={setCryptoCurrency} |
|||
setFiatCurrency={setFiatCurrency} |
|||
/> |
|||
</State> |
|||
</Modal> |
|||
</Page> |
|||
) |
|||
}) |
Loading…
Reference in new issue