diff --git a/.gitignore b/.gitignore index 49a157f..e2e77ee 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ backups/ wallets/ qr/ docker-compose.override.yml +ui/tsconfig.tsbuildinfo diff --git a/ui/app/i/[invoiceId]/page.tsx b/ui/app/i/[invoiceId]/page.tsx index 00b7226..4f7e4d4 100644 --- a/ui/app/i/[invoiceId]/page.tsx +++ b/ui/app/i/[invoiceId]/page.tsx @@ -1,6 +1,7 @@ import type { Metadata } from "next"; import BtcpayModalBridge from "../../../components/btcpay-modal-bridge"; +import BtcpayAutoReturn from "../../../components/btcpay-auto-return"; import BtcpayClassicCheckout from "../../../components/btcpay-classic-checkout"; import InvoicePaymentDetails from "../../../components/invoice-payment-details"; import InvoiceStatusAutoRefresh from "../../../components/invoice-status-auto-refresh"; @@ -210,7 +211,13 @@ export default async function BtcpayModalInvoicePage({ const isBtcpayInvoice = Boolean(invoice.btcpay_amount && invoice.btcpay_currency); const useClassicCheckout = isBtcpayInvoice && invoice.btcpay_checkout_style === "btcpay_classic"; - const shouldShowBtcpayActions = isBtcpayInvoice && invoice.status === "confirmed"; + // The merchant's own order page is where a customer belongs once the payment has been seen, so + // the way back appears at detection. The receipt still waits for the confirmation target, because + // that is the point at which there is a settled payment to write one about. + const btcpayPaymentSeen = + isBtcpayInvoice && + (invoice.status === "payment_detected" || invoice.status === "confirmed"); + const shouldShowBtcpayActions = btcpayPaymentSeen; const checkoutContinueAvailable = !isBtcpayInvoice && invoice.status === "confirmed" && @@ -371,6 +378,11 @@ export default async function BtcpayModalInvoicePage({ ) : null} +
{shouldShowBtcpayActions ? (
- - View receipt - + {invoice.status === "confirmed" ? ( + + View receipt + + ) : null} {invoice.btcpay_redirect_url ? ( { + if ( + (status !== "confirmed" && status !== "payment_detected") || + !redirectUrl || + !redirectAutomatically + ) { + return; + } + const timer = window.setTimeout(() => { + try { + window.top?.location.assign(redirectUrl); + } catch { + window.location.assign(redirectUrl); + } + }, delayMs); + return () => { + window.clearTimeout(timer); + }; + }, [delayMs, redirectAutomatically, redirectUrl, status]); + + return null; +} diff --git a/ui/components/btcpay-classic-checkout.tsx b/ui/components/btcpay-classic-checkout.tsx index 13c7ffa..37e7923 100644 --- a/ui/components/btcpay-classic-checkout.tsx +++ b/ui/components/btcpay-classic-checkout.tsx @@ -5,6 +5,7 @@ import { useEffect, useMemo, useState } from "react"; import QRCode from "qrcode"; import { formatXmrAmount } from "../lib/formatting"; +import BtcpayAutoReturn from "./btcpay-auto-return"; type InvoiceStatus = | "pending" @@ -129,22 +130,6 @@ export default function BtcpayClassicCheckout({ ? `1 XMR = ${formatFiatAmount(quote.rate, quote.fiat_currency)}` : null; - useEffect(() => { - if ((status !== "confirmed" && status !== "payment_detected") || !redirectUrl || !redirectAutomatically) { - return; - } - const timer = window.setTimeout(() => { - try { - window.top?.location.assign(redirectUrl); - } catch { - window.location.assign(redirectUrl); - } - }, 3000); - return () => { - window.clearTimeout(timer); - }; - }, [redirectAutomatically, redirectUrl, status]); - const handleCopy = async (value: string, field: string) => { try { await navigator.clipboard.writeText(value); @@ -285,6 +270,11 @@ export default function BtcpayClassicCheckout({ return (
+

Payment request