'use client' import { useInfiniteQuery, useQuery } from '@tanstack/react-query' import { eventPublicDetailStaleTime } from '@/queries/consumer/eventDetailCache' import { consumerKeys } from '@/queries/consumerKeys' import { unwrapService } from '@/queries/unwrapService' import { fetchConsumerEventDetail, fetchEventOwnerInsights, type ConsumerEventDetailData } from '@/services/consumerEventDetail' import { fetchEventFaqs, fetchEventMedia, type EventFaq, type EventMedia } from '@/services/eventDetail' import { fetchPublicOrganizer, type PublicOrganizerSummary } from '@/services/publicOrganizer' import { EVENT_REVIEWS_PAGE_SIZE, LIST_EVENT_REVIEWS_PAGE, type EventReview } from '@/services/reviews' interface InitialDataOptions { initialData?: T /** When false, the query stays idle (e.g. owner-insights for non-hosts). Default true. */ enabled?: boolean } export const useConsumerEventDetailQuery = (eventId: string, viewerId: string, options?: InitialDataOptions) => { const hasSeed = options?.initialData !== undefined return useQuery({ queryKey: consumerKeys.eventDetail(eventId, viewerId), queryFn: () => fetchConsumerEventDetail(eventId), enabled: Boolean(eventId) && (options?.enabled ?? true), staleTime: eventPublicDetailStaleTime, ...(hasSeed ? { initialData: options?.initialData } : {}), }) } export const useEventMediaQuery = (eventId: string, options?: InitialDataOptions) => { const hasSeed = options?.initialData !== undefined return useQuery({ queryKey: consumerKeys.eventMedia(eventId), queryFn: () => fetchEventMedia(eventId), enabled: Boolean(eventId) && (options?.enabled ?? true), staleTime: eventPublicDetailStaleTime, ...(hasSeed ? { initialData: options?.initialData } : {}), }) } export const useEventFaqsQuery = (eventId: string, options?: InitialDataOptions) => { const hasSeed = options?.initialData !== undefined return useQuery({ queryKey: consumerKeys.eventFaqs(eventId), queryFn: () => fetchEventFaqs(eventId), enabled: Boolean(eventId) && (options?.enabled ?? true), staleTime: eventPublicDetailStaleTime, ...(hasSeed ? { initialData: options?.initialData } : {}), }) } export const usePublicOrganizerQuery = (organizerId: string, options?: InitialDataOptions) => { const hasSeed = options?.initialData !== undefined return useQuery({ queryKey: consumerKeys.publicOrganizer(organizerId), queryFn: () => fetchPublicOrganizer(organizerId), enabled: Boolean(organizerId) && (options?.enabled ?? true), staleTime: eventPublicDetailStaleTime, ...(hasSeed ? { initialData: options?.initialData } : {}), }) } export const useEventOwnerInsightsQuery = (eventId: string, enabled: boolean) => useQuery({ queryKey: consumerKeys.eventOwnerInsights(eventId), queryFn: () => fetchEventOwnerInsights(eventId), enabled: Boolean(eventId) && enabled, staleTime: eventPublicDetailStaleTime, }) export interface EventReviewsPageSeed { items: EventReview[] totalItemsCount: number } /** * Infinite reviews list for the consumer event detail section. * SSR/bootstrap can seed page 1 so hydration does not refetch while fresh. */ export const useEventReviewsInfiniteQuery = (eventId: string, seed?: EventReviewsPageSeed) => { const hasSeed = seed !== undefined return useInfiniteQuery({ queryKey: consumerKeys.eventReviews(eventId), queryFn: async ({ pageParam }) => unwrapService(await LIST_EVENT_REVIEWS_PAGE(eventId, pageParam, EVENT_REVIEWS_PAGE_SIZE, { errorMode: 'parent' })), initialPageParam: 1, getNextPageParam: (lastPage) => (lastPage.page < lastPage.totalPages ? lastPage.page + 1 : undefined), enabled: Boolean(eventId), staleTime: eventPublicDetailStaleTime, ...(hasSeed && seed ? { initialData: { pages: [ { items: seed.items, page: 1, totalItemsCount: seed.totalItemsCount, totalPages: Math.max(1, Math.ceil(seed.totalItemsCount / EVENT_REVIEWS_PAGE_SIZE) || 1), }, ], pageParams: [1], }, } : {}), }) }