Calendar: add drag ghost element + grabbing cursor; BookingDetail: add Relocate room for checked_in guests

This commit is contained in:
2026-03-21 00:37:26 +03:00
parent 75d7d6aa08
commit 3e4a2a3cd2
3 changed files with 93 additions and 2 deletions

View File

@@ -84,6 +84,7 @@ export function BookingCalendar({ rooms, bookings, slug, onBookingCreate, onBook
// Drag-to-move booking state
const [movingBooking, setMovingBooking] = useState<Booking | null>(null)
const [moveTargetRoomId, setMoveTargetRoomId] = useState<string | null>(null)
const [ghostPos, setGhostPos] = useState<{ x: number; y: number } | null>(null)
const movingBookingRef = useRef<Booking | null>(null)
const didDragRef = useRef(false)
movingBookingRef.current = movingBooking
@@ -486,9 +487,11 @@ export function BookingCalendar({ rooms, bookings, slug, onBookingCreate, onBook
dragging = true
setMovingBooking(booking)
setMoveTargetRoomId(booking.roomId)
document.body.style.cursor = 'grabbing'
}
return
}
setGhostPos({ x: ev.clientX, y: ev.clientY })
const el = document.elementFromPoint(ev.clientX, ev.clientY)
const row = el?.closest('[data-room-id]') as HTMLElement | null
if (row?.dataset.roomId) setMoveTargetRoomId(row.dataset.roomId)
@@ -496,6 +499,7 @@ export function BookingCalendar({ rooms, bookings, slug, onBookingCreate, onBook
const onUp = (ev: MouseEvent) => {
window.removeEventListener('mousemove', onMove)
window.removeEventListener('mouseup', onUp)
document.body.style.cursor = ''
if (dragging) {
const el = document.elementFromPoint(ev.clientX, ev.clientY)
const row = el?.closest('[data-room-id]') as HTMLElement | null
@@ -506,6 +510,7 @@ export function BookingCalendar({ rooms, bookings, slug, onBookingCreate, onBook
}
setMovingBooking(null)
setMoveTargetRoomId(null)
setGhostPos(null)
}
}
window.addEventListener('mousemove', onMove)
@@ -741,6 +746,19 @@ export function BookingCalendar({ rooms, bookings, slug, onBookingCreate, onBook
/>
)}
{/* Drag ghost element */}
{movingBooking && ghostPos && (
<div
className={cn(
'fixed z-[9999] pointer-events-none px-3 py-1.5 rounded-lg text-white text-xs font-semibold shadow-xl border-2 border-white/40',
BOOKING_STATUS_COLORS[movingBooking.status],
)}
style={{ left: ghostPos.x + 14, top: ghostPos.y - 16 }}
>
{movingBooking.guestName}
</div>
)}
{/* Rental booking modal */}
{rentalModal && (
<RentalBookingModal