import Member from "../../../../models/member.js"; import { loadPublicEvent } from "../../../../utils/loadEvent.js"; import { validateBody } from "../../../../utils/validateBody.js"; import { ticketReserveSchema } from "../../../../utils/schemas.js"; import { calculateTicketPrice, hasMemberAccess, reserveTicket, validateTicketPurchase, } from "../../../../utils/tickets.js"; /** * POST /api/events/[id]/tickets/reserve * Temporarily reserve a ticket during checkout process * Body: { email } */ export default defineEventHandler(async (event) => { try { const identifier = getRouterParam(event, "id"); const body = await validateBody(event, ticketReserveSchema); const eventData = await loadPublicEvent(event, identifier); const member = await Member.findOne({ email: body.email.toLowerCase() }); // Gate on deadline, cancellation, start, members-only, sold-out, and // already-registered before reserving. const validation = validateTicketPurchase(eventData, { email: body.email, member: hasMemberAccess(member) ? member : null, }); if (!validation.valid) { const statusCode = /members only/i.test(validation.reason) ? 403 : 400; throw createError({ statusCode, statusMessage: validation.reason }); } const ticketInfo = validation.ticketInfo || calculateTicketPrice(eventData, member); const reservation = await reserveTicket(eventData, ticketInfo.ticketType); if (!reservation.success) { throw createError({ statusCode: 400, statusMessage: reservation.reason || "Failed to reserve ticket", }); } return { success: true, reservation: { id: reservation.reservationId, expiresAt: reservation.expiresAt, ticketType: ticketInfo.ticketType, }, }; } catch (error) { if (error.statusCode) { throw error; } console.error("Error reserving ticket:", error); throw createError({ statusCode: 500, statusMessage: "Failed to reserve ticket", }); } });