diff --git a/components/invoice.js b/components/invoice.js index ebe51d70e..be8b73cbd 100644 --- a/components/invoice.js +++ b/components/invoice.js @@ -267,6 +267,7 @@ export const useInvoiceable = (onSubmit, options = defaultOptions) => { } const waitForPayment = async ({ invoice, showModal, provider, pollInvoice, updateCache, undoUpdate }) => { + const INVOICE_CANCELED_ERROR = 'invoice was canceled' try { // try WebLN provider first return await new Promise((resolve, reject) => { @@ -275,7 +276,7 @@ const waitForPayment = async ({ invoice, showModal, provider, pollInvoice, updat // can't use await here since we might be paying HODL invoices // and sendPaymentAsync is not supported yet. // see https://www.webln.guide/building-lightning-apps/webln-reference/webln.sendpaymentasync - provider.sendPayment(invoice.bolt11) + provider.sendPayment(invoice) // WebLN payment will never resolve here for HODL invoices // since they only get resolved after settlement which can't happen here .then(resolve) @@ -295,6 +296,10 @@ const waitForPayment = async ({ invoice, showModal, provider, pollInvoice, updat clearInterval(interval) resolve() } + if (inv.cancelled) { + clearInterval(interval) + reject(new Error(INVOICE_CANCELED_ERROR)) + } } catch (err) { clearInterval(interval) reject(err) @@ -302,9 +307,12 @@ const waitForPayment = async ({ invoice, showModal, provider, pollInvoice, updat }, 1000) }) } catch (err) { - console.error('WebLN payment failed:', err) // undo attempt to make zapping UX consistent undoUpdate?.() + console.error('WebLN payment failed:', err) + if (err.message === INVOICE_CANCELED_ERROR) { + throw err + } } // QR code as fallback diff --git a/components/toast.js b/components/toast.js index 64db1870b..6f358449c 100644 --- a/components/toast.js +++ b/components/toast.js @@ -35,6 +35,7 @@ export const ToastProvider = ({ children }) => { }) }, warning: (body, options) => { + const id = toastId.current dispatchToast({ body, variant: 'warning', @@ -42,6 +43,7 @@ export const ToastProvider = ({ children }) => { delay: 5000, ...options }) + return () => removeToast(id) }, danger: (body, options) => { const id = toastId.current @@ -52,9 +54,7 @@ export const ToastProvider = ({ children }) => { autohide: false, ...options }) - return { - removeToast: () => removeToast(id) - } + return () => removeToast(id) } }), [dispatchToast, removeToast]) @@ -71,28 +71,32 @@ export const ToastProvider = ({ children }) => { return ( - {toasts.map(toast => ( - removeToast(toast.id)} - > - -
-
{toast.body}
- -
-
-
- ))} + {toasts.map(toast => { + const textStyle = toast.variant === 'warning' ? 'text-dark' : '' + return ( + removeToast(toast.id)} + > + +
+
{toast.body}
+ +
+
+
+ ) + })}
{children}
diff --git a/components/toast.module.css b/components/toast.module.css index 6d09ad7bc..c66d1363c 100644 --- a/components/toast.module.css +++ b/components/toast.module.css @@ -21,6 +21,13 @@ border-color: var(--bs-warning-border-subtle); } +.toastCancel { + font-style: italic; + cursor: pointer; + display: flex; + align-items: center; +} + .toastClose { color: #fff; font-family: "lightning"; diff --git a/components/use-crossposter.js b/components/use-crossposter.js index ede0f45df..552bf50d9 100644 --- a/components/use-crossposter.js +++ b/components/use-crossposter.js @@ -27,7 +27,7 @@ export default function useCrossposter () { const relayError = (failedRelays) => { return new Promise(resolve => { - const { removeToast } = toast.danger( + const removeToast = toast.danger( <> Crossposting failed for {failedRelays.join(', ')}