import { useState, useEffect, useRef } from 'react'; import { Zap, Copy, Check, ExternalLink, Sparkle, Sparkles, Star, Rocket, ArrowLeft, X } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, } from '@/components/ui/dialog'; import { Drawer, DrawerContent, DrawerDescription, DrawerHeader, DrawerTitle, DrawerTrigger, DrawerClose, } from '@/components/ui/drawer'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { Card, CardContent } from '@/components/ui/card'; import { Separator } from '@/components/ui/separator'; import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group'; import { useCurrentUser } from '@/hooks/useCurrentUser'; import { useAuthor } from '@/hooks/useAuthor'; import { useToast } from '@/hooks/useToast'; import { useZaps } from '@/hooks/useZaps'; import { useWallet } from '@/hooks/useWallet'; import { useIsMobile } from '@/hooks/useIsMobile'; import type { Event } from 'nostr-tools'; import QRCode from 'qrcode'; interface ZapDialogProps { target: Event; children?: React.ReactNode; className?: string; } const presetAmounts = [ { amount: 1, icon: Sparkle }, { amount: 50, icon: Sparkles }, { amount: 100, icon: Zap }, { amount: 250, icon: Star }, { amount: 1000, icon: Rocket }, ]; export function ZapDialog({ target, children, className }: ZapDialogProps) { const [open, setOpen] = useState(false); const { user } = useCurrentUser(); const { data: author } = useAuthor(target.pubkey); const { toast } = useToast(); const { webln, activeNWC, hasWebLN, detectWebLN } = useWallet(); const { zap, isZapping, invoice, setInvoice } = useZaps(target, webln, activeNWC, () => setOpen(false)); const [amount, setAmount] = useState(100); const [comment, setComment] = useState(''); const [copied, setCopied] = useState(false); const [qrCodeUrl, setQrCodeUrl] = useState(''); const inputRef = useRef(null); const isMobile = useIsMobile(); useEffect(() => { if (target) { setComment('Zapped with MKStack!'); } }, [target]); // Detect WebLN when dialog opens useEffect(() => { if (open && !hasWebLN) { detectWebLN(); } }, [open, hasWebLN, detectWebLN]); // Generate QR code useEffect(() => { const generateQR = async () => { if (!invoice) return; try { const url = await QRCode.toDataURL(invoice.toUpperCase(), { width: 256, margin: 2, color: { dark: '#000000', light: '#FFFFFF', }, }); setQrCodeUrl(url); } catch (err) { console.error('Failed to generate QR code:', err); } }; generateQR(); }, [invoice]); const handleCopy = async () => { if (invoice) { await navigator.clipboard.writeText(invoice); setCopied(true); toast({ title: 'Invoice copied', description: 'Lightning invoice copied to clipboard', }); setTimeout(() => setCopied(false), 2000); } }; const openInWallet = () => { if (invoice) { const lightningUrl = `lightning:${invoice}`; window.open(lightningUrl, '_blank'); } }; useEffect(() => { if (open) { setAmount(100); setInvoice(null); setCopied(false); setQrCodeUrl(''); } }, [open, setInvoice]); const handleZap = () => { const finalAmount = typeof amount === 'string' ? parseInt(amount, 10) : amount; zap(finalAmount, comment); }; // Shared content component const ZapContent = () => ( <> {invoice ? (
{/* Payment amount display */}
{amount} sats
{/* QR Code */}
{qrCodeUrl ? ( Lightning Invoice QR Code ) : (
)}
{/* Invoice input */}
e.currentTarget.select()} />
{/* Payment buttons */}
{hasWebLN && ( )}
Scan the QR code or copy the invoice to pay with any Lightning wallet.
) : ( <>
{ if (value) { setAmount(parseInt(value, 10)); } }} className="grid grid-cols-5 gap-2 w-full" > {presetAmounts.map(({ amount: presetAmount, icon: Icon }) => ( {presetAmount} ))}
OR
setAmount(e.target.value)} className="w-full" />