'use client'; import { useQuery, useInfiniteQuery, UseQueryResult, UseInfiniteQueryResult } from '@tanstack/react-query'; import { fetchBroadcastList, fetchPopularBroadcasts, fetchLiveBroadcasts, fetchBroadcastDetail, fetchBroadcastsByCategory, searchBroadcasts } from '@/lib/api/broadcast'; import { BroadcastInfo, BroadcastListResponse } from '@/types/broadcast'; import { ResultDto } from '@/dtos/response/common'; // 쿼리 키 상수 정의 export const broadcastKeys = { all: ['broadcasts'] as const, lists: () => [...broadcastKeys.all, 'list'] as const, list: (filters: string) => [...broadcastKeys.lists(), filters] as const, details: () => [...broadcastKeys.all, 'detail'] as const, detail: (id: string) => [...broadcastKeys.details(), id] as const, popular: (limit: number) => [...broadcastKeys.all, 'popular', limit] as const, live: (page: number, limit: number) => [...broadcastKeys.all, 'live', page, limit] as const, category: (category: string, page: number, limit: number) => [...broadcastKeys.all, 'category', category, page, limit] as const, search: (query: string, page: number, limit: number) => [...broadcastKeys.all, 'search', query, page, limit] as const, }; // 인기 방송 목록 조회 훅 export function usePopularBroadcasts(limit: number = 5): UseQueryResult { return useQuery({ queryKey: broadcastKeys.popular(limit), queryFn: async () => { const result = await fetchPopularBroadcasts(limit); if (!result.ok) { throw new Error(result.message || '인기 방송 목록을 가져오는데 실패했습니다.'); } return result.data || []; }, staleTime: 2 * 60 * 1000, // 2분 refetchInterval: 30 * 1000, // 30초마다 갱신 }); } // 실시간 방송 목록 조회 훅 (무한스크롤 지원) export function useLiveBroadcasts(limit: number = 20): UseInfiniteQueryResult { return useInfiniteQuery({ queryKey: broadcastKeys.live(1, limit), queryFn: async ({ pageParam = 1 }) => { const result = await fetchLiveBroadcasts(pageParam as number, limit); if (!result.ok) { throw new Error(result.message || '실시간 방송 목록을 가져오는데 실패했습니다.'); } return result.data || { broadcasts: [], totalCount: 0, hasMore: false }; }, getNextPageParam: (lastPage, allPages) => { return lastPage.hasMore ? allPages.length + 1 : undefined; }, initialPageParam: 1, staleTime: 1 * 60 * 1000, // 1분 refetchInterval: 15 * 1000, // 15초마다 갱신 }); } // 방송 상세 정보 조회 훅 export function useBroadcastDetail(broadcastId: string): UseQueryResult { return useQuery({ queryKey: broadcastKeys.detail(broadcastId), queryFn: async () => { const result = await fetchBroadcastDetail(broadcastId); if (!result.ok) { throw new Error(result.message || '방송 정보를 가져오는데 실패했습니다.'); } return result.data; }, enabled: !!broadcastId, staleTime: 30 * 1000, // 30초 refetchInterval: 10 * 1000, // 10초마다 갱신 (실시간 정보) }); } // 카테고리별 방송 목록 조회 훅 export function useBroadcastsByCategory( category: string, page: number = 1, limit: number = 20 ): UseQueryResult { return useQuery({ queryKey: broadcastKeys.category(category, page, limit), queryFn: async () => { const result = await fetchBroadcastsByCategory(category, page, limit); if (!result.ok) { throw new Error(result.message || '카테고리별 방송 목록을 가져오는데 실패했습니다.'); } return result.data || { broadcasts: [], totalCount: 0, hasMore: false }; }, enabled: !!category, staleTime: 2 * 60 * 1000, // 2분 }); } // 방송 검색 훅 export function useSearchBroadcasts( query: string, page: number = 1, limit: number = 20 ): UseQueryResult { return useQuery({ queryKey: broadcastKeys.search(query, page, limit), queryFn: async () => { const result = await searchBroadcasts(query, page, limit); if (!result.ok) { throw new Error(result.message || '방송 검색에 실패했습니다.'); } return result.data || { broadcasts: [], totalCount: 0, hasMore: false }; }, enabled: !!query && query.length > 0, staleTime: 5 * 60 * 1000, // 5분 }); } // 방송 목록 조회 훅 (일반적인 목록) export function useBroadcastList(page: number = 1, limit: number = 20): UseQueryResult { return useQuery({ queryKey: broadcastKeys.list(`page-${page}-limit-${limit}`), queryFn: async () => { const result = await fetchBroadcastList(page, limit); if (!result.ok) { throw new Error(result.message || '방송 목록을 가져오는데 실패했습니다.'); } return result.data || { broadcasts: [], totalCount: 0, hasMore: false }; }, staleTime: 2 * 60 * 1000, // 2분 }); }