- 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>
39 lines
1.2 KiB
TypeScript
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,
|
|
});
|
|
}
|