import { useState, useCallback, useRef } from 'react'; import type { Manager } from 'coco-cashu-core'; import { useToast } from '@/hooks/useToast'; interface UseLightningOperationsProps { coco: Manager | null; activeMintUrl: string | null; generateQRCode: (text: string) => Promise; } export function useLightningOperations({ coco, activeMintUrl, generateQRCode, }: UseLightningOperationsProps) { const { toast } = useToast(); // Receive state const [quoteAmount, setQuoteAmount] = useState(''); const [showInvoiceModal, setShowInvoiceModal] = useState(false); const [currentInvoice, setCurrentInvoice] = useState<{ quoteId: string; mintUrl: string; amount: number; invoice: string; qrCodeUrl: string; expiry: number; } | null>(null); // Send state const [lightningInvoice, setLightningInvoice] = useState(''); const [isProcessingPayment, setIsProcessingPayment] = useState(false); const mintQuoteUnsubscribeRef = useRef<(() => void) | null>(null); // Handle receive (create mint quote/invoice) const handleLightningReceive = useCallback(async () => { if (!coco || !quoteAmount || !activeMintUrl) return; try { const amount = parseInt(quoteAmount); if (isNaN(amount) || amount <= 0) { toast({ variant: 'destructive', title: 'Invalid amount', description: 'Please enter a valid amount' }); return; } const quote = await coco.quotes.createMintQuote(activeMintUrl, amount); const qrCodeUrl = await generateQRCode(quote.request); setCurrentInvoice({ quoteId: quote.quote, mintUrl: activeMintUrl, amount, invoice: quote.request, qrCodeUrl, expiry: quote.expiry, }); setShowInvoiceModal(true); setQuoteAmount(''); // Clean up any previous listener if (mintQuoteUnsubscribeRef.current) { mintQuoteUnsubscribeRef.current(); mintQuoteUnsubscribeRef.current = null; } // Listen for payment const quoteId = quote.quote; const invoiceAmount = amount; const unsubscribe = coco.on('mint-quote:redeemed', (payload: unknown) => { const redeemedQuote = payload as { quoteId?: string }; if (redeemedQuote.quoteId === quoteId) { toast({ title: 'Payment received', description: `Successfully received ${invoiceAmount} sats!` }); setShowInvoiceModal(false); setCurrentInvoice(null); mintQuoteUnsubscribeRef.current = null; unsubscribe(); } }); mintQuoteUnsubscribeRef.current = unsubscribe; } catch (err) { toast({ variant: 'destructive', title: 'Failed to create invoice', description: err instanceof Error ? err.message : 'Unknown error' }); } }, [coco, quoteAmount, activeMintUrl, generateQRCode, toast]); // Handle send (pay Lightning invoice) const handleLightningSend = useCallback(async () => { if (isProcessingPayment || !coco || !lightningInvoice || !activeMintUrl) return; setIsProcessingPayment(true); try { const invoice = lightningInvoice.trim(); // Create and pay melt quote const meltQuote = await coco.quotes.createMeltQuote(activeMintUrl, invoice); await coco.quotes.payMeltQuote(activeMintUrl, meltQuote.quote); toast({ title: 'Payment sent', description: 'Lightning payment completed successfully' }); setLightningInvoice(''); } catch (err) { toast({ variant: 'destructive', title: 'Payment failed', description: err instanceof Error ? err.message : 'Unknown error' }); } finally { setIsProcessingPayment(false); } }, [coco, lightningInvoice, activeMintUrl, isProcessingPayment, toast]); // Cleanup listener on unmount useCallback(() => { return () => { if (mintQuoteUnsubscribeRef.current) { mintQuoteUnsubscribeRef.current(); } }; }, []); return { // Receive quoteAmount, setQuoteAmount, showInvoiceModal, setShowInvoiceModal, currentInvoice, setCurrentInvoice, handleLightningReceive, // Send lightningInvoice, setLightningInvoice, isProcessingPayment, handleLightningSend, }; }