Wire manage-events/new with host picker and create flow against the new admin create API, including entry points from the events list and user detail.
227 lines
8.4 KiB
TypeScript
227 lines
8.4 KiB
TypeScript
import type {
|
|
CreateEventDto,
|
|
CreateEventFaqDto,
|
|
CreateEventMediaDto,
|
|
EventCategoryResponseDto,
|
|
EventResponseDto,
|
|
AdminCreateEventDto,
|
|
} from '@/api/generated/models'
|
|
import { getAdminEventCategories } from '@/api/generated/admin-event-categories/admin-event-categories'
|
|
import { getAdminEvents } from '@/api/generated/admin-events/admin-events'
|
|
import { getEventExtras } from '@/api/generated/event-extras/event-extras'
|
|
import { unwrapApiPayload } from '@/helpers/listResponse'
|
|
import axiosInstance from '@/config/axios'
|
|
import { API_ROUTES } from '@/services/config'
|
|
|
|
export type EventCategory = EventCategoryResponseDto
|
|
export type CreateEventPayload = CreateEventDto
|
|
export type AdminCreateEventPayload = AdminCreateEventDto
|
|
export type CreatedEvent = EventResponseDto
|
|
export type CreateEventMediaPayload = CreateEventMediaDto
|
|
export type CreateEventFaqPayload = CreateEventFaqDto
|
|
|
|
const adminEventsApi = getAdminEvents()
|
|
const adminEventCategoriesApi = getAdminEventCategories()
|
|
const eventExtrasApi = getEventExtras()
|
|
|
|
/** Full category tree for admin edit forms — admin list, not public discovery. */
|
|
export async function fetchEventCategories(): Promise<EventCategory[]> {
|
|
const items: EventCategory[] = []
|
|
let page = 1
|
|
let totalPages = 1
|
|
|
|
while (page <= totalPages) {
|
|
const response = await adminEventCategoriesApi.adminEventCategoriesControllerList({
|
|
page,
|
|
pageSize: 100,
|
|
sort: 'sortOrder',
|
|
})
|
|
const payload = unwrapApiPayload<{ items?: EventCategory[]; response?: { totalPages?: number } }>(response.data)
|
|
const batch = Array.isArray(payload.items) ? payload.items : Array.isArray(payload) ? (payload as EventCategory[]) : []
|
|
|
|
items.push(...batch)
|
|
totalPages = Number(payload.response?.totalPages ?? 1)
|
|
page += 1
|
|
}
|
|
|
|
return items
|
|
}
|
|
|
|
/**
|
|
* Create a pre-approved draft for a verified host. Host still publishes;
|
|
* backend notifies the host via `event_created_by_admin`.
|
|
*/
|
|
export async function createEventAsAdmin(payload: AdminCreateEventPayload): Promise<CreatedEvent> {
|
|
const response = await adminEventsApi.adminEventsControllerCreate(payload)
|
|
|
|
return unwrapApiPayload<CreatedEvent>(response.data)
|
|
}
|
|
|
|
/** Admin approval is one half of the two-key publication workflow. */
|
|
export async function approveEventAsAdmin(eventId: string): Promise<CreatedEvent> {
|
|
const response = await adminEventsApi.adminEventsControllerApprove(eventId)
|
|
|
|
return unwrapApiPayload<CreatedEvent>(response.data)
|
|
}
|
|
|
|
/** Force-publish bypass: skips the request/approve flow entirely. */
|
|
export async function publishEventAsAdmin(eventId: string): Promise<CreatedEvent> {
|
|
const response = await adminEventsApi.adminEventsControllerPublish(eventId)
|
|
|
|
return unwrapApiPayload<CreatedEvent>(response.data)
|
|
}
|
|
|
|
export async function rejectEventAsAdmin(eventId: string, rejectionReason: string): Promise<CreatedEvent> {
|
|
const response = await adminEventsApi.adminEventsControllerReject(eventId, { rejectionReason })
|
|
|
|
return unwrapApiPayload<CreatedEvent>(response.data)
|
|
}
|
|
|
|
export async function cancelEventAsAdmin(eventId: string): Promise<CreatedEvent> {
|
|
const response = await adminEventsApi.adminEventsControllerCancel(eventId)
|
|
|
|
return unwrapApiPayload<CreatedEvent>(response.data)
|
|
}
|
|
|
|
export async function completeEventAsAdmin(eventId: string): Promise<CreatedEvent> {
|
|
const response = await adminEventsApi.adminEventsControllerComplete(eventId)
|
|
|
|
return unwrapApiPayload<CreatedEvent>(response.data)
|
|
}
|
|
|
|
export async function deleteEventAsAdmin(eventId: string): Promise<CreatedEvent> {
|
|
const response = await axiosInstance.delete(API_ROUTES.EVENTS.ADMIN_DELETE(eventId))
|
|
|
|
return unwrapApiPayload<CreatedEvent>(response.data)
|
|
}
|
|
|
|
export async function updateEventReservedCapacity(eventId: string, reservedCapacity: number): Promise<CreatedEvent> {
|
|
const response = await axiosInstance.patch(API_ROUTES.EVENTS.ADMIN_RESERVED_CAPACITY(eventId), { reservedCapacity })
|
|
|
|
return unwrapApiPayload<CreatedEvent>(response.data)
|
|
}
|
|
|
|
/** Admin can edit any organizer's event (same field locks as host). */
|
|
export async function updateEventAsAdmin(eventId: string, payload: Partial<CreateEventPayload>): Promise<CreatedEvent> {
|
|
const response = await axiosInstance.patch(API_ROUTES.EVENTS.ADMIN_DETAIL(eventId), payload)
|
|
|
|
return unwrapApiPayload<CreatedEvent>(response.data)
|
|
}
|
|
|
|
/** Admin-only: set (or, with null, clear) this event's platform commission override. */
|
|
export async function updateEventCommissionAsAdmin(eventId: string, commissionPercent: number | null): Promise<CreatedEvent> {
|
|
const response = await axiosInstance.patch(API_ROUTES.EVENTS.ADMIN_COMMISSION(eventId), { commissionPercent })
|
|
|
|
return unwrapApiPayload<CreatedEvent>(response.data)
|
|
}
|
|
|
|
/**
|
|
* Full event for edit forms. Backend authorizes admin (and owner);
|
|
* admin panel uses this for the edit screen.
|
|
*/
|
|
export async function fetchEventForEdit(eventId: string): Promise<CreatedEvent> {
|
|
const response = await axiosInstance.get(API_ROUTES.EVENTS.FOR_EDIT(eventId))
|
|
|
|
return unwrapApiPayload<CreatedEvent>(response.data)
|
|
}
|
|
|
|
/** Admin detail including bookmarkCount + organizer contact. */
|
|
export async function fetchAdminEventDetail(eventId: string): Promise<CreatedEvent> {
|
|
const response = await axiosInstance.get(API_ROUTES.EVENTS.ADMIN_DETAIL(eventId))
|
|
|
|
return unwrapApiPayload<CreatedEvent>(response.data)
|
|
}
|
|
|
|
/**
|
|
* Media/FAQ mutations share `/events/:id/...` extras endpoints; backend
|
|
* authorizes event owner or admin. No separate admin CRUD routes exist.
|
|
*/
|
|
export async function createEventMedia(eventId: string, payload: CreateEventMediaPayload): Promise<void> {
|
|
await eventExtrasApi.eventMediaControllerCreate(eventId, payload)
|
|
}
|
|
|
|
export async function updateEventMedia(eventId: string, mediaId: string, payload: Partial<CreateEventMediaPayload>): Promise<void> {
|
|
await eventExtrasApi.eventMediaControllerUpdate(eventId, mediaId, payload)
|
|
}
|
|
|
|
export async function deleteEventMedia(eventId: string, mediaId: string): Promise<void> {
|
|
await eventExtrasApi.eventMediaControllerRemove(eventId, mediaId)
|
|
}
|
|
|
|
export async function createEventFaq(eventId: string, payload: CreateEventFaqPayload): Promise<void> {
|
|
await eventExtrasApi.eventFaqsControllerCreate(eventId, payload)
|
|
}
|
|
|
|
export async function updateEventFaq(eventId: string, faqId: string, payload: Partial<CreateEventFaqPayload>): Promise<void> {
|
|
await eventExtrasApi.eventFaqsControllerUpdate(eventId, faqId, payload)
|
|
}
|
|
|
|
export async function deleteEventFaq(eventId: string, faqId: string): Promise<void> {
|
|
await eventExtrasApi.eventFaqsControllerRemove(eventId, faqId)
|
|
}
|
|
|
|
export interface EventRevisionPayload {
|
|
title?: string
|
|
slug?: string
|
|
shortDescription?: string
|
|
description?: string
|
|
categoryId?: number
|
|
startsAt?: string
|
|
endsAt?: string
|
|
provinceId?: number
|
|
cityId?: number
|
|
address?: string
|
|
lat?: number
|
|
lng?: number
|
|
isFree?: boolean
|
|
price?: number
|
|
capacity?: number
|
|
genderRestriction?: string
|
|
ageRestriction?: string
|
|
cancellationFeePercent?: number
|
|
cancellationFeePercent12To24Hours?: number
|
|
cancellationFeePercentMoreThan24Hours?: number
|
|
settings?: CreateEventPayload['settings']
|
|
media: CreateEventMediaPayload[]
|
|
faqs?: CreateEventFaqPayload[]
|
|
}
|
|
|
|
export interface EventRevision {
|
|
id: string
|
|
eventId: string
|
|
status: string
|
|
payload: EventRevisionPayload & Record<string, unknown>
|
|
createdBy: string
|
|
reviewedBy: string | null
|
|
rejectionReason: string | null
|
|
submittedAt: string
|
|
decidedAt: string | null
|
|
}
|
|
|
|
export async function fetchAdminPendingEventRevision(eventId: string): Promise<EventRevision | null> {
|
|
try {
|
|
const response = await axiosInstance.get(API_ROUTES.EVENTS.ADMIN_REVISION_PENDING(eventId))
|
|
|
|
return unwrapApiPayload<EventRevision>(response.data)
|
|
} catch (error) {
|
|
const status = (error as { response?: { status?: number } })?.response?.status
|
|
|
|
if (status === 404) return null
|
|
throw error
|
|
}
|
|
}
|
|
|
|
export async function approveEventRevisionAsAdmin(eventId: string, revisionId: string): Promise<CreatedEvent> {
|
|
const response = await axiosInstance.patch(API_ROUTES.EVENTS.ADMIN_REVISION_APPROVE(eventId, revisionId))
|
|
|
|
return unwrapApiPayload<CreatedEvent>(response.data)
|
|
}
|
|
|
|
export async function rejectEventRevisionAsAdmin(eventId: string, revisionId: string, rejectionReason: string): Promise<EventRevision> {
|
|
const response = await axiosInstance.patch(API_ROUTES.EVENTS.ADMIN_REVISION_REJECT(eventId, revisionId), {
|
|
rejectionReason,
|
|
})
|
|
|
|
return unwrapApiPayload<EventRevision>(response.data)
|
|
}
|