feat: enhance zap functionality with stats tracking and pubkey support

- Added a new endpoint in ZapsController to retrieve zap statistics by project IDs, including total counts, amounts, and recent zapper pubkeys.
- Updated ZapsService to record zap statistics, including optional zapper pubkey for tracking who zapped.
- Enhanced CreateZapInvoiceDto to include an optional zapperPubkey field.
- Modified frontend components to display zap stats and integrate with the new backend functionality, improving user engagement and transparency.

These changes improve the overall zap experience by providing detailed insights into zap activities and enhancing the tracking of contributors.
This commit is contained in:
Dorian
2026-02-14 15:35:59 +00:00
parent bb4f13fc65
commit 66db9376ed
10 changed files with 208 additions and 16 deletions

View File

@@ -78,6 +78,12 @@ function getTagValue(event: NostrEvent, tagName: string): string | undefined {
return event.tags.find((t) => t[0] === tagName)?.[1]
}
/** If externalId is a URL like .../content/ID, return ID so we can index by both. */
function bareContentIdFromExternal(externalId: string): string | null {
const match = externalId.match(/\/content\/([^/]+)$/)
return match ? match[1] : null
}
/**
* Rebuild the stats map from current EventStore data
*/
@@ -98,6 +104,9 @@ function rebuildStats() {
recentEvents: [],
}
map.set(id, stats)
// Index by bare content id too (e.g. project id) so getStats(content.id) finds it
const bare = bareContentIdFromExternal(id)
if (bare && bare !== id) map.set(bare, stats)
}
return stats
}
@@ -279,10 +288,11 @@ export function useContentDiscovery() {
const statsMap = contentStatsMap.value
// Build entries array: [Content, stats] for each content item
// Build entries array: [Content, stats] for each content item (same dual-key as getStats)
const withStats: [Content, ContentStats][] = contents.map((c) => {
const externalId = getExternalContentId(c.id)
return [c, statsMap.get(externalId) || EMPTY_STATS]
const stats = statsMap.get(externalId) || statsMap.get(c.id) || EMPTY_STATS
return [c, stats]
})
// Sort entries
@@ -316,11 +326,16 @@ export function useContentDiscovery() {
}
/**
* Get stats for a specific content item
* Get stats for a specific content item (Nostr discovery).
* Lookup by full external URL and by bare content id so relay data matches either format.
*/
function getStats(contentId: string): ContentStats {
const externalId = getExternalContentId(contentId)
return contentStatsMap.value.get(externalId) || EMPTY_STATS
return (
contentStatsMap.value.get(externalId) ||
contentStatsMap.value.get(contentId) ||
EMPTY_STATS
)
}
return {