From 7fdcb658b39baf763ebc9db05bb0678a683b4f2b Mon Sep 17 00:00:00 2001 From: Chad Curtis Date: Sat, 12 Jul 2025 19:23:50 +0000 Subject: [PATCH] use single zaps component --- src/components/ZapButton.tsx | 56 ---------------- .../{ZapModal.tsx => ZapDialog.tsx} | 64 +++++++++++++++---- src/hooks/useZaps.ts | 4 +- 3 files changed, 52 insertions(+), 72 deletions(-) delete mode 100644 src/components/ZapButton.tsx rename src/components/{ZapModal.tsx => ZapDialog.tsx} (76%) diff --git a/src/components/ZapButton.tsx b/src/components/ZapButton.tsx deleted file mode 100644 index 863a288..0000000 --- a/src/components/ZapButton.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { useState } from 'react'; -import { Zap } from 'lucide-react'; -import { Button } from '@/components/ui/button'; -import { useCurrentUser } from '@/hooks/useCurrentUser'; -import { requestProvider } from 'webln'; -import type { WebLNProvider } from 'webln'; -import { ZapModal } from './ZapModal'; -import { useAuthor } from '@/hooks/useAuthor'; - -export interface ZapTarget { - pubkey: string; - id: string; - relays?: string[]; - dTag?: string; - naddr?: string; -} - -interface ZapButtonProps { - target: ZapTarget; - children?: React.ReactNode; - className?: string; -} - -export function ZapButton({ target, children, className }: ZapButtonProps) { - const [webln, setWebln] = useState(null); - const [isModalOpen, setIsModalOpen] = useState(false); - const { user } = useCurrentUser(); - const { data: author } = useAuthor(target.pubkey); - - const handleOpenModal = async () => { - if (!webln) { - try { - const provider = await requestProvider(); - setWebln(provider); - } catch (err) { - // Silently fail - console.error(err); - } - } - setIsModalOpen(true); - }; - - if (!user || user.pubkey === target.pubkey || !author?.metadata?.lud16) { - return null; - } - - return ( - <> - - {isModalOpen && } - - ); -} diff --git a/src/components/ZapModal.tsx b/src/components/ZapDialog.tsx similarity index 76% rename from src/components/ZapModal.tsx rename to src/components/ZapDialog.tsx index 625deeb..6e567c1 100644 --- a/src/components/ZapModal.tsx +++ b/src/components/ZapDialog.tsx @@ -1,10 +1,5 @@ -import { useToast } from '@/hooks/useToast'; -import { useZaps } from '@/hooks/useZaps'; -import type { WebLNProvider } from 'webln'; -import type { ZapTarget } from '@/components/ZapButton'; -import QRCode from 'qrcode'; +import { useState, useEffect, useRef } from 'react'; import { Zap, Copy } from 'lucide-react'; -import React, { useState, useEffect, useRef } from 'react'; import { Button } from '@/components/ui/button'; import { Dialog, @@ -13,23 +8,42 @@ import { DialogFooter, DialogHeader, DialogTitle, + DialogTrigger, } from '@/components/ui/dialog'; import { Input } from '@/components/ui/input'; import { Textarea } from '@/components/ui/textarea'; 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 { requestProvider } from 'webln'; +import type { WebLNProvider } from 'webln'; +import QRCode from 'qrcode'; -interface ZapModalProps { - open: boolean; - onOpenChange: (open: boolean) => void; +export interface ZapTarget { + pubkey: string; + id: string; + relays?: string[]; + dTag?: string; + naddr?: string; +} + +interface ZapDialogProps { target: ZapTarget; - webln: WebLNProvider | null; + children?: React.ReactNode; + className?: string; } const presetAmounts = [1, 50, 100, 250, 1000]; -export function ZapModal({ open, onOpenChange, target, webln }: ZapModalProps) { +export function ZapDialog({ target, children, className }: ZapDialogProps) { + const [open, setOpen] = useState(false); + const [webln, setWebln] = useState(null); + const { user } = useCurrentUser(); + const { data: author } = useAuthor(target.pubkey); const { toast } = useToast(); - const { zap, isZapping, invoice, setInvoice } = useZaps(target, webln, () => onOpenChange(false)); + const { zap, isZapping, invoice, setInvoice } = useZaps(target, webln, () => setOpen(false)); const [amount, setAmount] = useState(100); const [comment, setComment] = useState(''); const inputRef = useRef(null); @@ -68,9 +82,31 @@ export function ZapModal({ open, onOpenChange, target, webln }: ZapModalProps) { zap(finalAmount, comment); }; + const handleTriggerClick = async () => { + if (!webln) { + try { + const provider = await requestProvider(); + setWebln(provider); + } catch (err) { + // Silently fail + console.error(err); + } + } + }; + + if (!user || user.pubkey === target.pubkey || !author?.metadata?.lud16) { + return null; + } + return ( - - + + + + + {invoice ? 'Manual Zap' : 'Send a Zap'} diff --git a/src/hooks/useZaps.ts b/src/hooks/useZaps.ts index 38a5fcf..72eb1e0 100644 --- a/src/hooks/useZaps.ts +++ b/src/hooks/useZaps.ts @@ -6,7 +6,7 @@ import { useAppContext } from '@/hooks/useAppContext'; import { useToast } from '@/hooks/useToast'; import { nip57, nip19, Event } from 'nostr-tools'; import type { WebLNProvider } from 'webln'; -import type { ZapTarget } from '@/components/ZapButton'; +import type { ZapTarget } from '@/components/ZapDialog'; import { useQuery } from '@tanstack/react-query'; import { useNostr } from '@nostrify/react'; import type { NostrEvent, NostrFilter } from '@nostrify/nostrify'; @@ -28,7 +28,7 @@ export function useZaps(target: ZapTarget, webln: WebLNProvider | null, onZapSuc queryFn: async (c) => { if (!target.id && !target.naddr) return []; const signal = AbortSignal.any([c.signal, AbortSignal.timeout(1500)]); - + const filters: NostrFilter[] = []; if (target.naddr) {