import { useState, useEffect } from 'react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { useToast } from '@/hooks/useToast'; import { useWallet } from '@/hooks/useWallet'; import { useNWC } from '@/hooks/useNWCContext'; import { getInvoiceFromLightningAddress } from '@/lib/lightningAddress'; import { LISTING_FEE_SATS, PLATFORM_LIGHTNING_ADDRESS } from '@/hooks/useListingRestrictions'; import { Zap, Loader2, CheckCircle, Copy, ExternalLink, ShieldAlert, TrendingUp, MapPin } from 'lucide-react'; // qrcode imported lazily in async function interface SpamFeePaymentProps { feeRecipient: string; feeRecipientName: string; onPaymentSuccess: () => void; onSkip?: () => void; } type PaymentState = 'idle' | 'generating' | 'waiting' | 'paying' | 'success' | 'error'; export function SpamFeePayment({ feeRecipient, feeRecipientName, onPaymentSuccess, }: SpamFeePaymentProps) { const { toast } = useToast(); const { webln, activeNWC } = useWallet(); const { sendPayment } = useNWC(); const [paymentState, setPaymentState] = useState('idle'); const [invoice, setInvoice] = useState(null); const [qrCodeUrl, setQrCodeUrl] = useState(null); const [error, setError] = useState(null); // Auto-pay when wallet is connected and invoice is generated useEffect(() => { if (invoice && paymentState === 'waiting' && (webln || activeNWC)) { handleAutoPay(); } }, [invoice, paymentState, webln, activeNWC]); const generateInvoice = async () => { setPaymentState('generating'); setError(null); try { const bolt11 = await getInvoiceFromLightningAddress({ lightningAddress: feeRecipient, amountSats: LISTING_FEE_SATS, comment: 'SkateSpots listing fee', }); setInvoice(bolt11); // Generate QR code const { default: QRCode } = await import('qrcode'); const qr = await QRCode.toDataURL(bolt11.toUpperCase(), { width: 256, margin: 2, color: { dark: '#000000', light: '#ffffff', }, }); setQrCodeUrl(qr); setPaymentState('waiting'); // If wallet is available, try auto-pay if (webln || activeNWC) { await handleAutoPay(); } } catch (err) { console.error('Failed to generate invoice:', err); setError(err instanceof Error ? err.message : 'Failed to generate invoice'); setPaymentState('error'); } }; const handleAutoPay = async () => { if (!invoice) return; setPaymentState('paying'); try { // Try NWC first if (activeNWC && activeNWC.isConnected) { await sendPayment(activeNWC, invoice); setPaymentState('success'); toast({ title: 'Payment successful!', description: `${LISTING_FEE_SATS} sats sent to ${feeRecipientName}`, }); setTimeout(onPaymentSuccess, 1500); return; } // Try WebLN if (webln) { if (webln.enable) { await webln.enable(); } await webln.sendPayment(invoice); setPaymentState('success'); toast({ title: 'Payment successful!', description: `${LISTING_FEE_SATS} sats sent to ${feeRecipientName}`, }); setTimeout(onPaymentSuccess, 1500); return; } // No auto-pay available, stay in waiting state setPaymentState('waiting'); } catch (err) { console.error('Auto-pay failed:', err); // Fall back to manual payment setPaymentState('waiting'); toast({ title: 'Auto-pay failed', description: 'Please pay manually using the QR code or invoice', variant: 'destructive', }); } }; const copyInvoice = async () => { if (!invoice) return; try { await navigator.clipboard.writeText(invoice); toast({ title: 'Invoice copied!' }); } catch { toast({ title: 'Failed to copy', variant: 'destructive' }); } }; const openInWallet = () => { if (!invoice) return; window.open(`lightning:${invoice}`, '_blank'); }; // Show success state if (paymentState === 'success') { return (

Payment Received!

Your {LISTING_FEE_SATS} sat fee has been paid. You can now create your listing.

); } // Show payment flow return ( One-Time Listing Fee As a new member, a small fee is required for your first listing. {/* Why this fee exists */}

Why do I need to pay?

Spam prevention: This fee stops bots and scammers from flooding the marketplace with fake listings.

Trust building: New accounts need to prove commitment before listing. After a few successful listings, this fee is waived.

Supports the community: Fee goes to{' '} {feeRecipientName} {feeRecipient !== PLATFORM_LIGHTNING_ADDRESS && ' — the person who created this spot!'} {feeRecipient === PLATFORM_LIGHTNING_ADDRESS && ' — helping keep SkateSpots running.'}

{/* Fee amount */}
⚡ {LISTING_FEE_SATS.toLocaleString()} sats

~${(LISTING_FEE_SATS * 0.0006).toFixed(2)} USD • One-time fee

{/* Initial state - generate invoice button */} {paymentState === 'idle' && ( )} {/* Generating invoice */} {paymentState === 'generating' && (

Generating invoice...

)} {/* Paying */} {paymentState === 'paying' && (

Processing payment...

)} {/* Waiting for payment - show QR and manual options */} {paymentState === 'waiting' && invoice && qrCodeUrl && (
{/* QR Code */}
Payment QR Code
{/* Action buttons */}
{/* Try again with wallet */} {(webln || activeNWC) && ( )}

Scan the QR code with a Lightning wallet or use the buttons above

)} {/* Error state */} {paymentState === 'error' && error && (

{error}

)} {/* How to avoid future fees */}

✨ How to skip this fee in the future:

  • → Add a skate spot to the map
  • → Complete 2-3 successful listings
  • → Build your community reputation

Trusted members get unlimited free listings!

); }