Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
112 lines
4.2 KiB
TypeScript
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],
|
|
},
|
|
}
|
|
: {}),
|
|
})
|
|
}
|