From ee8ce711589b8d804bb56c0c6494066d68f72a43 Mon Sep 17 00:00:00 2001 From: Silberengel Date: Wed, 20 May 2026 16:51:50 +0200 Subject: [PATCH] remove zaps --- src/components/NoteStats/ZapButton.tsx | 161 +++++++++++++++++- src/components/PaytoLink/index.tsx | 4 +- src/components/Profile/index.tsx | 42 ++--- src/components/ZapDialog/index.tsx | 79 +++++++-- src/constants.ts | 3 + src/hooks/useProfileAuthorFeedSubRequests.ts | 15 +- src/hooks/useProfileReportsEvents.tsx | 13 +- src/hooks/useProfileWall.tsx | 49 +++--- .../WalletPage/WalletZapSendingSettings.tsx | 74 ++++++++ src/pages/secondary/WalletPage/index.tsx | 71 +------- src/providers/ZapProvider.tsx | 3 + 11 files changed, 364 insertions(+), 150 deletions(-) create mode 100644 src/pages/secondary/WalletPage/WalletZapSendingSettings.tsx diff --git a/src/components/NoteStats/ZapButton.tsx b/src/components/NoteStats/ZapButton.tsx index 47a76b41..533bcd83 100644 --- a/src/components/NoteStats/ZapButton.tsx +++ b/src/components/NoteStats/ZapButton.tsx @@ -1,3 +1,4 @@ +import { ZAP_SENDING_ENABLED } from '@/constants' import { Skeleton } from '@/components/ui/skeleton' import { useNoteStatsById } from '@/hooks/useNoteStatsById' import { @@ -33,7 +34,161 @@ type ZapButtonProps = { noteStats?: Partial } +function formatAmount(amount: number) { + if (amount < 1000) return amount + if (amount < 1000000) return `${Math.round(amount / 100) / 10}k` + return `${Math.round(amount / 100000) / 10}M` +} + +/** Zap tally + payment-methods dialog when {@link ZAP_SENDING_ENABLED} is false. */ +function ZapPaymentMethodsButton({ event, hideCount = false, noteStats }: ZapButtonProps) { + const { t } = useTranslation() + const { pubkey } = useNostr() + const [openPaymentDialog, setOpenPaymentDialog] = useState(false) + const statsLoaded = noteStats?.updatedAt != null + const { zapAmount, hasZapped } = useMemo(() => { + return { + zapAmount: noteStats?.zaps?.reduce((acc, zap) => acc + zap.amount, 0), + hasZapped: pubkey ? noteStats?.zaps?.some((zap) => zap.pubkey === pubkey) : false + } + }, [noteStats, pubkey]) + const showZapAmount = !hideCount && (statsLoaded || (zapAmount ?? 0) > 0) + const authorPubkey = event.pubkey.toLowerCase() + const isSelf = !!pubkey && pubkey.toLowerCase() === authorPubkey + const feedProfiles = useNoteFeedProfileContext() + const feedProfile = feedProfiles?.profiles.get(authorPubkey) + const feedProfileRef = useRef(feedProfile) + feedProfileRef.current = feedProfile + + const [disable, setDisable] = useState(true) + const [tipPaymentData, setTipPaymentData] = useState(null) + + const applyTipAvailability = useCallback( + ( + profile: TProfile | null, + profileEvent: Event | null | undefined, + paymentInfo: ReturnType | null + ) => { + const canTip = recipientHasAnyPaymentOptions( + paymentInfo, + profile, + profileEvent ?? null + ) + setDisable(!canTip) + setTipPaymentData((prev) => + mergeRecipientZapPaymentData( + buildRecipientZapPaymentData(paymentInfo, profile, profileEvent ?? null), + prev + ) + ) + }, + [] + ) + + useEffect(() => { + if (isSelf) return + if (!feedProfile || feedProfile.batchPlaceholder) return + applyTipAvailability(feedProfile, null, null) + }, [isSelf, feedProfile, feedProfiles?.version, applyTipAvailability]) + + useEffect(() => { + if (isSelf) { + setDisable(true) + setTipPaymentData(null) + return + } + + setDisable(true) + setTipPaymentData(null) + let cancelled = false + + void Promise.allSettled([ + replaceableEventService.fetchReplaceableEvent(authorPubkey, kinds.Metadata), + client.fetchPaymentInfoEvent(authorPubkey), + replaceableEventService.getProfileFromIndexedDB(authorPubkey) + ]).then(([profileRes, paymentRes, idbRes]) => { + if (cancelled) return + + const profileEvent = + profileRes.status === 'fulfilled' ? profileRes.value : undefined + const paymentEvent = + paymentRes.status === 'fulfilled' ? paymentRes.value : undefined + const idbProfile = idbRes.status === 'fulfilled' ? idbRes.value : undefined + + const cachedFeed = feedProfileRef.current + const profile = + (profileEvent ? getProfileFromEvent(profileEvent) : null) ?? + (cachedFeed && !cachedFeed.batchPlaceholder ? cachedFeed : null) ?? + idbProfile ?? + null + const paymentInfo = paymentEvent ? getPaymentInfoFromEvent(paymentEvent) : null + + applyTipAvailability(profile, profileEvent ?? null, paymentInfo) + }) + + return () => { + cancelled = true + } + }, [authorPubkey, isSelf, applyTipAvailability]) + + const handleOpenPaymentMethods = (e: React.MouseEvent) => { + e.stopPropagation() + e.preventDefault() + if (disable) return + setOpenPaymentDialog(true) + } + + return ( + <> + + + + ) +} + export function ZapButtonWithStats({ event, hideCount = false, noteStats }: ZapButtonProps) { + if (!ZAP_SENDING_ENABLED) { + return + } + const { t } = useTranslation() const { checkLogin, pubkey } = useNostr() const { defaultZapSats, defaultZapComment, quickZap, includePublicZapReceipt } = useZap() @@ -305,9 +460,3 @@ export default function ZapButton({ event, hideCount = false }: ZapButtonProps) const noteStats = useNoteStatsById(event.id) return } - -function formatAmount(amount: number) { - if (amount < 1000) return amount - if (amount < 1000000) return `${Math.round(amount / 100) / 10}k` - return `${Math.round(amount / 100000) / 10}M` -} diff --git a/src/components/PaytoLink/index.tsx b/src/components/PaytoLink/index.tsx index 188d68df..9124f14b 100644 --- a/src/components/PaytoLink/index.tsx +++ b/src/components/PaytoLink/index.tsx @@ -1,3 +1,4 @@ +import { ZAP_SENDING_ENABLED } from '@/constants' import { useState } from 'react' import { useTranslation } from 'react-i18next' import { toast } from 'sonner' @@ -65,7 +66,8 @@ export default function PaytoLink({ const info = getPaytoTypeInfo(type) const known = isKnownPaytoType(type) const isLightning = isLightningPaytoType(type) - const canZap = isZappableLightningPaytoType(type) && !!pubkey && !!onOpenZap + const canZap = + ZAP_SENDING_ENABLED && isZappableLightningPaytoType(type) && !!pubkey && !!onOpenZap const handleClick = (e: React.MouseEvent) => { e.preventDefault() diff --git a/src/components/Profile/index.tsx b/src/components/Profile/index.tsx index 9a4e9898..22e38134 100644 --- a/src/components/Profile/index.tsx +++ b/src/components/Profile/index.tsx @@ -68,7 +68,6 @@ import ProfileReportsDialog from './ProfileReportsDialog' import SmartFollowings from './SmartFollowings' import SmartMuteLink from './SmartMuteLink' import SmartRelays from './SmartRelays' -import ZapDialog from '@/components/ZapDialog' import PostEditor from '@/components/PostEditor' import { ScheduleVideoCallDialog, @@ -81,6 +80,7 @@ import { FAST_READ_RELAY_URLS, FAST_WRITE_RELAY_URLS } from '@/constants' import { nip66Service } from '@/services/nip66.service' import PaymentMethodsSection from '@/components/PaymentMethodsSection' import { buildRecipientZapPaymentData } from '@/hooks/useRecipientAlternativePayments' +import ZapDialog from '@/components/ZapDialog' import { groupPaymentMethodsByDisplayType, mergePaymentMethods, @@ -114,8 +114,7 @@ export default function Profile({ const { pubkey: accountPubkey, profileEvent: accountProfileEvent, publish, checkLogin } = useNostr() const [paymentInfo, setPaymentInfo] = useState | null>(null) const [profileEvent, setProfileEvent] = useState(undefined) - const [openZapDialog, setOpenZapDialog] = useState(false) - const [zapLightningDefault, setZapLightningDefault] = useState(null) + const [openPaymentDialog, setOpenPaymentDialog] = useState(false) const [openPublicMessageTo, setOpenPublicMessageTo] = useState(null) const [openCallInviteTo, setOpenCallInviteTo] = useState<{ pubkey: string; url: string } | null>(null) const [openScheduleOwnCall, setOpenScheduleOwnCall] = useState(false) @@ -147,12 +146,12 @@ export default function Profile({ [mergedPaymentMethods] ) - const hasTipDialog = useMemo( + const hasPaymentMethods = useMemo( () => recipientHasAnyPaymentOptions(paymentInfo, profile ?? null, effectiveProfileEvent), [paymentInfo, profile, effectiveProfileEvent] ) - const prefetchedZapPayment = useMemo( + const prefetchedPaymentData = useMemo( () => profile?.pubkey ? buildRecipientZapPaymentData(paymentInfo, profile ?? null, effectiveProfileEvent ?? null) @@ -506,15 +505,11 @@ export default function Profile({ )} {!isSelf ? ( <> - {hasTipDialog && ( + {hasPaymentMethods && ( { - if (open) setZapLightningDefault(null) - setOpenZapDialog(open) - if (!open) setZapLightningDefault(null) - }} + openZapDialog={openPaymentDialog} + setOpenZapDialog={setOpenPaymentDialog} /> )} @@ -585,24 +580,17 @@ export default function Profile({ { - setZapLightningDefault(lightningAuthority) - setOpenZapDialog(true) - }} className="mt-2 mb-4 p-3 pb-4 border rounded-lg bg-muted/50 min-w-0" /> )} - { - const willOpen = typeof next === 'function' ? next(openZapDialog) : next - setOpenZapDialog(willOpen) - if (!willOpen) setZapLightningDefault(null) - }} - pubkey={pubkey} - defaultLightningAddress={zapLightningDefault} - prefetchedPayment={prefetchedZapPayment} - /> + {!isSelf && hasPaymentMethods && ( + + )}
diff --git a/src/components/ZapDialog/index.tsx b/src/components/ZapDialog/index.tsx index a25299fe..137502b9 100644 --- a/src/components/ZapDialog/index.tsx +++ b/src/components/ZapDialog/index.tsx @@ -1,3 +1,4 @@ +import { ZAP_SENDING_ENABLED } from '@/constants' import { Button } from '@/components/ui/button' import { Dialog, @@ -32,7 +33,10 @@ import { useTranslation } from 'react-i18next' import { toast } from 'sonner' import { buildOrderedZapLightningAddresses, + groupPaymentMethodsByDisplayType, + mergePaymentMethods, prepareZapDialogAlternativePayments, + sortMergedPaymentMethods, ZAP_HIDE_BITCOIN_ALTS_MAX_SATS } from '@/lib/merge-payment-methods' import PaymentMethodsSection from '@/components/PaymentMethodsSection' @@ -102,12 +106,20 @@ export default function ZapDialog({ ] ) const canLightningZap = lightningAddressOptions.length > 0 - const dialogTitlePrefix = canLightningZap ? t('Zap to') : t('Pay to') - const dialogDescription = canLightningZap - ? t('Send a Lightning payment to this user') - : t('Send a payment to this user') + const paymentsOnly = !ZAP_SENDING_ENABLED + const dialogTitlePrefix = paymentsOnly + ? t('Payment methods') + : canLightningZap + ? t('Zap to') + : t('Pay to') + const dialogDescription = paymentsOnly + ? t('Payment methods') + : canLightningZap + ? t('Send a Lightning payment to this user') + : t('Send a payment to this user') const maybeOfferTipNoticeOnClose = () => { + if (paymentsOnly) return if (skipTipNoticeOnCloseRef.current) return if (selfPubkey && pubkey === selfPubkey) return setTipNoticeOpen(true) @@ -186,11 +198,13 @@ export default function ZapDialog({ }} /> - + {!paymentsOnly && ( + + )} ) } @@ -223,11 +237,13 @@ export default function ZapDialog({ /> - + {!paymentsOnly && ( + + )} ) } @@ -258,8 +274,43 @@ function ZapDialogContent({ }) { const { t, i18n } = useTranslation() const { pubkey } = useNostr() + const paymentsOnly = !ZAP_SENDING_ENABLED const { defaultZapSats, defaultZapComment, includePublicZapReceipt, updateIncludePublicZapReceipt } = useZap() + + const allPaymentGroups = useMemo(() => { + if (!paymentsOnly) return [] + const merged = sortMergedPaymentMethods( + mergePaymentMethods( + recipientPayment.paymentInfo, + recipientPayment.profile, + recipientPayment.profileEvent + ) + ) + return groupPaymentMethodsByDisplayType(merged) + }, [paymentsOnly, recipientPayment]) + + if (paymentsOnly) { + return ( +
+ {allPaymentGroups.length > 0 ? ( + + ) : ( +

+ {t('No payment methods available for this profile')} +

+ )} +
+ ) + } const [sats, setSats] = useState(() => clampZapSats(defaultAmount ?? defaultZapSats)) const [comment, setComment] = useState(defaultComment ?? defaultZapComment) const [zapping, setZapping] = useState(false) diff --git a/src/constants.ts b/src/constants.ts index 69c6ed60..a7647fe9 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -603,6 +603,9 @@ export const ExtendedKind = { EVENTS_I_MUTED_NOTIFICATIONS_LIST: 19132 } +/** NIP-57 send flow (wallet connect, zap dialog, note zap button). Kind 9735 receipts and payment targets stay visible when false. */ +export const ZAP_SENDING_ENABLED = false + /** Kind 0 + NIP-A3 payment: publish to profile mirrors, full outbox (NIP-65 + HTTP + cache), and IndexedDB. */ export function isAuthorProfileMetadataPublishKind(kind: number): boolean { return kind === kinds.Metadata || kind === ExtendedKind.PAYMENT_INFO diff --git a/src/hooks/useProfileAuthorFeedSubRequests.ts b/src/hooks/useProfileAuthorFeedSubRequests.ts index d8b75a1a..3ddbf58c 100644 --- a/src/hooks/useProfileAuthorFeedSubRequests.ts +++ b/src/hooks/useProfileAuthorFeedSubRequests.ts @@ -2,7 +2,7 @@ import { buildProfileAuthorSubRequestsFromUrlGroups } from '@/lib/profile-author import { isSocialKindBlockedKind } from '@/constants' import { useGlobalRelayBootstrapDefaults } from '@/hooks/use-global-relay-bootstrap-defaults' import { buildProfilePageReadRelayUrls } from '@/lib/favorites-feed-relays' -import { hexPubkeysEqual, normalizeHexPubkey } from '@/lib/pubkey' +import { hexPubkeysEqual, isValidPubkey, normalizeHexPubkey, userIdToPubkey } from '@/lib/pubkey' import { normalizeAnyRelayUrl } from '@/lib/url' import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider' import { useNostrOptional } from '@/providers/nostr-context' @@ -65,11 +65,8 @@ export function useProfileAuthorFeedSubRequests({ const kindsKey = useMemo(() => [...kinds].join(','), [kinds]) const authorHex = useMemo(() => { - try { - return normalizeHexPubkey(pubkey) - } catch { - return pubkey.trim() - } + const pk = userIdToPubkey(pubkey) + return isValidPubkey(pk) ? pk : '' }, [pubkey]) const [refreshToken, setRefreshToken] = useState(0) @@ -103,6 +100,10 @@ export function useProfileAuthorFeedSubRequests({ } } + // Bootstrap immediately (favorites + fast-read) so /users/… feeds are not stuck on "Nothing to load" + // while fetchRelayList runs (often 10–30s under relay contention). + applyRelayList(emptyAuthor) + void client .peekRelayListFromStorage(pubkey) .then((cached) => { @@ -125,7 +126,7 @@ export function useProfileAuthorFeedSubRequests({ }, [pubkey, relayListsKey, kindsKey, kinds, refreshToken, includeAuthorLocalRelays, useGlobalRelayBootstrap]) const subRequests = useMemo(() => { - if (!relayUrls?.length) return [] as TFeedSubRequest[] + if (!relayUrls?.length || !authorHex) return [] as TFeedSubRequest[] return buildProfileAuthorSubRequestsFromUrlGroups([relayUrls], authorHex, [...kinds], limit) }, [relayUrls, authorHex, kinds, limit]) diff --git a/src/hooks/useProfileReportsEvents.tsx b/src/hooks/useProfileReportsEvents.tsx index 4b4c5631..f1dc264d 100644 --- a/src/hooks/useProfileReportsEvents.tsx +++ b/src/hooks/useProfileReportsEvents.tsx @@ -1,10 +1,11 @@ -import { ExtendedKind } from '@/constants' +import { ExtendedKind, FAST_READ_RELAY_URLS, PROFILE_RELAY_URLS } from '@/constants' import { useGlobalRelayBootstrapDefaults } from '@/hooks/use-global-relay-bootstrap-defaults' import type { ProfileTimelineRelayUrlsBuilder } from '@/hooks/useProfileTimeline' import { buildProfilePageReadRelayUrls, mergeRelayUrlLayers } from '@/lib/favorites-feed-relays' import { isNip56ReportEvent } from '@/lib/event' import { isReportAuthoredBy, reportTargetsPubkey } from '@/lib/nip56-reports' import { normalizeHexPubkey } from '@/lib/pubkey' +import { dedupeNormalizeRelayUrlsOrdered } from '@/lib/relay-url-priority' import { normalizeAnyRelayUrl, subtractNormalizedRelayUrls } from '@/lib/url' import { useDeletedEvent } from '@/providers/DeletedEventProvider' import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider' @@ -207,7 +208,15 @@ export function useProfileReportsEvents({ } const emptyAuthor = { read: [] as string[], write: [] as string[], httpRead: [] as string[], httpWrite: [] as string[] } - const provisionalUrls = resolveFeedUrls(emptyAuthor, includeAuthorLocalRelays) + const authorPeek = await client.peekRelayListFromStorage(pubkey).catch(() => emptyAuthor) + if (cancelled) return + let provisionalUrls = resolveFeedUrls(authorPeek, includeAuthorLocalRelays) + if (provisionalUrls.length === 0) { + provisionalUrls = dedupeNormalizeRelayUrlsOrdered([ + ...PROFILE_RELAY_URLS, + ...FAST_READ_RELAY_URLS + ]).slice(0, 24) + } if (provisionalUrls.length === 0) return const filter = buildFilter(pkNorm, mode, limit) diff --git a/src/hooks/useProfileWall.tsx b/src/hooks/useProfileWall.tsx index 0ca6bc7c..de89e9da 100644 --- a/src/hooks/useProfileWall.tsx +++ b/src/hooks/useProfileWall.tsx @@ -18,12 +18,11 @@ import { type ResolvedProfileBadge } from '@/lib/nip58-profile-badges' import { isDirectProfileWallComment } from '@/lib/profile-wall-comments' -import { normalizeHexPubkey } from '@/lib/pubkey' +import { isValidPubkey, userIdToPubkey } from '@/lib/pubkey' import { normalizeAnyRelayUrl } from '@/lib/url' import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider' import { useDeletedEvent } from '@/providers/DeletedEventProvider' import client, { replaceableEventService } from '@/services/client.service' -import { ReplaceableEventService } from '@/services/client-replaceable-events.service' import indexedDb from '@/services/indexed-db.service' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { Event, kinds, type Filter } from 'nostr-tools' @@ -111,6 +110,8 @@ export function useProfileWall(pubkey: string, profileEventId: string | undefine useEffect(() => { let cancelled = false + let idleHandle: number | undefined + let idleTimeout: ReturnType | undefined const run = async () => { const mem = wallCacheByKey.get(cacheKey) @@ -123,15 +124,14 @@ export function useProfileWall(pubkey: string, profileEventId: string | undefine setIsLoading(true) - let pkNorm = pubkey - try { - pkNorm = normalizeHexPubkey(pubkey) - } catch { - /* use raw */ + const pkNorm = userIdToPubkey(pubkey) || pubkey + if (!isValidPubkey(pkNorm)) { + if (!cancelled) setIsLoading(false) + return } const emptyAuthor = { read: [] as string[], write: [] as string[], httpRead: [] as string[], httpWrite: [] as string[] } - const authorRl = await client.fetchRelayList(pubkey).catch(() => emptyAuthor) + const authorRl = await client.peekRelayListFromStorage(pubkey).catch(() => emptyAuthor) if (cancelled) return const relayUrls = buildProfilePageReadRelayUrls( @@ -212,9 +212,23 @@ export function useProfileWall(pubkey: string, profileEventId: string | undefine setIsLoading(false) } - void run() + const scheduleRun = () => { + if (typeof requestIdleCallback === 'function') { + idleHandle = requestIdleCallback(() => void run(), { timeout: 4_000 }) + } else { + idleTimeout = setTimeout(() => void run(), 400) + } + } + scheduleRun() + return () => { cancelled = true + if (idleHandle !== undefined && typeof cancelIdleCallback === 'function') { + cancelIdleCallback(idleHandle) + } + if (idleTimeout !== undefined) { + clearTimeout(idleTimeout) + } } }, [pubkey, profileEventId, cacheKey, refreshToken, relayListsKey]) @@ -224,22 +238,5 @@ export function useProfileWall(pubkey: string, profileEventId: string | undefine setRefreshToken((t) => t + 1) }, [cacheKey]) - useEffect(() => { - const onAuthorReplaceablesRefreshed: EventListener = (domEvt) => { - const pk = (domEvt as CustomEvent<{ pubkey?: string }>).detail?.pubkey?.toLowerCase() - if (!pk || pk !== normalizeHexPubkey(pubkey)) return - refresh() - } - window.addEventListener( - ReplaceableEventService.AUTHOR_REPLACEABLES_REFRESHED_EVENT, - onAuthorReplaceablesRefreshed - ) - return () => - window.removeEventListener( - ReplaceableEventService.AUTHOR_REPLACEABLES_REFRESHED_EVENT, - onAuthorReplaceablesRefreshed - ) - }, [pubkey, refresh]) - return { badges, comments, isLoading, refresh } } diff --git a/src/pages/secondary/WalletPage/WalletZapSendingSettings.tsx b/src/pages/secondary/WalletPage/WalletZapSendingSettings.tsx new file mode 100644 index 00000000..071f9d3a --- /dev/null +++ b/src/pages/secondary/WalletPage/WalletZapSendingSettings.tsx @@ -0,0 +1,74 @@ +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger +} from '@/components/ui/alert-dialog' +import { Button } from '@/components/ui/button' +import { useZap } from '@/providers/ZapProvider' +import { disconnect, launchModal } from '@getalby/bitcoin-connect-react' +import { useTranslation } from 'react-i18next' +import DefaultZapAmountInput from './DefaultZapAmountInput' +import DefaultZapCommentInput from './DefaultZapCommentInput' +import QuickZapSwitch from './QuickZapSwitch' +import IncludePublicZapReceiptSwitch from './IncludePublicZapReceiptSwitch' + +export default function WalletZapSendingSettings() { + const { t } = useTranslation() + const { isWalletConnected, walletInfo } = useZap() + + if (isWalletConnected) { + return ( + <> +
+ {walletInfo?.node.alias && ( +
+ {t('Connected to')} {walletInfo.node.alias} +
+ )} + + + + + + + {t('Are you absolutely sure?')} + + {t('You will not be able to send zaps to others.')} + + + + {t('Cancel')} + disconnect()}> + {t('Disconnect')} + + + + +
+ + + + + + ) + } + + return ( +
+ +
+ ) +} diff --git a/src/pages/secondary/WalletPage/index.tsx b/src/pages/secondary/WalletPage/index.tsx index 65cb711b..7a3e64a0 100644 --- a/src/pages/secondary/WalletPage/index.tsx +++ b/src/pages/secondary/WalletPage/index.tsx @@ -1,35 +1,18 @@ -import { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, - AlertDialogTrigger -} from '@/components/ui/alert-dialog' import { RefreshButton } from '@/components/RefreshButton' -import { Button } from '@/components/ui/button' +import { ZAP_SENDING_ENABLED } from '@/constants' import SecondaryPageLayout from '@/layouts/SecondaryPageLayout' import { usePrimaryNoteView } from '@/contexts/primary-note-view-context' -import { useZap } from '@/providers/ZapProvider' -import { disconnect, launchModal } from '@getalby/bitcoin-connect-react' import { forwardRef, useCallback, useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' -import DefaultZapAmountInput from './DefaultZapAmountInput' -import DefaultZapCommentInput from './DefaultZapCommentInput' import LightningAddressInput from './LightningAddressInput' -import QuickZapSwitch from './QuickZapSwitch' -import IncludePublicZapReceiptSwitch from './IncludePublicZapReceiptSwitch' import ZapReplyThresholdInput from './ZapReplyThresholdInput' +import WalletZapSendingSettings from './WalletZapSendingSettings' const WalletPage = forwardRef(({ index, hideTitlebar = false }: { index?: number; hideTitlebar?: boolean }, ref) => { const { t } = useTranslation() const { registerPrimaryPanelRefresh } = usePrimaryNoteView() const [contentKey, setContentKey] = useState(0) const bump = useCallback(() => setContentKey((k) => k + 1), []) - const { isWalletConnected, walletInfo } = useZap() useEffect(() => { if (!hideTitlebar) { @@ -48,54 +31,8 @@ const WalletPage = forwardRef(({ index, hideTitlebar = false }: { index?: number controls={hideTitlebar ? undefined : } >
- {isWalletConnected ? ( - <> -
- {walletInfo?.node.alias && ( -
- {t('Connected to')} {walletInfo.node.alias} -
- )} - - - - - - - {t('Are you absolutely sure?')} - - {t('You will not be able to send zaps to others.')} - - - - {t('Cancel')} - disconnect()}> - {t('Disconnect')} - - - - -
- - - - - - - ) : ( -
- -
- )} - - {/* Zap Reply Threshold - always visible as it's just a display setting */} + {ZAP_SENDING_ENABLED ? : null} +
diff --git a/src/providers/ZapProvider.tsx b/src/providers/ZapProvider.tsx index f87eae76..9bae4976 100644 --- a/src/providers/ZapProvider.tsx +++ b/src/providers/ZapProvider.tsx @@ -1,3 +1,4 @@ +import { ZAP_SENDING_ENABLED } from '@/constants' import lightningService from '@/services/lightning.service' import storage from '@/services/local-storage.service' import { onConnected, onDisconnected } from '@getalby/bitcoin-connect-react' @@ -43,6 +44,8 @@ export function ZapProvider({ children }: { children: React.ReactNode }) { const [walletInfo, setWalletInfo] = useState(null) useEffect(() => { + if (!ZAP_SENDING_ENABLED) return + const unSubOnConnected = onConnected((provider) => { setIsWalletConnected(true) setWalletInfo(null)