feat(registration): add watcher capacity limits and update pricing
Add 70-person capacity limit for watchers with real-time availability checks. Update drink card pricing to €5 per person (was €5 base + €2 per guest). Add feature flag to bypass registration countdown. Show under-review notice for performer registrations. Update FAQ performance duration from 5-7 to 5 minutes.
This commit is contained in:
@@ -62,9 +62,11 @@ const REMINDER_24H_WINDOW_END = new Date(
|
||||
// Shared helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/** Drink card price in euros: €5 base + €2 per extra guest. */
|
||||
const MAX_WATCHERS = 70; // max total watcher spots (people, not registrations)
|
||||
|
||||
/** Drink card price in euros: €5 per person (primary + guests). */
|
||||
function drinkCardEuros(guestCount: number): number {
|
||||
return 5 + guestCount * 2;
|
||||
return 5 + guestCount * 5;
|
||||
}
|
||||
|
||||
/** Drink card price in cents for payment processing. */
|
||||
@@ -301,6 +303,28 @@ export const appRouter = {
|
||||
healthCheck: publicProcedure.handler(() => "OK"),
|
||||
drinkkaart: drinkkaartRouter,
|
||||
|
||||
getWatcherCapacity: publicProcedure.handler(async () => {
|
||||
const rows = await db
|
||||
.select({ guests: registration.guests })
|
||||
.from(registration)
|
||||
.where(
|
||||
and(
|
||||
eq(registration.registrationType, "watcher"),
|
||||
isNull(registration.cancelledAt),
|
||||
),
|
||||
);
|
||||
const takenSpots = rows.reduce((sum, r) => {
|
||||
const g = r.guests ? (JSON.parse(r.guests) as unknown[]) : [];
|
||||
return sum + 1 + g.length;
|
||||
}, 0);
|
||||
return {
|
||||
total: MAX_WATCHERS,
|
||||
taken: takenSpots,
|
||||
available: Math.max(0, MAX_WATCHERS - takenSpots),
|
||||
isFull: takenSpots >= MAX_WATCHERS,
|
||||
};
|
||||
}),
|
||||
|
||||
privateData: protectedProcedure.handler(({ context }) => ({
|
||||
message: "This is private",
|
||||
user: context.session?.user,
|
||||
@@ -313,6 +337,29 @@ export const appRouter = {
|
||||
const isPerformer = input.registrationType === "performer";
|
||||
const guests = isPerformer ? [] : (input.guests ?? []);
|
||||
|
||||
// Enforce max watcher capacity (70 people total, counting guests)
|
||||
if (!isPerformer) {
|
||||
const rows = await db
|
||||
.select({ guests: registration.guests })
|
||||
.from(registration)
|
||||
.where(
|
||||
and(
|
||||
eq(registration.registrationType, "watcher"),
|
||||
isNull(registration.cancelledAt),
|
||||
),
|
||||
);
|
||||
const takenSpots = rows.reduce((sum, r) => {
|
||||
const g = r.guests ? (JSON.parse(r.guests) as unknown[]) : [];
|
||||
return sum + 1 + g.length;
|
||||
}, 0);
|
||||
const newSpots = 1 + guests.length;
|
||||
if (takenSpots + newSpots > MAX_WATCHERS) {
|
||||
throw new Error(
|
||||
`Er zijn helaas niet genoeg plaatsen meer beschikbaar. Nog ${MAX_WATCHERS - takenSpots} ${MAX_WATCHERS - takenSpots === 1 ? "plaats" : "plaatsen"} vrij.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await db.insert(registration).values({
|
||||
id: randomUUID(),
|
||||
firstName: input.firstName,
|
||||
|
||||
Reference in New Issue
Block a user