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