125 lines
3.7 KiB
JavaScript
125 lines
3.7 KiB
JavaScript
import { useState, useEffect } from 'react'
|
|
import { numWithUnits } from '@/lib/format'
|
|
import AccordianItem from './accordian-item'
|
|
import Qr from './qr'
|
|
import Countdown from './countdown'
|
|
import PayerData from './payer-data'
|
|
import Bolt11Info from './bolt11-info'
|
|
import { useQuery } from '@apollo/client'
|
|
import { INVOICE } from '@/fragments/wallet'
|
|
import { FAST_POLL_INTERVAL, SSR } from '@/lib/constants'
|
|
import { WebLnNotEnabledError } from './payment'
|
|
|
|
export default function Invoice ({ invoice, modal, onPayment, info, successVerb, webLn, webLnError, poll }) {
|
|
const [expired, setExpired] = useState(new Date(invoice.expiredAt) <= new Date())
|
|
|
|
const { data, error } = useQuery(INVOICE, SSR
|
|
? {}
|
|
: {
|
|
pollInterval: FAST_POLL_INTERVAL,
|
|
variables: { id: invoice.id },
|
|
nextFetchPolicy: 'cache-and-network',
|
|
skip: !poll
|
|
})
|
|
|
|
if (data) {
|
|
invoice = data.invoice
|
|
}
|
|
|
|
if (error) {
|
|
return <div>{error.toString()}</div>
|
|
}
|
|
|
|
// if webLn was not passed, use true by default
|
|
if (webLn === undefined) webLn = true
|
|
|
|
let variant = 'default'
|
|
let status = 'waiting for you'
|
|
|
|
if (invoice.cancelled) {
|
|
variant = 'failed'
|
|
status = 'cancelled'
|
|
webLn = false
|
|
} else if (invoice.confirmedAt || (invoice.isHeld && invoice.satsReceived && !expired)) {
|
|
variant = 'confirmed'
|
|
status = `${numWithUnits(invoice.satsReceived, { abbreviate: false })} ${successVerb || 'deposited'}`
|
|
webLn = false
|
|
} else if (expired) {
|
|
variant = 'failed'
|
|
status = 'expired'
|
|
webLn = false
|
|
}
|
|
|
|
useEffect(() => {
|
|
if (invoice.confirmedAt || (invoice.isHeld && invoice.satsReceived)) {
|
|
onPayment?.(invoice)
|
|
}
|
|
}, [invoice.confirmedAt, invoice.isHeld, invoice.satsReceived])
|
|
|
|
const { nostr, comment, lud18Data, bolt11, confirmedPreimage } = invoice
|
|
|
|
return (
|
|
<>
|
|
{webLnError && !(webLnError instanceof WebLnNotEnabledError) &&
|
|
<div className='text-center text-danger mb-3'>
|
|
Payment from attached wallet failed:
|
|
<div>{webLnError.toString()}</div>
|
|
</div>}
|
|
<Qr
|
|
webLn={webLn} value={invoice.bolt11}
|
|
description={numWithUnits(invoice.satsRequested, { abbreviate: false })}
|
|
statusVariant={variant} status={status}
|
|
/>
|
|
{invoice.confirmedAt
|
|
? (
|
|
<div className='text-muted text-center invisible'>
|
|
<Countdown date={Date.now()} />
|
|
</div>
|
|
)
|
|
: (
|
|
<div className='text-muted text-center'>
|
|
<Countdown
|
|
date={invoice.expiresAt} onComplete={() => {
|
|
setExpired(true)
|
|
}}
|
|
/>
|
|
</div>
|
|
)}
|
|
{!modal &&
|
|
<>
|
|
{info && <div className='text-muted fst-italic text-center'>{info}</div>}
|
|
<div className='w-100'>
|
|
{nostr
|
|
? <AccordianItem
|
|
header='Nostr Zap Request'
|
|
body={
|
|
<pre>
|
|
<code>
|
|
{JSON.stringify(nostr, null, 2)}
|
|
</code>
|
|
</pre>
|
|
}
|
|
/>
|
|
: null}
|
|
</div>
|
|
{lud18Data &&
|
|
<div className='w-100'>
|
|
<AccordianItem
|
|
header='sender information'
|
|
body={<PayerData data={lud18Data} className='text-muted ms-3 mb-3' />}
|
|
/>
|
|
</div>}
|
|
{comment &&
|
|
<div className='w-100'>
|
|
<AccordianItem
|
|
header='sender comments'
|
|
body={<span className='text-muted ms-3'>{comment}</span>}
|
|
/>
|
|
</div>}
|
|
<Bolt11Info bolt11={bolt11} preimage={confirmedPreimage} />
|
|
</>}
|
|
|
|
</>
|
|
)
|
|
}
|