import axios from "axios"; import { useAuthStore } from "@/store/authStore"; const apiClient = axios.create({ baseURL: process.env.NEXT_PUBLIC_API_URL ?? "http://localhost:8081/api", headers: { "Content-Type": "application/json" }, }); apiClient.interceptors.request.use((config) => { const token = useAuthStore.getState().token; if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }); // ─── Domain types (mirror backend schemas) ──────────────────────────────────── export interface TournamentInfo { id: number; title: string; event_date: string; // ISO-8601 } export interface SeatInfo { id: number; sector: string; row: number; number: number; price: number; tournament: TournamentInfo; } export type TicketStatus = "AVAILABLE" | "LOCKED" | "PAID" | "SCANNED" | "REFUNDED"; export interface TicketResponse { id: number; status: TicketStatus; pdf_url: string | null; created_at: string; // ISO-8601 seat: SeatInfo; } // ─── Tickets API ────────────────────────────────────────────────────────────── /** * GET /api/tickets/me * Returns all PAID tickets for the authenticated user. * Throws AxiosError 401 if the token is missing or expired. */ export async function getMyTicketsApi(): Promise { const response = await apiClient.get("/tickets/me"); return response.data; } // ─── Seat locking ───────────────────────────────────────────────────────────── interface LockSeatResponse { message: string; seat_id: number; status: string; /** Returned by backend when the Ticket row is created. Falls back to seat_id. */ ticket_id?: number; } /** * POST /api/seats/{seat_id}/lock?user_id={user_id} * Returns the ticketId for the locked seat (falls back to seatId if backend * does not yet expose ticket_id in the response body). * Throws AxiosError with status 409 if the seat is already locked. */ export async function lockSeatApi( seatId: number, userId: number ): Promise<{ ticketId: number }> { const response = await apiClient.post( `/seats/${seatId}/lock`, null, { params: { user_id: userId } } ); return { ticketId: response.data.ticket_id ?? seatId }; } // ─── Payment webhook ────────────────────────────────────────────────────────── /** * POST /api/webhooks/payment * Simulates a payment gateway callback for the given ticket. * Uses a random idempotency key to satisfy the backend's idempotency check. */ export async function processPaymentWebhook(ticketId: number): Promise { const idempotencyKey = "req-" + Math.random().toString(36).substring(2, 9); await apiClient.post("/webhooks/payment", { ticket_id: ticketId, idempotency_key: idempotencyKey, status: "success", }); } export default apiClient;