admin/services/eventManagement.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

106 lines
3.7 KiB
TypeScript

import type {
EventAttendeeFilter,
EventAttendeeResponseDto,
MyEventsControllerAttendees200,
OwnerEventInsightsResponseDto,
} from '@/api/generated/models'
import { getAdminBookings } from '@/api/generated/admin-bookings/admin-bookings'
import { getAdminEvents } from '@/api/generated/admin-events/admin-events'
import { getBookings } from '@/api/generated/bookings/bookings'
import { getMyEvents } from '@/api/generated/my-events/my-events'
import { unwrapApiPayload } from '@/helpers/listResponse'
import axiosInstance from '@/config/axios'
import type { CreatedEvent } from '@/services/events'
import type { EventFaq, EventMedia } from '@/services/eventDetail'
export type EventAttendee = Omit<EventAttendeeResponseDto, 'firstName' | 'lastName' | 'confirmedAt' | 'checkedInAt' | 'noShowAt'> & {
firstName: string | null
lastName: string | null
confirmedAt: string | null
checkedInAt: string | null
noShowAt: string | null
}
/** Extended until OpenAPI client is regenerated with traffic insights. */
export type EventManagementInsights = OwnerEventInsightsResponseDto & {
traffic?: {
instagram: { uniqueVisits: number; confirmedBookings: number }
telegram: { uniqueVisits: number; confirmedBookings: number }
}
}
export type AttendanceFilter = EventAttendeeFilter
export interface EventManagementBootstrap {
event: CreatedEvent
insights: EventManagementInsights
categoryName: string
cityName: string
provinceName: string
media: EventMedia[]
faqs: EventFaq[]
}
export interface EventAttendeePage {
items: EventAttendee[]
totalItemsCount: number
totalPages: number
}
const myEventsApi = getMyEvents()
const bookingsApi = getBookings()
const adminEventsApi = getAdminEvents()
const adminBookingsApi = getAdminBookings()
export async function fetchEventManagementInsights(eventId: string): Promise<EventManagementInsights> {
const response = await myEventsApi.myEventsControllerOwnerInsights(eventId)
return unwrapApiPayload<EventManagementInsights>(response.data)
}
export async function fetchEventManagementBootstrap(eventId: string): Promise<EventManagementBootstrap> {
const response = await axiosInstance.get(`events/${eventId}/management-bootstrap`)
return unwrapApiPayload<EventManagementBootstrap>(response.data)
}
/** Admin can view insights for any organizer's event (no ownership check). */
export async function fetchEventInsightsAsAdmin(eventId: string): Promise<EventManagementInsights> {
const response = await adminEventsApi.adminEventsControllerInsights(eventId)
return unwrapApiPayload<EventManagementInsights>(response.data)
}
export async function fetchEventAttendees(
eventId: string,
options: {
search?: string
attendance?: AttendanceFilter
page?: number
pageSize?: number
} = {}
): Promise<EventAttendeePage> {
const response = await myEventsApi.myEventsControllerAttendees(eventId, {
page: options.page ?? 1,
pageSize: options.pageSize ?? 20,
sort: '-createdAt',
search: options.search?.trim() || undefined,
attendance: options.attendance ?? 'all',
})
const payload = unwrapApiPayload<MyEventsControllerAttendees200>(response.data)
return {
items: Array.isArray(payload.items) ? (payload.items as EventAttendee[]) : [],
totalItemsCount: Number(payload.response?.totalItemsCount ?? 0),
totalPages: Number(payload.response?.totalPages ?? 0),
}
}
export async function checkInEventAttendee(bookingId: string): Promise<void> {
await bookingsApi.bookingsControllerCheckIn(bookingId)
}
/** Admin can check in a guest for any organizer's event (no ownership check). */
export async function checkInBookingAsAdmin(bookingId: string): Promise<void> {
await adminBookingsApi.adminBookingsControllerCheckIn(bookingId)
}