diff --git a/.gitignore b/.gitignore index c742db9..2b8868f 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ ui/node_modules/ nginx/certs/ backups/ +ui/tsconfig.tsbuildinfo diff --git a/ui/app/i/[invoiceId]/page.tsx b/ui/app/i/[invoiceId]/page.tsx index a5a6016..78d0259 100644 --- a/ui/app/i/[invoiceId]/page.tsx +++ b/ui/app/i/[invoiceId]/page.tsx @@ -6,6 +6,7 @@ import InvoicePaymentDetails from "../../../components/invoice-payment-details"; import InvoiceStatusAutoRefresh from "../../../components/invoice-status-auto-refresh"; import { formatRelativeTime } from "../../../components/relative-time"; import StatusRefreshButton from "../../../components/status-refresh-button"; +import BtcpayAutoReturn from "../../../components/btcpay-auto-return"; export const dynamic = "force-dynamic"; export const metadata: Metadata = { @@ -149,7 +150,12 @@ 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 shouldShowBtcpayActions = + isBtcpayInvoice && + (invoice.status === "payment_detected" || invoice.status === "confirmed"); const checkoutContinueAvailable = !isBtcpayInvoice && invoice.status === "confirmed" && @@ -257,6 +263,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 3b0ed53..adbc817 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 WOW = ${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