diff --git a/ui/app/i/[invoiceId]/receipt/page.tsx b/ui/app/i/[invoiceId]/receipt/page.tsx index 7c5154d..cfe08d8 100644 --- a/ui/app/i/[invoiceId]/receipt/page.tsx +++ b/ui/app/i/[invoiceId]/receipt/page.tsx @@ -2,6 +2,8 @@ import type { Metadata } from "next"; import { headers } from "next/headers"; import BtcpayModalBridge from "../../../../components/btcpay-modal-bridge"; +import CopyIconButton from "../../../../components/copy-icon-button"; +import PrintButton from "../../../../components/print-button"; import { formatRelativeTime } from "../../../../components/relative-time"; export const dynamic = "force-dynamic"; @@ -91,7 +93,7 @@ const resolveQrSrc = (invoiceId: string, qrUrl: string | null | undefined) => { }; 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"; + "rounded-md border border-neutral-200 bg-white px-3 py-2 text-xs font-semibold text-neutral-700 transition hover:bg-neutral-50"; export default async function BtcpayReceiptPage({ params, @@ -166,85 +168,106 @@ export default async function BtcpayReceiptPage({ : 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); + const amountPaidLabel = totalFiat ? totalFiat : `${paidXmr} XMR`; + const returnLabel = invoice.btcpay_redirect_url ? `Return to ${storeTitle}` : "Return to invoice"; + const returnHref = invoice.btcpay_redirect_url ?? `/i/${encodeURIComponent(invoiceId)}`; return ( -
+
-
- - Close - -
+
+

{storeTitle}

+
{invoice.status !== "confirmed" ? (
-

{storeTitle}

- {orderId ?

Order ID: {orderId}

: null} -

+ {orderId ?

Order ID: {orderId}

: null} +

{timestampLabel}

-

+

This receipt is available after the payment is confirmed.

) : ( <> -
-

{storeTitle}

- {orderId ?

Order ID: {orderId}

: null} -

- {timestampLabel} -

+
+
+
+ {qrSrc ? ( + // eslint-disable-next-line @next/next/no-img-element + Payment QR + ) : null} +
+ +
+
+
+

Amount Paid

+

{amountPaidLabel}

+
+
+

Date

+

+ {timestampLabel} +

+
+ {orderId ? ( +
+

Order ID

+

{orderId}

+
+ ) : null} +
+ +
+ +
+
+
-
-
-
-
Total
-
{totalFiat ?? "-"}
+
+

Payment Details

+ +
+
+
Date
+
Paid
+
Payment
-
-
Paid
-
-
{paidXmr} XMR
- {totalFiat ?
{totalFiat}
: null} -
+
+
{timestampLabel}
+
{totalFiat ?? "-"}
+
{paidXmr} XMR
-
-
Rate
-
{exchangeRate ?? "-"}
-
-
-
Destination
-
+
+ +
+

Destination

+
+ {invoice.address} - + +
-
-
+
+
- {qrSrc ? ( - // eslint-disable-next-line @next/next/no-img-element - Payment QR - ) : null} + + {returnLabel} +
- -

- Powered by XMR Checkout -

)}
diff --git a/ui/components/copy-icon-button.tsx b/ui/components/copy-icon-button.tsx new file mode 100644 index 0000000..3ce6759 --- /dev/null +++ b/ui/components/copy-icon-button.tsx @@ -0,0 +1,56 @@ +"use client"; + +import { useState } from "react"; + +type CopyIconButtonProps = { + value: string; + label: string; + className?: string; +}; + +export default function CopyIconButton({ value, label, className }: CopyIconButtonProps) { + const [copied, setCopied] = useState(false); + + const handleCopy = async () => { + try { + await navigator.clipboard.writeText(value); + setCopied(true); + window.setTimeout(() => setCopied(false), 1500); + } catch { + setCopied(false); + } + }; + + return ( + + ); +} + diff --git a/ui/components/print-button.tsx b/ui/components/print-button.tsx new file mode 100644 index 0000000..647ac3a --- /dev/null +++ b/ui/components/print-button.tsx @@ -0,0 +1,21 @@ +"use client"; + +type PrintButtonProps = { + className?: string; +}; + +export default function PrintButton({ className }: PrintButtonProps) { + return ( + + ); +} +