import { useQuery } from '@tanstack/react-query'; import { useSkateRelays } from '@/hooks/useSkateRelays'; import { SKATE_MUSICIAN_KIND, CALENDAR_EVENT_KIND, parseSkateEvent, type SkateEvent, } from '@/lib/types'; /** * Gigs for a musician — calendar events (kind 31923) carrying an `a` tag that * points back at the musician's Lab coordinate (`35011:pubkey:d`). * * This powers the "Upcoming gigs" list on a musician's Lab detail page and * closes the Music ↔ Events loop: an event promoter tags a musician when * creating an event, and the gig automatically surfaces on the act's profile. */ export function useGigs(musicianPubkey?: string, musicianIdentifier?: string, limit = 30) { const { querySkateContent, getQueryKeySuffix } = useSkateRelays(); const musicianCoord = musicianPubkey && musicianIdentifier ? `${SKATE_MUSICIAN_KIND}:${musicianPubkey}:${musicianIdentifier}` : ''; return useQuery({ queryKey: ['gigs', musicianCoord, getQueryKeySuffix()], enabled: !!musicianCoord, staleTime: 60 * 1000, gcTime: 30 * 60 * 1000, queryFn: async () => { const signal = AbortSignal.timeout(10000); const events = await querySkateContent( [{ kinds: [CALENDAR_EVENT_KIND], '#a': [musicianCoord], limit }], { signal }, ); const parsed: SkateEvent[] = []; for (const ev of events) { const skateEvent = parseSkateEvent(ev); // Guard against loose relay matches — the `a` tag must be present. const hasRef = ev.tags.some(([t, v]) => t === 'a' && v === musicianCoord); if (skateEvent && hasRef) parsed.push(skateEvent); } // Soonest upcoming first, then past. const now = Math.floor(Date.now() / 1000); return parsed.sort((a, b) => { const aFuture = a.start >= now ? 0 : 1; const bFuture = b.start >= now ? 0 : 1; if (aFuture !== bFuture) return aFuture - bFuture; return a.start - b.start; }); }, }); }