import { useQuery } from '@tanstack/react-query'; import { SKATE_SHOP_KIND, SKATE_SPOT_KIND, parseSkateShop, parseSkateSpot, type SkateShop } from '@/lib/types'; import { useSkateRelays } from '@/hooks/useSkateRelays'; export function useShops(limit = 100) { const { querySkateContent, getQueryKeySuffix } = useSkateRelays(); return useQuery({ queryKey: ['skate-shops', limit, getQueryKeySuffix()], queryFn: async () => { const signal = AbortSignal.timeout(10000); console.log('[useShops] Querying for shops'); // Query new shop kind (30017) const newShops = await querySkateContent( [ { kinds: [SKATE_SHOP_KIND], '#t': ['skateshop'], limit, }, ], { signal } ); console.log(`[useShops] Received ${newShops.length} new shops (kind 30017)`); // Query old shops (kind 30818 with 'shop' type) for backward compatibility const oldShops = await querySkateContent( [ { kinds: [SKATE_SPOT_KIND], '#t': ['shop'], limit, }, ], { signal } ); console.log(`[useShops] Received ${oldShops.length} old shops (kind 30818)`); const allEvents = [...newShops, ...oldShops]; const shops: SkateShop[] = []; for (const event of allEvents) { // Try parsing as new shop (kind 30017) let shop = parseSkateShop(event); // If that fails, try parsing as old spot and convert to shop if (!shop && event.kind === SKATE_SPOT_KIND) { const spot = parseSkateSpot(event); if (spot && spot.types.includes('shop')) { // Convert old spot-type shop to new shop format shop = { id: spot.id, pubkey: spot.pubkey, identifier: spot.identifier, name: spot.title, description: spot.description, geohash: spot.geohash, location: spot.location, images: spot.images, phone: undefined, email: undefined, website: undefined, instagram: undefined, hours: undefined, createdAt: spot.createdAt, event: spot.event, }; } } if (shop) { shops.push(shop); } else { console.warn('[useShops] Failed to parse event:', event); } } console.log('[useShops] Parsed shops:', shops.length); // Sort by created_at descending return shops.sort((a, b) => b.createdAt - a.createdAt); }, staleTime: 30000, gcTime: 300000, refetchOnMount: 'always', }); } export function useShop(identifier: string, pubkey?: string) { const { querySkateContent, getQueryKeySuffix } = useSkateRelays(); return useQuery({ queryKey: ['skate-shop', identifier, pubkey, getQueryKeySuffix()], queryFn: async () => { const signal = AbortSignal.timeout(10000); console.log(`[useShop] Querying for shop: ${identifier}`); // Query new shop format (kind 30017) const newFilter: { kinds: number[]; '#d': string[]; authors?: string[]; limit: number; } = { kinds: [SKATE_SHOP_KIND], '#d': [identifier], limit: 1, }; if (pubkey) newFilter.authors = [pubkey]; const newShops = await querySkateContent([newFilter], { signal }); console.log(`[useShop] Received ${newShops.length} new shops`); // Query old shop format (kind 30818 with 'shop' type) for backward compatibility const oldFilter: { kinds: number[]; '#d': string[]; '#t': string[]; authors?: string[]; limit: number; } = { kinds: [SKATE_SPOT_KIND], '#d': [identifier], '#t': ['shop'], limit: 1, }; if (pubkey) oldFilter.authors = [pubkey]; const oldShops = await querySkateContent([oldFilter], { signal }); console.log(`[useShop] Received ${oldShops.length} old shops`); const allEvents = [...newShops, ...oldShops]; if (allEvents.length === 0) { console.warn(`[useShop] No events found for identifier: ${identifier}`); return null; } // If multiple events, take the most recent const mostRecent = allEvents.reduce((latest, current) => current.created_at > latest.created_at ? current : latest ); // Try parsing as new shop first let shop = parseSkateShop(mostRecent); // If that fails, try parsing as old spot and convert if (!shop && mostRecent.kind === SKATE_SPOT_KIND) { const spot = parseSkateSpot(mostRecent); if (spot && spot.types.includes('shop')) { shop = { id: spot.id, pubkey: spot.pubkey, identifier: spot.identifier, name: spot.title, description: spot.description, geohash: spot.geohash, location: spot.location, images: spot.images, phone: undefined, email: undefined, website: undefined, instagram: undefined, hours: undefined, createdAt: spot.createdAt, event: spot.event, }; } } return shop; }, enabled: !!identifier, staleTime: 30000, refetchOnMount: 'always', }); } export function useUserShops(pubkey: string) { const { querySkateContent, getQueryKeySuffix } = useSkateRelays(); return useQuery({ queryKey: ['user-skate-shops', pubkey, getQueryKeySuffix()], queryFn: async () => { const signal = AbortSignal.timeout(10000); const events = await querySkateContent( [ { kinds: [SKATE_SHOP_KIND], authors: [pubkey], '#t': ['skateshop'], limit: 50, }, ], { signal } ); const shops: SkateShop[] = []; for (const event of events) { const shop = parseSkateShop(event); if (shop) shops.push(shop); } return shops.sort((a, b) => b.createdAt - a.createdAt); }, enabled: !!pubkey, staleTime: 30000, refetchOnMount: 'always', }); }