import { API_BASE_URL } from './client'; type ApiEnvelope = { success?: boolean; data?: T; error?: { message?: string } }; async function parse(res: Response): Promise<{ data?: T; error?: string }> { let body: unknown; try { body = await res.json(); } catch { return { error: res.statusText || 'Network error' }; } const api = body as ApiEnvelope; if (api.success === true && api.data !== undefined) return { data: api.data }; return { error: api.error?.message || 'Request failed' }; } function url(path: string) { const base = API_BASE_URL.endsWith('/') ? API_BASE_URL.slice(0, -1) : API_BASE_URL; const p = path.startsWith('/') ? path : `/${path}`; return `${base}${p}`; } export type PublicTicketCatalogItem = { _id: string; name: string; description: string; keyPoints: string[]; basePriceMinor: number; currency: string; maxPerOrder: number | null; requiresBillingState: boolean; registrationFormId: string | null; registrationFormFields: PublicFormField[] | null; }; export type PublicFormField = { label?: string; type?: string; required?: boolean; options?: string[]; allowOther?: boolean; otherLabel?: string; placeholder?: string; mapsTo?: string; }; export type TicketQuote = { ticketId: string; quantity: number; billingStateCode: string | null; baseMinor: number; taxMinor: number; totalMinor: number; /** Present on manual UPI quotes — Eventbuzz platform fee (paise). */ platformFeeMinor?: number; /** Manual quote only — for UPI `pn` field. */ ticketName?: string; eventName?: string; taxLines: { label: string; rateBps: number; amountMinor: number }[]; currency: string; }; export type PublicCheckoutOptions = { onlineAvailable: boolean; onlineGateways?: Array<{ id: string; provider: string; label: string; isActive: boolean; isPrimary: boolean; testMode: boolean; ticketCheckoutSupported: boolean; }>; manualUpi: { manualQrMode: 'upload' | 'dynamic'; eventName: string; upiQrImageUrl: string; upiId: string; payeeName: string; instructions: string; platformFeeInr: number; } | null; }; export type CheckoutOrderResponse = { keyId: string; orderId: string; amount: number; currency: string; transactionId: string; checkoutSource: string; }; export const publicEventTicketsApi = { async getEventSummary(eventId: string): Promise<{ name: string; subtitle?: string; startDate?: string; endDate?: string; location?: string; locationType?: string; image?: string; }> { const res = await fetch(url(`/public/events/${eventId}/summary`), { method: 'GET' }); const out = await parse<{ name: string; subtitle?: string; startDate?: string; endDate?: string; location?: string; locationType?: string; image?: string; }>(res); if (out.error) throw new Error(out.error); return out.data!; }, async listTickets(eventId: string): Promise { const res = await fetch(url(`/public/events/${eventId}/tickets`), { method: 'GET' }); const out = await parse<{ tickets: PublicTicketCatalogItem[] }>(res); if (out.error) throw new Error(out.error); return out.data?.tickets ?? []; }, async checkoutOptions(eventId: string): Promise { const res = await fetch(url(`/public/events/${eventId}/tickets/checkout-options`), { method: 'GET' }); const out = await parse(res); if (out.error) throw new Error(out.error); return out.data!; }, async quote( eventId: string, payload: { ticketId: string; quantity: number; billingStateCode?: string }, ): Promise { const res = await fetch(url(`/public/events/${eventId}/tickets/quote`), { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const out = await parse(res); if (out.error) throw new Error(out.error); return out.data!; }, async manualQuote( eventId: string, payload: { ticketId: string; quantity: number; billingStateCode?: string }, ): Promise { const res = await fetch(url(`/public/events/${eventId}/tickets/manual-quote`), { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const out = await parse(res); if (out.error) throw new Error(out.error); return out.data!; }, async checkout( eventId: string, payload: { ticketId: string; quantity: number; billingStateCode?: string; purchaserEmail: string; sourceFormId?: string; attendees: Array<{ firstName: string; lastName: string; email: string; phone?: string; organization?: string; designation?: string; displayName?: string; formData?: Record; }>; expectedTotalMinor: number; idempotencyKey?: string; orgGatewayId?: string; }, ): Promise { const res = await fetch(url(`/public/events/${eventId}/tickets/checkout`), { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const out = await parse(res); if (out.error) throw new Error(out.error); return out.data!; }, async verifyPayment( eventId: string, payload: { orderId: string; paymentId: string; signature: string }, ): Promise { const res = await fetch(url(`/public/events/${eventId}/payment/verify`), { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const out = await parse<{ verified: boolean }>(res); if (out.error) throw new Error(out.error); }, async manualSubmit( eventId: string, payload: { ticketId: string; quantity: number; billingStateCode?: string; purchaserEmail: string; sourceFormId?: string; attendees: Array<{ firstName: string; lastName: string; email: string; phone?: string; organization?: string; designation?: string; displayName?: string; formData?: Record; }>; expectedTotalMinor: number; screenshotDataUrl: string; buyerNote?: string; }, ): Promise<{ orderId: string; message: string }> { const res = await fetch(url(`/public/events/${eventId}/tickets/manual-submit`), { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const out = await parse<{ orderId: string; message: string }>(res); if (out.error) throw new Error(out.error); return out.data!; }, };