EmbeddedLNInvoice.tsx raw

   1  import { Button } from '@/components/ui/button'
   2  import { formatAmount, getInvoiceDetails } from '@/lib/lightning'
   3  import { cn } from '@/lib/utils'
   4  import { useNostr } from '@/providers/NostrProvider'
   5  import lightning from '@/services/lightning.service'
   6  import { Loader, Zap } from 'lucide-react'
   7  import { useMemo, useState } from 'react'
   8  import { useTranslation } from 'react-i18next'
   9  import { toast } from 'sonner'
  10  
  11  export function EmbeddedLNInvoice({ invoice, className }: { invoice: string; className?: string }) {
  12    const { t } = useTranslation()
  13    const { checkLogin, pubkey } = useNostr()
  14    const [paying, setPaying] = useState(false)
  15  
  16    const { amount, description } = useMemo(() => {
  17      return getInvoiceDetails(invoice)
  18    }, [invoice])
  19  
  20    const handlePay = async () => {
  21      try {
  22        if (!pubkey) {
  23          throw new Error('You need to be logged in to zap')
  24        }
  25        setPaying(true)
  26        const invoiceResult = await lightning.payInvoice(invoice)
  27        // user canceled
  28        if (!invoiceResult) {
  29          return
  30        }
  31      } catch (error) {
  32        toast.error(t('Lightning payment failed') + ': ' + (error as Error).message)
  33      } finally {
  34        setPaying(false)
  35      }
  36    }
  37  
  38    const handlePayClick = (e: React.MouseEvent) => {
  39      e.stopPropagation()
  40      checkLogin(() => handlePay())
  41    }
  42  
  43    return (
  44      <div
  45        className={cn('p-3 border rounded-lg cursor-default flex flex-col gap-3 max-w-sm', className)}
  46        onClick={(e) => e.stopPropagation()}
  47      >
  48        <div className="flex items-center gap-2">
  49          <Zap className="w-5 h-5 text-yellow-400" />
  50          <div className="font-semibold text-sm">{t('Lightning Invoice')}</div>
  51        </div>
  52        {description && (
  53          <div className="text-sm text-muted-foreground break-words">{description}</div>
  54        )}
  55        <div className="text-lg font-bold">
  56          {formatAmount(amount)} {t('sats')}
  57        </div>
  58        <Button onClick={handlePayClick}>
  59          {paying && <Loader className="w-4 h-4 animate-spin" />}
  60          {t('Pay')}
  61        </Button>
  62      </div>
  63    )
  64  }
  65