Show occupancy badges on normal view for bedroom-type tasks

Occupied/departing/arriving badges previously only appeared in rooms-view.
Now bedroom-type tasks (those with a newbook_site_id) show them on the
normal view too, plus a new Unoccupied badge when none apply. Normal view
drops the grey-out/dim treatment and conveys state via badge only; the
dimming stays exclusive to rooms-view.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-10-01 14:18:03 +00:00
parent d0ff70eb86
commit 42b5bd7d9e

View file

@ -102,8 +102,9 @@ export default function Summary() {
status: OPEN_STATUSES.join(','), status: OPEN_STATUSES.join(','),
assigned_to: mineOnly ? user.email : undefined, assigned_to: mineOnly ? user.email : undefined,
}) })
// When rooms-view is on, also fetch live occupancy to mark occupied tasks // Always fetch live occupancy — bedroom-type tasks show occupancy badges on
const occFetch = roomsView ? fetchOccupancy().catch(() => null) : Promise.resolve(null) // every view, not just the rooms-view filter.
const occFetch = fetchOccupancy().catch(() => null)
Promise.all([taskFetch, occFetch]) Promise.all([taskFetch, occFetch])
.then(([t, occ]) => { .then(([t, occ]) => {
@ -115,7 +116,7 @@ export default function Summary() {
}) })
.catch(err => setError(err.message)) .catch(err => setError(err.message))
.finally(() => setLoading(false)) .finally(() => setLoading(false))
}, [mineOnly, roomsView, user.email]) }, [mineOnly, user.email])
useEffect(() => { load() }, [load]) useEffect(() => { load() }, [load])
useEffect(() => { useEffect(() => {
@ -346,20 +347,25 @@ export default function Summary() {
{(() => { {(() => {
const renderTask = (t: Task) => { const renderTask = (t: Task) => {
// Bedroom-type locations are the ones synced from NewBook (they carry a
// site id) — manual Rooms-category locations like corridors/stores never
// get an occupancy badge, in either view.
const sid = t.newbook_site_id ? String(t.newbook_site_id) : null const sid = t.newbook_site_id ? String(t.newbook_site_id) : null
const isOccupied = roomsView && !!sid && occupiedSiteIds.has(sid) const isOccupied = !!sid && occupiedSiteIds.has(sid)
const isDeparting = roomsView && !!sid && !isOccupied && departingSiteIds.has(sid) const isDeparting = !!sid && !isOccupied && departingSiteIds.has(sid)
// Not exclusive with isDeparting — a departing room can also have a same-day // Not exclusive with isDeparting — a departing room can also have a same-day
// incoming booking (back-to-back turnover), and both badges should show. // incoming booking (back-to-back turnover), and both badges should show.
const isArriving = roomsView && !!sid && !isOccupied && arrivingSiteIds.has(sid) const isArriving = !!sid && !isOccupied && arrivingSiteIds.has(sid)
const isUnoccupied = !!sid && !isOccupied && !isDeparting && !isArriving
return ( return (
<div <div
key={t.id} key={t.id}
className={`card task-card ${t.priority === 'urgent' ? 'urgent' : t.priority === 'high' ? 'high' : ''} ${t.unusable ? 'unusable' : ''}`} className={`card task-card ${t.priority === 'urgent' ? 'urgent' : t.priority === 'high' ? 'high' : ''} ${t.unusable ? 'unusable' : ''}`}
// Occupied (stayover) rooms grey out hard — not accessible today. Departing // Occupied (stayover) rooms grey out hard and departing rooms dim lightly,
// rooms are lightly dimmed only: guest is still in there right now, but the // but only in rooms-view — that's the filtered "what can I access today"
// room frees up later today so it's worth flagging rather than hiding. // view. On the normal view the same occupancy state is conveyed with
style={isOccupied ? { opacity: 0.5, filter: 'grayscale(0.3)' } : isDeparting ? { opacity: 0.8 } : undefined} // badges only, no dimming.
style={roomsView ? (isOccupied ? { opacity: 0.5, filter: 'grayscale(0.3)' } : isDeparting ? { opacity: 0.8 } : undefined) : undefined}
onClick={() => setOpenTask(t.id)} onClick={() => setOpenTask(t.id)}
> >
<div className="task-card-main"> <div className="task-card-main">
@ -368,6 +374,7 @@ export default function Summary() {
{isOccupied && <span className="badge badge-outline"><BedDouble size={10} strokeWidth={1.75} /> Occupied</span>} {isOccupied && <span className="badge badge-outline"><BedDouble size={10} strokeWidth={1.75} /> Occupied</span>}
{isDeparting && <span className="badge" style={{ background: '#ede9fe', color: '#6d28d9', border: '1px solid #c4b5fd' }}><LogOut size={10} strokeWidth={1.75} /> Departing</span>} {isDeparting && <span className="badge" style={{ background: '#ede9fe', color: '#6d28d9', border: '1px solid #c4b5fd' }}><LogOut size={10} strokeWidth={1.75} /> Departing</span>}
{isArriving && <span className="badge" style={{ background: '#fef3c7', color: '#92400e', border: '1px solid #fcd34d' }}><BedDouble size={10} strokeWidth={1.75} /> Arrival today</span>} {isArriving && <span className="badge" style={{ background: '#fef3c7', color: '#92400e', border: '1px solid #fcd34d' }}><BedDouble size={10} strokeWidth={1.75} /> Arrival today</span>}
{!roomsView && isUnoccupied && <span className="badge" style={{ background: '#dcfce7', color: '#166534', border: '1px solid #86efac' }}><BedDouble size={10} strokeWidth={1.75} /> Unoccupied</span>}
{t.unusable && <UnusableBadge />} {t.unusable && <UnusableBadge />}
{t.template_id && <span className="badge badge-outline">Recurring</span>} {t.template_id && <span className="badge badge-outline">Recurring</span>}
</div> </div>