Add useFollowerPictureFeed hook and integrate it into Index page for user-specific picture feed

This commit is contained in:
2025-11-27 21:30:42 +01:00
parent f5d6e1fce6
commit 3f66182484
2 changed files with 69 additions and 1 deletions

View File

@@ -0,0 +1,60 @@
import { useNostr } from '@nostrify/react';
import { useInfiniteQuery } from '@tanstack/react-query';
import type { NostrEvent } from '@nostrify/nostrify';
import { useCurrentUser } from './useCurrentUser';
/**
* Hook for fetching kind 20 (NIP-68) picture events from followed users with infinite scroll
* Uses NIP-02 follow list to filter events
*/
export function useFollowerPictureFeed() {
const { nostr } = useNostr();
const { user } = useCurrentUser();
return useInfiniteQuery({
queryKey: ['follower-picture-feed', user?.pubkey],
queryFn: async ({ pageParam, signal }) => {
if (!user?.pubkey) {
return [];
}
// First, fetch the user's follow list (kind 3, NIP-02)
const followListEvents = await nostr.query(
[{ kinds: [3], authors: [user.pubkey], limit: 1 }],
{ signal: AbortSignal.any([signal, AbortSignal.timeout(1500)]) }
);
if (followListEvents.length === 0) {
return [];
}
// Extract followed pubkeys from p tags
const followedPubkeys = followListEvents[0].tags
.filter(([tag]) => tag === 'p')
.map(([, pubkey]) => pubkey)
.filter(Boolean);
if (followedPubkeys.length === 0) {
return [];
}
// Fetch pictures from followed users
const filter = pageParam
? { kinds: [20], authors: followedPubkeys, limit: 20, until: pageParam as number }
: { kinds: [20], authors: followedPubkeys, limit: 20 };
const events = await nostr.query([filter], {
signal: AbortSignal.any([signal, AbortSignal.timeout(1500)])
});
return events as NostrEvent[];
},
getNextPageParam: (lastPage) => {
if (lastPage.length === 0) return undefined;
// Subtract 1 since 'until' is inclusive
return lastPage[lastPage.length - 1].created_at - 1;
},
initialPageParam: undefined as number | undefined,
enabled: !!user?.pubkey,
});
}

View File

@@ -1,6 +1,7 @@
import { useSeoMeta } from '@unhead/react';
import { Layout } from '@/components/Layout';
import { usePictureFeed } from '@/hooks/usePictureFeed';
import { useFollowerPictureFeed } from '@/hooks/useFollowerPictureFeed';
import { PictureCard } from '@/components/feed/PictureCard';
import { MinimalPictureCard } from '@/components/feed/MinimalPictureCard';
import { useInView } from 'react-intersection-observer';
@@ -8,6 +9,7 @@ import { useEffect, useMemo } from 'react';
import { Skeleton } from '@/components/ui/skeleton';
import { Card, CardContent } from '@/components/ui/card';
import { useAppContext } from '@/hooks/useAppContext';
import { useCurrentUser } from '@/hooks/useCurrentUser';
const Index = () => {
useSeoMeta({
@@ -16,7 +18,13 @@ const Index = () => {
});
const { config } = useAppContext();
const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading } = usePictureFeed();
const { user } = useCurrentUser();
// Use follower feed for logged-in users, global feed for logged-out users
const globalFeed = usePictureFeed();
const followerFeed = useFollowerPictureFeed();
const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading } = user ? followerFeed : globalFeed;
const { ref, inView } = useInView();
useEffect(() => {