From 80d643c65c3fc0fb6fb6c21a136baf88e597d91f Mon Sep 17 00:00:00 2001 From: jackiettran <41605212+jackiettran@users.noreply.github.com> Date: Mon, 12 Jan 2026 16:52:37 -0500 Subject: [PATCH] Fixed bug where could not rent 3-4 and 4-5PM --- backend/routes/rentals.js | 58 ++++++++++++++++++--------------- frontend/src/pages/RentItem.tsx | 14 ++++++++ 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/backend/routes/rentals.js b/backend/routes/rentals.js index b3886b0..7fed6aa 100644 --- a/backend/routes/rentals.js +++ b/backend/routes/rentals.js @@ -273,37 +273,20 @@ router.post("/", authenticateToken, requireVerifiedEmail, async (req, res) => { // Check for overlapping rentals using datetime ranges // Note: "active" rentals are stored as "confirmed" with startDateTime in the past + // Two ranges [A,B] and [C,D] overlap if and only if A < D AND C < B + // Here: existing rental [existingStart, existingEnd], new rental [rentalStartDateTime, rentalEndDateTime] + // Overlap: existingStart < rentalEndDateTime AND rentalStartDateTime < existingEnd const overlappingRental = await Rental.findOne({ where: { itemId, status: "confirmed", - [Op.or]: [ - { - [Op.and]: [ - { startDateTime: { [Op.not]: null } }, - { endDateTime: { [Op.not]: null } }, - { - [Op.or]: [ - { - startDateTime: { - [Op.between]: [rentalStartDateTime, rentalEndDateTime], - }, - }, - { - endDateTime: { - [Op.between]: [rentalStartDateTime, rentalEndDateTime], - }, - }, - { - [Op.and]: [ - { startDateTime: { [Op.lte]: rentalStartDateTime } }, - { endDateTime: { [Op.gte]: rentalEndDateTime } }, - ], - }, - ], - }, - ], - }, + startDateTime: { [Op.not]: null }, + endDateTime: { [Op.not]: null }, + [Op.and]: [ + // existingStart < newEnd (existing rental starts before new one ends) + { startDateTime: { [Op.lt]: rentalEndDateTime } }, + // existingEnd > newStart (existing rental ends after new one starts) + { endDateTime: { [Op.gt]: rentalStartDateTime } }, ], }, }); @@ -1087,6 +1070,27 @@ router.post("/cost-preview", authenticateToken, async (req, res) => { }); } + // Check for overlapping rentals (same logic as in POST /rentals) + // Two ranges overlap if: existingStart < newEnd AND existingEnd > newStart + const overlappingRental = await Rental.findOne({ + where: { + itemId, + status: "confirmed", + startDateTime: { [Op.not]: null }, + endDateTime: { [Op.not]: null }, + [Op.and]: [ + { startDateTime: { [Op.lt]: rentalEndDateTime } }, + { endDateTime: { [Op.gt]: rentalStartDateTime } }, + ], + }, + }); + + if (overlappingRental) { + return res + .status(400) + .json({ error: "Item is already booked for these dates" }); + } + // Calculate rental cost using duration calculator const totalAmount = RentalDurationCalculator.calculateRentalCost( rentalStartDateTime, diff --git a/frontend/src/pages/RentItem.tsx b/frontend/src/pages/RentItem.tsx index 14d50f1..49517f2 100644 --- a/frontend/src/pages/RentItem.tsx +++ b/frontend/src/pages/RentItem.tsx @@ -420,6 +420,20 @@ const RentItem: React.FC = () => { {dateValidationError} + ) : costError ? ( +