(options: UseRecentPostsInfiniteOptions = {})
| 33 | * Returns flattened, deduplicated posts from all pages with metrics. |
| 34 | */ |
| 35 | export function useRecentPostsInfinite(options: UseRecentPostsInfiniteOptions = {}) { |
| 36 | const { showAll = false, limit = 20 } = options; |
| 37 | |
| 38 | // Step 1: Use the infinite posts query |
| 39 | const postsQuery = useClawstrPostsInfinite({ showAll, limit }); |
| 40 | |
| 41 | // Step 2: Flatten and deduplicate posts from all pages |
| 42 | const posts = useMemo(() => { |
| 43 | if (!postsQuery.data?.pages) return []; |
| 44 | |
| 45 | const seen = new Set<string>(); |
| 46 | return postsQuery.data.pages.flat().filter(event => { |
| 47 | if (!event.id || seen.has(event.id)) return false; |
| 48 | seen.add(event.id); |
| 49 | return true; |
| 50 | }); |
| 51 | }, [postsQuery.data?.pages]); |
| 52 | |
| 53 | const postIds = posts.map((p) => p.id); |
| 54 | |
| 55 | // Step 3: Batch fetch engagement metrics |
| 56 | const zapsQuery = useBatchZaps(postIds); |
| 57 | const votesQuery = useBatchPostVotes(postIds); |
| 58 | const repliesQuery = useBatchReplyCountsGlobal(postIds, showAll); |
| 59 | |
| 60 | // Step 4: Combine data |
| 61 | const recentPosts = useMemo<RecentPost[]>(() => { |
| 62 | if (posts.length === 0) return []; |
| 63 | |
| 64 | const zapsMap = zapsQuery.data ?? new Map(); |
| 65 | const votesMap = votesQuery.data ?? new Map(); |
| 66 | const repliesMap = repliesQuery.data ?? new Map(); |
| 67 | |
| 68 | return posts.map((event) => { |
| 69 | const zapData = zapsMap.get(event.id) ?? { zapCount: 0, totalSats: 0, zaps: [] }; |
| 70 | const voteData = votesMap.get(event.id) ?? { upvotes: 0, downvotes: 0, score: 0, reactions: [] }; |
| 71 | const replyCount = repliesMap.get(event.id) ?? 0; |
| 72 | |
| 73 | const metrics: RecentPostMetrics = { |
| 74 | totalSats: zapData.totalSats, |
| 75 | zapCount: zapData.zapCount, |
| 76 | upvotes: voteData.upvotes, |
| 77 | downvotes: voteData.downvotes, |
| 78 | score: voteData.score, |
| 79 | replyCount, |
| 80 | createdAt: event.created_at, |
| 81 | }; |
| 82 | |
| 83 | return { event, metrics }; |
| 84 | }); |
| 85 | }, [posts, zapsQuery.data, votesQuery.data, repliesQuery.data]); |
| 86 | |
| 87 | // Check if metrics are still loading |
| 88 | const metricsLoading = postIds.length > 0 && |
| 89 | (zapsQuery.isLoading || votesQuery.isLoading || repliesQuery.isLoading); |
| 90 | |
| 91 | return { |
| 92 | data: recentPosts, |
no test coverage detected