ghostguild-org/server/api/series/[id]/tickets/available.get.js

112 lines
3 KiB
JavaScript

import Member from "../../../../models/member.js";
import { loadPublicSeries } from "../../../../utils/loadSeries.js";
import {
calculateSeriesTicketPrice,
checkSeriesTicketAvailability,
checkUserSeriesPass,
} from "../../../../utils/tickets.js";
export default defineEventHandler(async (event) => {
try {
const seriesId = getRouterParam(event, "id");
const query = getQuery(event);
const email = query.email;
// Fetch series
const series = await loadPublicSeries(event, seriesId);
// Check if tickets are enabled
if (!series.tickets?.enabled) {
return {
available: false,
message: "Tickets are not enabled for this series",
};
}
// Check membership if email provided
let member = null;
// Try auth cookie first for accurate member pricing
try {
member = await requireAuth(event);
} catch {
// Not authenticated — fall through to email lookup
}
if (!member && email) {
member = await Member.findOne({ email: email.toLowerCase() });
}
// Check if user already has a series pass
const { hasPass, registration } = checkUserSeriesPass(series, member?.email || email || "");
if (hasPass) {
return {
available: false,
alreadyRegistered: true,
registration: {
ticketType: registration.ticketType,
registeredAt: registration.registeredAt,
eventsIncluded: registration.eventRegistrations?.length || 0,
},
message: "You already have a pass for this series",
};
}
// Calculate pricing for user
const ticketInfo = calculateSeriesTicketPrice(series, member);
if (!ticketInfo) {
return {
available: false,
message: "No series passes available for your membership status",
};
}
// Check availability
const availability = checkSeriesTicketAvailability(
series,
ticketInfo.ticketType,
);
return {
available: availability.available,
ticket: {
type: ticketInfo.ticketType,
name: ticketInfo.name,
description: ticketInfo.description,
price: ticketInfo.price,
currency: ticketInfo.currency,
isFree: ticketInfo.isFree,
isEarlyBird: ticketInfo.isEarlyBird,
},
availability: {
remaining: availability.remaining,
unlimited: availability.remaining === null,
waitlistAvailable: availability.waitlistAvailable,
},
series: {
id: series.id,
title: series.title,
totalEvents: series.totalEvents,
type: series.type,
},
memberInfo: member
? {
isMember: true,
circle: member.circle,
name: member.name,
}
: {
isMember: false,
},
};
} catch (error) {
console.error("Error checking series ticket availability:", error);
throw createError({
statusCode: error.statusCode || 500,
statusMessage:
error.statusMessage || "Failed to check series ticket availability",
});
}
});