From 663eda34af63d2fbdc307b20bf0f3e452033e56e Mon Sep 17 00:00:00 2001 From: jtricerolph Date: Sat, 4 Jul 2026 18:55:31 +0000 Subject: [PATCH] Future dates: morning-only departure classifies as vacant, not depart MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A day-card represents that night. 'Depart' is a live operational state (checkout tracking) that only makes sense for today: on a future date the room's last occupied night is the previous day (shown as Stay), and the departure morning itself leaves the night vacant. classifyRoom now takes opts.future — when set, a departing-only room stays 'vacant' (or arrive/B2B if someone arrives), with the departing booking's coloured sliver on the left and the late-checkout time still shown in the bracket. Co-Authored-By: Claude Sonnet 4.6 --- backend/src/lib/booking-flow.js | 7 +++++-- backend/src/routes/rooms.js | 6 ++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/backend/src/lib/booking-flow.js b/backend/src/lib/booking-flow.js index afec45e..030ad12 100644 --- a/backend/src/lib/booking-flow.js +++ b/backend/src/lib/booking-flow.js @@ -52,7 +52,10 @@ export function departingBookingForSite(bookings, siteId, viewDate) { // Classify a site's booking state for a given view date. // Returns a rich descriptor used to build the room card. -export function classifyRoom(site, allBookings, viewDate, yesterday, tomorrow) { +// opts.future: viewDate is after the real today. A day-card represents that +// night, so a morning-only departure doesn't occupy it — 'depart' is a live +// operational state (checkout tracking) that only applies to today/past. +export function classifyRoom(site, allBookings, viewDate, yesterday, tomorrow, opts = {}) { const siteId = String(site.site_id) // Primary: booking that occupies the room on viewDate (arrival <= viewDate < departure) @@ -100,7 +103,7 @@ export function classifyRoom(site, allBookings, viewDate, yesterday, tomorrow) { flowType = 'stopover' } } - } else if (effectiveDeparting) { + } else if (effectiveDeparting && !opts.future) { primaryBooking = effectiveDeparting flowType = 'depart' } diff --git a/backend/src/routes/rooms.js b/backend/src/routes/rooms.js index b62c29f..3b5f79d 100644 --- a/backend/src/routes/rooms.js +++ b/backend/src/routes/rooms.js @@ -116,7 +116,8 @@ export async function roomRoutes(app) { const siteBookings = bookings.filter(matchFn) - const classified = classifyRoom(site, bookings, viewDate, yesterday, tomorrow) + const future = viewDate > new Date().toISOString().slice(0, 10) + const classified = classifyRoom(site, bookings, viewDate, yesterday, tomorrow, { future }) return { view_date: viewDate, yesterday, tomorrow, @@ -198,13 +199,14 @@ export async function roomRoutes(app) { } // Classify each site + const future = viewDate > new Date().toISOString().slice(0, 10) const rooms = [] for (const site of sites) { const catId = String(site.site_category_id ?? site.category_id ?? site.category?.id ?? '') const isExcluded = excludedCategories.includes(catId) if (isExcluded && hideExcluded) continue - const classified = classifyRoom(site, bookings, viewDate, yesterday, tomorrow) + const classified = classifyRoom(site, bookings, viewDate, yesterday, tomorrow, { future }) // Override category_order with settings value if available const catOrderOverride = settingsCatOrder[catId]