import type { Metadata } from "next"; import { headers } from "next/headers"; import BtcpayModalBridge from "../../../../components/btcpay-modal-bridge"; import { formatRelativeTime } from "../../../../components/relative-time"; export const dynamic = "force-dynamic"; export const metadata: Metadata = { title: "Receipt", }; const apiBaseUrl = process.env.API_BASE_URL ?? "http://localhost:8000"; type InvoiceStatus = | "pending" | "payment_detected" | "confirmed" | "expired" | "invalid"; type InvoiceStatusResponse = { id: string; address: string; amount_xmr: string; amount_paid_xmr?: string | null; status: InvoiceStatus; confirmation_target: number; confirmations: number; created_at: string; confirmed_at: string | null; btcpay_amount?: string | null; btcpay_currency?: string | null; btcpay_redirect_url?: string | null; btcpay_order_id?: string | null; btcpay_order_number?: string | null; quote?: { fiat_amount: string; fiat_currency: string; rate: string; source: string; quoted_at: string; } | null; qr_url?: string | null; }; const formatFiatAmount = (value: string, currency: string) => { const amount = Number.parseFloat(value); if (!Number.isFinite(amount)) { return `${value} ${currency}`; } try { return new Intl.NumberFormat("en-US", { style: "currency", currency, maximumFractionDigits: 2, minimumFractionDigits: 2, }).format(amount); } catch { return `${amount.toFixed(2)} ${currency}`; } }; const receiptTitle = (redirectUrl: string | null | undefined) => { if (!redirectUrl) { return "Receipt"; } try { const parsed = new URL(redirectUrl); return parsed.hostname ? `${parsed.hostname}` : "Receipt"; } catch { return "Receipt"; } }; const resolveQrSrc = (invoiceId: string, qrUrl: string | null | undefined) => { if (!qrUrl) { return `/qr/${encodeURIComponent(invoiceId)}.png`; } if (qrUrl.startsWith("/qr/")) { return qrUrl; } try { const parsed = new URL(qrUrl); if (parsed.pathname.startsWith("/qr/")) { return parsed.pathname; } } catch { // Ignore malformed URLs and fall back to the provided value. } return qrUrl; }; const closeLinkClassName = "rounded-full border border-stroke bg-white/80 px-3 py-1 text-[0.65rem] font-semibold uppercase tracking-[0.12em] text-ink-soft transition hover:bg-white"; export default async function BtcpayReceiptPage({ params, }: { params: Promise<{ invoiceId: string }>; }) { const { invoiceId } = await params; const requestHeaders = await headers(); const forwardedProto = requestHeaders.get("x-forwarded-proto"); const forwardedHost = requestHeaders.get("x-forwarded-host") ?? requestHeaders.get("host"); const response = await fetch( `${apiBaseUrl}/api/core/public/invoice/${encodeURIComponent(invoiceId)}`, { cache: "no-store", headers: { ...(forwardedProto ? { "x-forwarded-proto": forwardedProto } : {}), ...(forwardedHost ? { "x-forwarded-host": forwardedHost } : {}), }, } ); if (response.status === 404) { return (
Close

Invoice not found

The invoice id does not match a known invoice. Check the id and try again.

); } if (!response.ok) { return (
Close

Status unavailable

We could not load this invoice status. Refresh the page or try again later.

); } const invoice = (await response.json()) as InvoiceStatusResponse; const orderId = invoice.btcpay_order_number ?? invoice.btcpay_order_id ?? null; const receiptTimestamp = invoice.confirmed_at ?? invoice.created_at; const timestampLabel = new Date(receiptTimestamp).toLocaleString(); const timestampRelative = formatRelativeTime(receiptTimestamp); const totalFiat = invoice.btcpay_amount && invoice.btcpay_currency && invoice.btcpay_currency !== "XMR" ? formatFiatAmount(invoice.btcpay_amount, invoice.btcpay_currency) : invoice.btcpay_amount && invoice.btcpay_currency ? `${invoice.btcpay_amount} ${invoice.btcpay_currency}` : null; const exchangeRate = invoice.quote?.rate && invoice.quote.fiat_currency ? formatFiatAmount(invoice.quote.rate, invoice.quote.fiat_currency) : null; const paidXmr = invoice.amount_paid_xmr ?? invoice.amount_xmr; const qrSrc = resolveQrSrc(invoiceId, invoice.qr_url); const storeTitle = receiptTitle(invoice.btcpay_redirect_url); return (
Close
{invoice.status !== "confirmed" ? (

{storeTitle}

{orderId ?

Order ID: {orderId}

: null}

{timestampLabel}

This receipt is available after the payment is confirmed.

) : ( <>

{storeTitle}

{orderId ?

Order ID: {orderId}

: null}

{timestampLabel}

Total
{totalFiat ?? "-"}
Paid
{paidXmr} XMR
{totalFiat ?
{totalFiat}
: null}
Rate
{exchangeRate ?? "-"}
Destination
{invoice.address}
{qrSrc ? ( // eslint-disable-next-line @next/next/no-img-element Payment QR ) : null}

Powered by XMR Checkout

)}
); }