From 32a4c0c37b340ac5f3eac8a10c392c91a7635f3c Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 15 Dec 2025 15:50:48 +0800 Subject: [PATCH 1/3] feat: implement weekly booking deadline restriction --- src/lib/actions/booking.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/lib/actions/booking.ts b/src/lib/actions/booking.ts index dd0cb02..6d6942f 100644 --- a/src/lib/actions/booking.ts +++ b/src/lib/actions/booking.ts @@ -51,6 +51,22 @@ export const createBooking = async ( }; } + // check booking deadline (one week or more in advance) + // unless user is admin + if (token.isAdmin === false) { + const now = new Date(); + const bookingDate = new Date(data.startTime); + const daysUntilBooking = Math.floor( + (bookingDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24), + ); + if (daysUntilBooking < 7) { + return { + success: false, + message: 'Bookings must be made at least one week in advance.', + }; + } + } + const overlapping = await prisma.booking.findFirst({ where: { venueId: data.venueId, From ad386b08fd8eab1b323c515809f235e3f1917e3e Mon Sep 17 00:00:00 2001 From: TheMythologist Date: Fri, 19 Dec 2025 11:35:33 +0800 Subject: [PATCH 2/3] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/lib/actions/booking.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/actions/booking.ts b/src/lib/actions/booking.ts index 6d6942f..683d0ca 100644 --- a/src/lib/actions/booking.ts +++ b/src/lib/actions/booking.ts @@ -52,8 +52,8 @@ export const createBooking = async ( } // check booking deadline (one week or more in advance) - // unless user is admin - if (token.isAdmin === false) { + // unless user is admin + if (!token.isAdmin) { const now = new Date(); const bookingDate = new Date(data.startTime); const daysUntilBooking = Math.floor( From e79e5ce3cea410c77a35dd2f8f5f574deb64e4f0 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 14 Jan 2026 00:32:10 +0800 Subject: [PATCH 3/3] restrictions to venues --- src/lib/actions/booking.ts | 101 ++++++++++++++++++++++++++++++------- 1 file changed, 84 insertions(+), 17 deletions(-) diff --git a/src/lib/actions/booking.ts b/src/lib/actions/booking.ts index 683d0ca..42a1227 100644 --- a/src/lib/actions/booking.ts +++ b/src/lib/actions/booking.ts @@ -42,7 +42,46 @@ export const createBooking = async ( message: 'Unknown error occurred. Please contact admin.', }; } - + const MSPERDAY = 1000 * 60 * 60 * 24; + const MIN_BOOKING_ADVANCE_DAYS = 7; + const MIN_BOOKING_ADVANCE_DAYS_PANTRY = 1; + if (token.isAdmin === false) { + const venue = await prisma.venue.findUnique({ + where: { + id: data.venueId + }, + select: { + name: true + }, + } + ); + const isPantry = venue?.name.toLowerCase().includes('pantry'); + const minDaysRequired = isPantry ? MIN_BOOKING_ADVANCE_DAYS_PANTRY : MIN_BOOKING_ADVANCE_DAYS; + const now = new Date(); + const bookingDate = new Date(data.startTime); + // ensure same timezone for rare cases of bookings + const utcNow = Date.UTC( + now.getFullYear(), + now.getMonth(), + now.getDate(), + ); + const utcBookingDate = Date.UTC( + bookingDate.getFullYear(), + bookingDate.getMonth(), + bookingDate.getDate(), + ); + const daysUntilBooking = Math.ceil( + (utcBookingDate - utcNow) / (MSPERDAY), + ); + // if pantries from saga; elm; cendy, bookings can be made up to 24 hours prior + if (daysUntilBooking < minDaysRequired) { + const advanceMessage = isPantry ? 'Pantry bookings must be made at least 24 hours in advance.' : 'Bookings must be made at least one week in advance.'; + return { + success: false, + message: advanceMessage, + }; + } +} // Ensure user has the permissions for the corresponding organisation if (!hasOrgPerms(token, data.organisationId)) { return { @@ -51,22 +90,6 @@ export const createBooking = async ( }; } - // check booking deadline (one week or more in advance) - // unless user is admin - if (!token.isAdmin) { - const now = new Date(); - const bookingDate = new Date(data.startTime); - const daysUntilBooking = Math.floor( - (bookingDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24), - ); - if (daysUntilBooking < 7) { - return { - success: false, - message: 'Bookings must be made at least one week in advance.', - }; - } - } - const overlapping = await prisma.booking.findFirst({ where: { venueId: data.venueId, @@ -178,6 +201,50 @@ export const editBooking = async ( }; } + const MSPERDAY = 1000 * 60 * 60 * 24; + const MIN_BOOKING_ADVANCE_DAYS = 7; + const MIN_BOOKING_ADVANCE_DAYS_PANTRY = 1; + + if (token.isAdmin === false) { + const venue = await prisma.venue.findUnique({ + where: { id: data.venueId }, + select: { name: true }, + }); + + const isPantry = venue?.name.toLowerCase().includes('pantry'); + const minDaysRequired = isPantry + ? MIN_BOOKING_ADVANCE_DAYS_PANTRY + : MIN_BOOKING_ADVANCE_DAYS; + + const now = new Date(); + const bookingDate = new Date(data.startTime); + + // Ensure same timezone + const utcNow = Date.UTC( + now.getFullYear(), + now.getMonth(), + now.getDate(), + ); + const utcBookingDate = Date.UTC( + bookingDate.getFullYear(), + bookingDate.getMonth(), + bookingDate.getDate(), + ); + + const daysUntilBooking = Math.ceil( + (utcBookingDate - utcNow) / MSPERDAY, + ); + + if (daysUntilBooking < minDaysRequired) { + return { + success: false, + message: isPantry + ? 'Pantry bookings must be made at least 24 hours in advance.' + : 'Bookings must be made at least one week in advance.', + }; + } + } + const overlapping = await prisma.booking.findFirst({ where: { venueId: data.venueId,