>
)
}
const Contacts = ({ invoiceHash, invoiceHmac }) => {
const subject = `Support request for payment hash: ${invoiceHash}`
const body = 'Hi, I successfully paid for but the action did not work.'
return (
}
if (!data || loading) {
return
}
let errorStatus = 'Something went wrong trying to perform the action after payment.'
if (errorCount > 1) {
errorStatus = 'Something still went wrong.\nPlease contact admins for support or to request a refund.'
}
return (
<>
{errorCount > 0
? (
<>
>
)
: null}
>
)
}
const defaultOptions = {
forceInvoice: false,
requireSession: false
}
export const useInvoiceable = (fn, options = defaultOptions) => {
const me = useMe()
const [createInvoice, { data }] = useMutation(gql`
mutation createInvoice($amount: Int!) {
createInvoice(amount: $amount, expireSecs: 1800) {
id
hash
hmac
}
}`)
const showModal = useShowModal()
const [fnArgs, setFnArgs] = useState()
// fix for bug where `showModal` runs the code for two modals and thus executes `onConfirmation` twice
let errorCount = 0
const onConfirmation = useCallback(
(onClose, hmac) => {
return async ({ id, satsReceived, hash }) => {
await sleep(500)
const repeat = () =>
fn(satsReceived, ...fnArgs, hash, hmac)
.then(onClose)
.catch((error) => {
console.error(error)
errorCount++
onClose()
showModal(onClose => (
), { keepOpen: true })
})
// prevents infinite loop of calling `onConfirmation`
if (errorCount === 0) await repeat()
}
}, [fn, fnArgs]
)
const invoice = data?.createInvoice
useEffect(() => {
if (invoice) {
showModal(onClose => (
), { keepOpen: true }
)
}
}, [invoice?.id])
const actionFn = useCallback(async (amount, ...args) => {
if (!me && options.requireSession) {
throw new Error('you must be logged in')
}
if (!amount || (me && !options.forceInvoice)) {
try {
return await fn(amount, ...args)
} catch (error) {
if (isInsufficientFundsError(error)) {
showModal(onClose => {
return (
{ await fn(amount, ...args, invoiceHash, invoiceHmac) }}
/>
)
})
return { keepLocalStorage: true }
}
throw error
}
}
setFnArgs(args)
await createInvoice({ variables: { amount } })
// tell onSubmit handler that we want to keep local storage
// even though the submit handler was "successful"
return { keepLocalStorage: true }
}, [fn, setFnArgs, createInvoice])
return actionFn
}