import { useEffect, useState, useCallback } from 'react' import type { AlbyInvoice } from '@/types/alby' import { getAlbyService, isWebLNAvailable } from '@/lib/alby' import { copyInvoiceToClipboard, openWalletForInvoice } from '@/lib/paymentModalHelpers' import { AlbyInstaller } from './AlbyInstaller' import { Modal } from './ui' import { useToast } from './ui/ToastContainer' import { t } from '@/lib/i18n' import { PaymentHeader, InvoiceDisplay, PaymentInstructions, PaymentActions, ExpiredNotice, PaymentError, } from './paymentModal/PaymentModalComponents' interface PaymentModalProps { invoice: AlbyInvoice onClose: () => void onPaymentComplete: () => void } function useInvoiceTimer(expiresAt?: number): number | null { const [timeRemaining, setTimeRemaining] = useState(null) useEffect(() => { if (!expiresAt) { return } const updateTimeRemaining = (): void => { 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 } type PaymentModalState = { copied: boolean errorMessage: string | null paymentUrl: string timeRemaining: number | null handleCopy: () => Promise handleOpenWallet: () => Promise } function usePaymentModalState(invoice: AlbyInvoice, onPaymentComplete: () => void, showToast: ((message: string, variant?: 'success' | 'info' | 'warning' | 'error', duration?: number) => void) | undefined): PaymentModalState { const [copied, setCopied] = useState(false) const [errorMessage, setErrorMessage] = useState(null) const paymentUrl = `lightning:${invoice.invoice}` const timeRemaining = useInvoiceTimer(invoice.expiresAt) const handleCopy = useCallback( (): Promise => copyInvoiceToClipboard({ invoice: invoice.invoice, setCopied, setErrorMessage, showToast: showToast ?? undefined }), [invoice.invoice, showToast] ) const handleOpenWallet = useCallback( (): Promise => openWalletForInvoice({ invoice: invoice.invoice, onPaymentComplete, setErrorMessage, showToast: showToast ?? undefined }), [invoice.invoice, onPaymentComplete, showToast] ) return { copied, errorMessage, paymentUrl, timeRemaining, handleCopy, handleOpenWallet } } function useAlbyDetection(): boolean { const [hasAlby, setHasAlby] = useState(false) useEffect(() => { const checkAlby = (): void => { const alby = getAlbyService() setHasAlby(isWebLNAvailable() && alby.isEnabled()) } checkAlby() const interval = setInterval(checkAlby, 1000) return () => clearInterval(interval) }, []) return hasAlby } function PaymentModalContent({ invoice, copied, errorMessage, paymentUrl, timeRemaining, handleCopy, handleOpenWallet, hasAlby, }: { invoice: AlbyInvoice copied: boolean errorMessage: string | null paymentUrl: string timeRemaining: number | null handleCopy: () => Promise handleOpenWallet: () => void hasAlby: boolean }): React.ReactElement { return ( <> {!hasAlby && }

{t('payment.modal.autoVerify')}

) } export function PaymentModal({ invoice, onClose, onPaymentComplete }: PaymentModalProps): React.ReactElement { const { showToast } = useToast() const { copied, errorMessage, paymentUrl, timeRemaining, handleCopy, handleOpenWallet } = usePaymentModalState(invoice, onPaymentComplete, showToast) const hasAlby = useAlbyDetection() const handleOpenWalletSync = (): void => { void handleOpenWallet() } return ( ) }