import Event from "../../../../models/event.js"; import Member from "../../../../models/member.js"; import { connectDB } from "../../../../utils/mongoose.js"; import { calculateTicketPrice, checkTicketAvailability, formatPrice, } from "../../../../utils/tickets.js"; import mongoose from "mongoose"; /** * GET /api/events/[id]/tickets/available * Check ticket availability and pricing for current user * Query params: ?email=user@example.com (optional) */ export default defineEventHandler(async (event) => { try { await connectDB(); const identifier = getRouterParam(event, "id"); const query = getQuery(event); const userEmail = query.email; if (!identifier) { throw createError({ statusCode: 400, statusMessage: "Event identifier is required", }); } // Fetch the event let eventData; if (mongoose.Types.ObjectId.isValid(identifier)) { eventData = await Event.findById(identifier); } if (!eventData) { eventData = await Event.findOne({ slug: identifier }); } if (!eventData) { throw createError({ statusCode: 404, statusMessage: "Event not found", }); } // Check if event is cancelled or past if (eventData.isCancelled) { return { available: false, reason: "Event has been cancelled", }; } if (new Date(eventData.startDate) < new Date()) { return { available: false, reason: "Event has already started", }; } // Check if user is a member (if email provided) let member = null; if (userEmail) { member = await Member.findOne({ email: userEmail.toLowerCase() }); } // Calculate ticket pricing for this user const ticketInfo = calculateTicketPrice(eventData, member); if (!ticketInfo) { return { available: false, reason: eventData.membersOnly ? "This event is for members only" : "No tickets available", membersOnly: eventData.membersOnly, }; } // Check availability const availability = checkTicketAvailability( eventData, ticketInfo.ticketType ); // Build response const response = { available: availability.available, ticketType: ticketInfo.ticketType, price: ticketInfo.price, currency: ticketInfo.currency, formattedPrice: formatPrice(ticketInfo.price, ticketInfo.currency), isFree: ticketInfo.isFree, isEarlyBird: ticketInfo.isEarlyBird, name: ticketInfo.name, description: ticketInfo.description, remaining: availability.remaining, waitlistAvailable: availability.waitlistAvailable, }; // Add early bird deadline if applicable if ( ticketInfo.isEarlyBird && eventData.tickets?.public?.earlyBirdDeadline ) { response.earlyBirdDeadline = eventData.tickets.public.earlyBirdDeadline; response.regularPrice = eventData.tickets.public.price; response.formattedRegularPrice = formatPrice( eventData.tickets.public.price, ticketInfo.currency ); } // Add member vs public comparison for transparency if (member && eventData.tickets?.public?.available) { response.publicTicket = { price: eventData.tickets.public.price, formattedPrice: formatPrice( eventData.tickets.public.price, eventData.tickets.currency ), }; response.memberSavings = eventData.tickets.public.price - ticketInfo.price; } // Check if user is already registered if (userEmail) { const alreadyRegistered = eventData.registrations?.some( (reg) => reg.email.toLowerCase() === userEmail.toLowerCase() && !reg.cancelledAt ); if (alreadyRegistered) { response.alreadyRegistered = true; response.available = false; response.reason = "You are already registered for this event"; } } return response; } catch (error) { console.error("Error checking ticket availability:", error); if (error.statusCode) { throw error; } throw createError({ statusCode: 500, statusMessage: "Failed to check ticket availability", }); } });