SkateSpots/src/hooks/useCrewFeed.ts
shakespeare.diy f10aa7971c Step 3: Crews — map-anchored collective feature (kind 35006)
- New SkateCrew kind 35006 + type/parser + useCrews/useCrew hooks
- /crews directory, /create-crew, /edit-crew, /crew/:pubkey/:identifier pages
- Reuses the collective engine: NIP-32 membership attestation (confirmed/pending),
  CollectiveMembers + ConfirmMembershipCard, ClinkPayButton, SpotPicker
- Activity v1: home spots + crew member feed (no events, per plan)
- Map: teal/cyan Crews layer at home turf with crew markers + popups;
  wired through SpotMap props, layer toggles (mobile popover + filters sheet),
  and mobileLayerCount badge
- Nav: Crews added to navItemKeys (desktop header, mobile bottom bar, sidebar)
  with en/es i18n keys
- NIP.md: documents kind 35006, tag taxonomy, and shared membership mechanism

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-24 13:59:50 +07:00

39 lines
1.2 KiB
TypeScript

import { useQuery } from '@tanstack/react-query';
import { useSkateRelays } from '@/hooks/useSkateRelays';
import type { NostrEvent } from '@nostrify/nostrify';
/**
* Recent kind-1 notes from a crew's members — the "crew feed".
* Keeps the crew page alive without any new event kinds.
*/
export function useCrewFeed(memberPubkeys: string[], limit = 30) {
const { querySkateContent, getQueryKeySuffix } = useSkateRelays();
return useQuery({
queryKey: ['crew-feed', memberPubkeys.slice().sort().join(','), getQueryKeySuffix()],
queryFn: async (): Promise<NostrEvent[]> => {
if (memberPubkeys.length === 0) return [];
const signal = AbortSignal.timeout(8000);
const events = await querySkateContent(
[
{
kinds: [1],
authors: memberPubkeys,
limit,
},
],
{ signal }
);
// Exclude replies — a crew feed reads better as top-level posts.
const topLevel = events.filter(
(e) => !e.tags.some(([name]) => name === 'e')
);
return topLevel.sort((a, b) => b.created_at - a.created_at).slice(0, limit);
},
enabled: memberPubkeys.length > 0,
staleTime: 60 * 1000,
});
}