import { useState, useEffect, useRef } from "react"; import QRCode from "qrcode"; import { Modal } from "./Modal"; import { getSponsorCheckPayment } from "../api"; const POLL_INTERVAL_MS = 10_000; const INVOICE_EXPIRY_MS = 60 * 60 * 1000; // 1 hour export interface PendingInvoice { payment_hash: string; payment_request: string; price_sats: number; duration_days: number; } interface SponsorInvoiceModalProps { open: boolean; onClose: () => void; result: PendingInvoice | null; /** Called when payment is detected (e.g. to refresh sponsor list). */ onPaid?: () => void; title?: string; } export function SponsorInvoiceModal({ open, onClose, result, onPaid, title }: SponsorInvoiceModalProps) { const [qrDataUrl, setQrDataUrl] = useState(null); const onPaidRef = useRef(onPaid); const onCloseRef = useRef(onClose); onPaidRef.current = onPaid; onCloseRef.current = onClose; useEffect(() => { if (!result?.payment_request) { setQrDataUrl(null); return; } QRCode.toDataURL(result.payment_request, { width: 200 }).then(setQrDataUrl).catch(() => setQrDataUrl(null)); }, [result?.payment_request]); useEffect(() => { if (!open || !result?.payment_hash) return; const openedAt = Date.now(); let cancelled = false; const check = async () => { if (cancelled) return; if (Date.now() - openedAt > INVOICE_EXPIRY_MS) return; try { const { paid: isPaid } = await getSponsorCheckPayment(result!.payment_hash); if (cancelled) return; if (isPaid) { onPaidRef.current?.(); onCloseRef.current(); } } catch { // Ignore; will retry on next poll } }; check(); const interval = setInterval(check, POLL_INTERVAL_MS); return () => { cancelled = true; clearInterval(interval); }; }, [open, result?.payment_hash]); const handleCopy = () => { if (!result?.payment_request) return; navigator.clipboard.writeText(result.payment_request).then(() => { // Could show a toast }); }; if (!result) return null; return (

Scan or copy the Lightning invoice to pay {result.price_sats.toLocaleString()} sats. Your sponsor will activate after payment.

{qrDataUrl && (
Lightning invoice QR
)}

Duration: {result.duration_days} days.

); }