useBroadcasts.ts 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. 'use client';
  2. import { useQuery, useInfiniteQuery, UseQueryResult, UseInfiniteQueryResult } from '@tanstack/react-query';
  3. import {
  4. fetchBroadcastList,
  5. fetchPopularBroadcasts,
  6. fetchLiveBroadcasts,
  7. fetchBroadcastDetail,
  8. fetchBroadcastsByCategory,
  9. searchBroadcasts
  10. } from '@/lib/api/broadcast';
  11. import { BroadcastInfo, BroadcastListResponse } from '@/types/broadcast';
  12. import { ResultDto } from '@/dtos/response/common';
  13. // 쿼리 키 상수 정의
  14. export const broadcastKeys = {
  15. all: ['broadcasts'] as const,
  16. lists: () => [...broadcastKeys.all, 'list'] as const,
  17. list: (filters: string) => [...broadcastKeys.lists(), filters] as const,
  18. details: () => [...broadcastKeys.all, 'detail'] as const,
  19. detail: (id: string) => [...broadcastKeys.details(), id] as const,
  20. popular: (limit: number) => [...broadcastKeys.all, 'popular', limit] as const,
  21. live: (page: number, limit: number) => [...broadcastKeys.all, 'live', page, limit] as const,
  22. category: (category: string, page: number, limit: number) => [...broadcastKeys.all, 'category', category, page, limit] as const,
  23. search: (query: string, page: number, limit: number) => [...broadcastKeys.all, 'search', query, page, limit] as const,
  24. };
  25. // 인기 방송 목록 조회 훅
  26. export function usePopularBroadcasts(limit: number = 5): UseQueryResult<BroadcastInfo[], Error> {
  27. return useQuery({
  28. queryKey: broadcastKeys.popular(limit),
  29. queryFn: async () => {
  30. const result = await fetchPopularBroadcasts(limit);
  31. if (!result.ok) {
  32. throw new Error(result.message || '인기 방송 목록을 가져오는데 실패했습니다.');
  33. }
  34. return result.data || [];
  35. },
  36. staleTime: 2 * 60 * 1000, // 2분
  37. refetchInterval: 30 * 1000, // 30초마다 갱신
  38. });
  39. }
  40. // 실시간 방송 목록 조회 훅 (무한스크롤 지원)
  41. export function useLiveBroadcasts(limit: number = 20): UseInfiniteQueryResult<BroadcastListResponse, Error> {
  42. return useInfiniteQuery({
  43. queryKey: broadcastKeys.live(1, limit),
  44. queryFn: async ({ pageParam = 1 }) => {
  45. const result = await fetchLiveBroadcasts(pageParam as number, limit);
  46. if (!result.ok) {
  47. throw new Error(result.message || '실시간 방송 목록을 가져오는데 실패했습니다.');
  48. }
  49. return result.data || { broadcasts: [], totalCount: 0, hasMore: false };
  50. },
  51. getNextPageParam: (lastPage, allPages) => {
  52. return lastPage.hasMore ? allPages.length + 1 : undefined;
  53. },
  54. initialPageParam: 1,
  55. staleTime: 1 * 60 * 1000, // 1분
  56. refetchInterval: 15 * 1000, // 15초마다 갱신
  57. });
  58. }
  59. // 방송 상세 정보 조회 훅
  60. export function useBroadcastDetail(broadcastId: string): UseQueryResult<BroadcastInfo, Error> {
  61. return useQuery({
  62. queryKey: broadcastKeys.detail(broadcastId),
  63. queryFn: async () => {
  64. const result = await fetchBroadcastDetail(broadcastId);
  65. if (!result.ok) {
  66. throw new Error(result.message || '방송 정보를 가져오는데 실패했습니다.');
  67. }
  68. return result.data;
  69. },
  70. enabled: !!broadcastId,
  71. staleTime: 30 * 1000, // 30초
  72. refetchInterval: 10 * 1000, // 10초마다 갱신 (실시간 정보)
  73. });
  74. }
  75. // 카테고리별 방송 목록 조회 훅
  76. export function useBroadcastsByCategory(
  77. category: string,
  78. page: number = 1,
  79. limit: number = 20
  80. ): UseQueryResult<BroadcastListResponse, Error> {
  81. return useQuery({
  82. queryKey: broadcastKeys.category(category, page, limit),
  83. queryFn: async () => {
  84. const result = await fetchBroadcastsByCategory(category, page, limit);
  85. if (!result.ok) {
  86. throw new Error(result.message || '카테고리별 방송 목록을 가져오는데 실패했습니다.');
  87. }
  88. return result.data || { broadcasts: [], totalCount: 0, hasMore: false };
  89. },
  90. enabled: !!category,
  91. staleTime: 2 * 60 * 1000, // 2분
  92. });
  93. }
  94. // 방송 검색 훅
  95. export function useSearchBroadcasts(
  96. query: string,
  97. page: number = 1,
  98. limit: number = 20
  99. ): UseQueryResult<BroadcastListResponse, Error> {
  100. return useQuery({
  101. queryKey: broadcastKeys.search(query, page, limit),
  102. queryFn: async () => {
  103. const result = await searchBroadcasts(query, page, limit);
  104. if (!result.ok) {
  105. throw new Error(result.message || '방송 검색에 실패했습니다.');
  106. }
  107. return result.data || { broadcasts: [], totalCount: 0, hasMore: false };
  108. },
  109. enabled: !!query && query.length > 0,
  110. staleTime: 5 * 60 * 1000, // 5분
  111. });
  112. }
  113. // 방송 목록 조회 훅 (일반적인 목록)
  114. export function useBroadcastList(page: number = 1, limit: number = 20): UseQueryResult<BroadcastListResponse, Error> {
  115. return useQuery({
  116. queryKey: broadcastKeys.list(`page-${page}-limit-${limit}`),
  117. queryFn: async () => {
  118. const result = await fetchBroadcastList(page, limit);
  119. if (!result.ok) {
  120. throw new Error(result.message || '방송 목록을 가져오는데 실패했습니다.');
  121. }
  122. return result.data || { broadcasts: [], totalCount: 0, hasMore: false };
  123. },
  124. staleTime: 2 * 60 * 1000, // 2분
  125. });
  126. }