diff --git a/frontend/src/components/CategoryGroup.tsx b/frontend/src/components/CategoryGroup.tsx
index 06091ea..832c108 100644
--- a/frontend/src/components/CategoryGroup.tsx
+++ b/frontend/src/components/CategoryGroup.tsx
@@ -15,6 +15,10 @@ interface Props {
export default function CategoryGroup({ categoryId, categoryName, rooms, viewDate, config, onRoomClick }: Props) {
const [open, setOpen] = useState(true)
+ const today = new Date().toISOString().slice(0, 10)
+ const isToday = viewDate === today
+ const isFuture = viewDate > today
+
const outstandingTasks = rooms.reduce((n, r) => {
return n + r.tasks.filter(t => {
const d = t.task_when_date || t.task_period_from
@@ -30,10 +34,10 @@ export default function CategoryGroup({ categoryId, categoryName, rooms, viewDat
setOpen(o => !o)}>
{categoryName}
{rooms.length}
- {outstandingTasks > 0 && (
+ {!isFuture && outstandingTasks > 0 && (
{outstandingTasks} tasks
)}
- {dirtyCount > 0 && (
+ {isToday && dirtyCount > 0 && (
{dirtyCount} dirty
)}
today
+
// Booking status (lowercased) drives the card border via CSS attribute selector
const bookingStatus = booking?.booking_status?.toLowerCase() ?? null
@@ -94,9 +98,13 @@ function RoomCard({ room, viewDate, config, onClick }: Props) {
// Departure time shown in the left-bracket sliver (not as a card pill).
// Show only when there's a departing booking whose status is still 'arrived'
// (not yet checked out). Matches original: collapses once status flips to 'departed'.
+ // On future dates every in-house booking is still 'arrived', so only show
+ // late checkouts (time after the default checkout time).
+ const defaultCheckout = (config?.default_checkout_time || '11:00').slice(0, 5)
const sliverDepartTime = !room.spans_previous &&
room.departing_time &&
- room.departing_booking?.booking_status?.toLowerCase() === 'arrived'
+ room.departing_booking?.booking_status?.toLowerCase() === 'arrived' &&
+ (!isFuture || room.departing_time.slice(0, 5) > defaultCheckout)
? room.departing_time.slice(0, 5)
: null
@@ -131,7 +139,7 @@ function RoomCard({ room, viewDate, config, onClick }: Props) {
return (
)}
onClick={() => onClick(room)}
>
@@ -139,7 +147,7 @@ function RoomCard({ room, viewDate, config, onClick }: Props) {
{sliverDepartTime && (
- {sliverDepartTime}
+ {sliverDepartTime}
)}
@@ -171,9 +179,11 @@ function RoomCard({ room, viewDate, config, onClick }: Props) {
{nights.current}/{nights.total}
)}
-
- {room.site_status || 'Unknown'}
-
+ {isToday && (
+
+ {room.site_status || 'Unknown'}
+
+ )}
@@ -222,16 +232,18 @@ function RoomCard({ room, viewDate, config, onClick }: Props) {
)}
- {/* Task status */}
-
-
- {outstanding.length > 0 && {outstanding.length}}
-
+ {/* Task status — housekeeping tasks only apply up to today */}
+ {!isFuture && (
+
+
+ {outstanding.length > 0 && {outstanding.length}}
+
+ )}
)}
{/* ── show_on_card task dots ──────────────────── */}
- {todayTasks.some(t => taskDisp[t.task_type_id]?.show_on_card) && (
+ {!isFuture && todayTasks.some(t => taskDisp[t.task_type_id]?.show_on_card) && (
{todayTasks.map(t => {
const d = taskDisp[t.task_type_id]
diff --git a/frontend/src/index.css b/frontend/src/index.css
index b292cca..6cecc58 100644
--- a/frontend/src/index.css
+++ b/frontend/src/index.css
@@ -460,23 +460,30 @@ html, body, #root {
.room-card[data-next-status="unconfirmed"]::after { border-color: #f59e0b; }
.room-card[data-next-status="departed"]::after { border-color: #a855f7; }
-/* Departure time shown in left-bracket sliver (while prev booking still 'arrived') */
+/* Departure time shown in left-bracket sliver (while prev booking still 'arrived').
+ The bracket widens to 19px when a time is shown; the time reads vertically. */
+.room-card.has-sliver-time[data-previous-status]::before { width: 19px; }
.card-sliver-depart {
position: absolute;
- left: -21px;
+ left: -23px;
+ width: 19px;
top: 50%;
transform: translateY(-50%);
display: flex;
flex-direction: column;
align-items: center;
- gap: 1px;
- font-size: 8px;
+ gap: 2px;
+ font-size: 9px;
font-weight: 600;
color: var(--col-arrived);
line-height: 1;
pointer-events: none;
white-space: nowrap;
}
+.card-sliver-depart .sliver-time {
+ writing-mode: vertical-rl;
+ letter-spacing: .04em;
+}
/* Blocked room */
.room-card.room-blocked {