import { useEffect, useMemo, useState, useCallback } from 'react' import QRCode from 'react-qr-code' import type { AlbyInvoice } from '@/types/alby' import { getAlbyService, isWebLNAvailable } from '@/lib/alby' import { AlbyInstaller } from './AlbyInstaller' interface PaymentModalProps { invoice: AlbyInvoice onClose: () => void onPaymentComplete: () => void } function useInvoiceTimer(expiresAt?: number) { const [timeRemaining, setTimeRemaining] = useState(null) useEffect(() => { if (!expiresAt) { return } const updateTimeRemaining = () => { const now = Math.floor(Date.now() / 1000) const remaining = expiresAt - now setTimeRemaining(remaining > 0 ? remaining : 0) } updateTimeRemaining() const interval = setInterval(updateTimeRemaining, 1000) return () => clearInterval(interval) }, [expiresAt]) return timeRemaining } function PaymentHeader({ amount, timeRemaining, onClose, }: { amount: number timeRemaining: number | null onClose: () => void }) { const timeLabel = useMemo(() => { if (timeRemaining === null) { return null } if (timeRemaining <= 0) { return 'Expired' } const minutes = Math.floor(timeRemaining / 60) const secs = timeRemaining % 60 return `${minutes}:${secs.toString().padStart(2, '0')}` }, [timeRemaining]) return (

Pay {amount} sats

{timeLabel && (

Time remaining: {timeLabel}

)}
) } function InvoiceDisplay({ invoiceText, paymentUrl }: { invoiceText: string; paymentUrl: string }) { return (

Lightning Invoice:

{invoiceText}

Scan with your Lightning wallet to pay

) } function PaymentActions({ copied, onCopy, onOpenWallet, }: { copied: boolean onCopy: () => Promise onOpenWallet: () => void }) { return (
) } function ExpiredNotice({ show }: { show: boolean }) { if (!show) { return null } return (

This invoice has expired

Please close this modal and try again to generate a new invoice.

) } function usePaymentModalState(invoice: AlbyInvoice, onPaymentComplete: () => void) { const [copied, setCopied] = useState(false) const [errorMessage, setErrorMessage] = useState(null) const paymentUrl = `lightning:${invoice.invoice}` const timeRemaining = useInvoiceTimer(invoice.expiresAt) const handleCopy = useCallback(async () => { try { await navigator.clipboard.writeText(invoice.invoice) setCopied(true) setTimeout(() => setCopied(false), 2000) } catch (e) { console.error('Failed to copy:', e) setErrorMessage('Failed to copy the invoice') } }, [invoice.invoice]) const handleOpenWallet = useCallback(async () => { try { const alby = getAlbyService() if (!isWebLNAvailable()) { throw new Error('WebLN is not available. Please install Alby or another Lightning wallet extension.') } await alby.enable() await alby.sendPayment(invoice.invoice) onPaymentComplete() } catch (e) { const error = e instanceof Error ? e : new Error(String(e)) if (error.message.includes('user rejected') || error.message.includes('cancelled')) { return } console.error('Payment failed:', error) setErrorMessage(error.message) } }, [invoice.invoice, onPaymentComplete]) return { copied, errorMessage, paymentUrl, timeRemaining, handleCopy, handleOpenWallet } } export function PaymentModal({ invoice, onClose, onPaymentComplete }: PaymentModalProps) { const { copied, errorMessage, paymentUrl, timeRemaining, handleCopy, handleOpenWallet } = usePaymentModalState(invoice, onPaymentComplete) const handleOpenWalletSync = () => { void handleOpenWallet() } return (
{errorMessage && (

{errorMessage}

)}

Payment will be automatically verified once completed

) }