admin/queries/consumer/useEventDetailQueries.ts
alisaza e1eaf5eff5 feat: initial ghabilee-admin backoffice app
Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js
app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
2026-09-05 13:12:59 +03:30

112 lines
4.2 KiB
TypeScript

'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<T> {
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<ConsumerEventDetailData>) => {
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<EventMedia[]>) => {
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<EventFaq[]>) => {
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<PublicOrganizerSummary>) => {
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],
},
}
: {}),
})
}