SkateSpots/src/hooks/useGigs.ts

55 lines
2 KiB
TypeScript

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;
});
},
});
}