Fix badges page showing infinite skeleton when logged out

The useBadgeFeed hook required a logged-in user before enabling the query,
causing the follows tab to show loading skeletons forever when logged out.
Now fetches the Team Soapbox follow pack (kind 39089) and uses its members
as the authors filter, giving logged-out users a curated badge feed.
This commit is contained in:
Alex Gleason
2026-03-27 13:15:44 -05:00
parent 488ce5750d
commit 17954e0504
2 changed files with 37 additions and 10 deletions
+35 -9
View File
@@ -1,10 +1,11 @@
import { useNostr } from '@nostrify/react';
import { useInfiniteQuery } from '@tanstack/react-query';
import { useInfiniteQuery, useQuery } from '@tanstack/react-query';
import type { NostrEvent } from '@nostrify/nostrify';
import { useCurrentUser } from './useCurrentUser';
import { useFollowList } from './useFollowActions';
import { BADGE_DEFINITION_KIND, BADGE_PROFILE_KIND } from '@/lib/badgeUtils';
import { TEAM_SOAPBOX_PACK } from '@/lib/helpContent';
const PAGE_SIZE = 20;
@@ -15,21 +16,46 @@ export function useBadgeFeed(tab: 'follows' = 'follows') {
const { data: followData } = useFollowList();
const followList = followData?.pubkeys;
// For follows tab, wait until follow list is loaded
const followsReady = tab !== 'follows' || (!!user && followList !== undefined);
// When logged out, fetch the Team Soapbox follow pack to use as the authors filter.
const { data: packPubkeys } = useQuery({
queryKey: ['team-soapbox-pack-pubkeys'],
queryFn: async ({ signal }) => {
const events = await nostr.query(
[{
kinds: [TEAM_SOAPBOX_PACK.kind],
authors: [TEAM_SOAPBOX_PACK.pubkey],
'#d': [TEAM_SOAPBOX_PACK.identifier],
limit: 1,
}],
{ signal: AbortSignal.any([signal, AbortSignal.timeout(8000)]) },
);
if (events.length === 0) return [];
return events[0].tags.filter(([n]) => n === 'p').map(([, pk]) => pk);
},
enabled: !user,
staleTime: 10 * 60_000,
});
// Stable key segment for the follow list — only changes when the list content changes
const followKey = followList ? [...followList].sort().join(',') : '';
// When logged in, wait for the follow list. When logged out, wait for the pack pubkeys.
const followsReady = tab !== 'follows' || (user ? followList !== undefined : packPubkeys !== undefined);
// Stable key segment — only changes when the list content changes
const authorsList = user ? followList : packPubkeys;
const authorsKey = authorsList ? [...authorsList].sort().join(',') : '';
return useInfiniteQuery({
queryKey: ['badge-feed', tab, user?.pubkey ?? '', followKey],
queryKey: ['badge-feed', tab, user?.pubkey ?? '', authorsKey],
queryFn: async ({ pageParam, signal }) => {
const baseUntil = pageParam as number | undefined;
// For follows tab, build the authors list
// Build the authors list from follows (logged in) or pack members (logged out)
let authors: string[] | undefined;
if (tab === 'follows' && user && followList) {
authors = followList.length > 0 ? [...followList, user.pubkey] : [user.pubkey];
if (tab === 'follows') {
if (user && followList) {
authors = followList.length > 0 ? [...followList, user.pubkey] : [user.pubkey];
} else if (!user && packPubkeys && packPubkeys.length > 0) {
authors = packPubkeys;
}
}
const shared = {
+2 -1
View File
@@ -811,6 +811,7 @@ function EditBadgeForm({ badge, onClose }: { badge: ParsedBadge; onClose: () =>
// ═══════════════════════════════════════════════════════════════════════════════
function FollowsFeedTab({ onRefresh }: { onRefresh: () => Promise<void> }) {
const { user } = useCurrentUser();
const feedQuery = useBadgeFeed('follows');
const {
@@ -873,7 +874,7 @@ function FollowsFeedTab({ onRefresh }: { onRefresh: () => Promise<void> }) {
)}
</div>
) : (
<FeedEmptyState message="No badge activity from people you follow yet." />
<FeedEmptyState message={user ? "No badge activity from people you follow yet." : "No badge activity found yet."} />
)}
</PullToRefresh>
);