diff --git a/src/components/ContentDetailModal.vue b/src/components/ContentDetailModal.vue index 79a00f4..a9382d9 100644 --- a/src/components/ContentDetailModal.vue +++ b/src/components/ContentDetailModal.vue @@ -143,8 +143,8 @@ {{ content.creator }} - -
+ +
@@ -157,7 +157,7 @@ v-for="(zap, idx) in displayZaps" :key="zap.pubkey + '-' + zap.timestamp + '-' + idx" class="zap-avatar-pill" - :title="getZapperName(zap.pubkey) + ' — ' + zap.amount.toLocaleString() + ' sats'" + :title="zap.amount > 0 ? getZapperName(zap.pubkey) + ' — ' + zap.amount.toLocaleString() + ' sats' : getZapperName(zap.pubkey) + ' zapped'" > nostr.reactionCounts.value) const isLoadingComments = computed(() => nostr.isLoading.value) const commentCount = computed(() => nostr.commentCount.value) -// Zap data from relay -const zapsList = computed(() => nostr.zaps.value) +// Backend zap stats (BTCPay in-app zaps) so modal shows total + who zapped +const backendZapStats = ref<{ + zapCount: number + zapAmountSats: number + recentZapperPubkeys: string[] +} | null>(null) + +// Zap data: merge Nostr relay (9735) + backend so in-app zaps show too +const zapsList = computed(() => { + const fromNostr = nostr.zaps.value + const backend = backendZapStats.value + const nostrPubkeys = new Set(fromNostr.map((z) => z.pubkey)) + const fromBackend: { pubkey: string; amount: number; timestamp: number }[] = [] + if (backend?.recentZapperPubkeys?.length) { + for (const pk of backend.recentZapperPubkeys) { + if (!nostrPubkeys.has(pk)) { + fromBackend.push({ pubkey: pk, amount: 0, timestamp: 0 }) + } + } + } + const merged = [...fromNostr, ...fromBackend] + return merged.sort((a, b) => b.timestamp - a.timestamp) +}) const displayZaps = computed(() => zapsList.value.slice(0, 8)) -const totalZapSats = computed(() => zapsList.value.reduce((sum, z) => sum + z.amount, 0)) +const totalZapSats = computed(() => { + const fromNostr = nostr.zaps.value.reduce((sum, z) => sum + z.amount, 0) + const fromBackend = backendZapStats.value?.zapAmountSats ?? 0 + return fromNostr + fromBackend +}) // User's existing reaction read from relay (not local state) const userReaction = computed(() => nostr.userContentReaction.value) @@ -400,6 +426,7 @@ watch(() => props.content?.id, (newId) => { if (newId && props.isOpen) { loadSocialData(newId) checkRentalAccess() + fetchBackendZapStats(newId) } }) @@ -407,13 +434,23 @@ watch(() => props.isOpen, (open) => { if (open && props.content?.id) { loadSocialData(props.content.id) checkRentalAccess() + fetchBackendZapStats(props.content.id) } else if (!open) { - // Reset rental state when modal closes hasActiveRental.value = false rentalExpiresAt.value = null + backendZapStats.value = null } }) +async function fetchBackendZapStats(contentId: string) { + try { + const data = await indeehubApiService.getZapStats([contentId]) + backendZapStats.value = data[contentId] ?? null + } catch { + backendZapStats.value = null + } +} + function loadSocialData(contentId: string) { nostr.cleanup() nostr.subscribeToContent(contentId) @@ -505,8 +542,8 @@ function handleZap() { } function handleZapped(_amount: number) { - // The zap was confirmed — the relay subscription will pick up - // the zap receipt automatically and update zapsList. + // In-app zaps go through BTCPay; refetch backend stats so modal updates. + if (props.content?.id) fetchBackendZapStats(props.content.id) } function getZapperName(pubkey: string): string { @@ -522,6 +559,7 @@ function getZapperPicture(pubkey: string): string { } function formatZapAmount(sats: number): string { + if (sats <= 0) return '—' if (sats >= 1_000_000) return (sats / 1_000_000).toFixed(1) + 'M' if (sats >= 1_000) return (sats / 1_000).toFixed(sats >= 10_000 ? 0 : 1) + 'k' return sats.toLocaleString() diff --git a/src/components/ContentRow.vue b/src/components/ContentRow.vue index 168316f..0b18a5c 100644 --- a/src/components/ContentRow.vue +++ b/src/components/ContentRow.vue @@ -45,21 +45,7 @@ {{ getCommentCount(content.id) }} - -