Fix: drag ghost visual, check-in date auto-fill, backend room_id patch

- BookingCalendar: replace tiny ghost badge with full-size booking block
  (same color, correct width based on nights × cell width, centered on cursor)
- BookingModal: auto-set check-out to check-in+1 day when check-in changes
- Backend PATCH /bookings/🆔 add room_id to allowed fields so drag-to-move saves correctly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-21 00:56:49 +03:00
parent 97b2ca1f91
commit 80e3b21827
3 changed files with 29 additions and 14 deletions

View File

@@ -144,7 +144,7 @@ const bookings: FastifyPluginAsync = async (fastify) => {
const hotelId = await getHotelId(slug) const hotelId = await getHotelId(slug)
if (!hotelId) return reply.code(404).send({ error: 'Hotel not found' }) if (!hotelId) return reply.code(404).send({ error: 'Hotel not found' })
const allowed = ['guest_name','guest_email','guest_phone','check_in','check_out', const allowed = ['room_id','guest_name','guest_email','guest_phone','check_in','check_out',
'adults','children','status','source','total_amount','paid_amount','notes'] 'adults','children','status','source','total_amount','paid_amount','notes']
const updates: string[] = [] const updates: string[] = []
const values: unknown[] = [] const values: unknown[] = []

View File

@@ -1,5 +1,5 @@
import { useState } from 'react' import { useState } from 'react'
import { format } from 'date-fns' import { format, addDays } from 'date-fns'
import { Star, Banknote, CreditCard, AlertCircle, Map, Plus, Trash2, Tag, Minus, BedDouble, Tv2, Send, Loader2, CheckCircle2 } from 'lucide-react' import { Star, Banknote, CreditCard, AlertCircle, Map, Plus, Trash2, Tag, Minus, BedDouble, Tv2, Send, Loader2, CheckCircle2 } from 'lucide-react'
import { MOCK_DISCOUNTS } from '../../pages/DiscountsPage' import { MOCK_DISCOUNTS } from '../../pages/DiscountsPage'
import type { Discount } from '../../pages/DiscountsPage' import type { Discount } from '../../pages/DiscountsPage'
@@ -298,7 +298,13 @@ export function BookingModal({ open, draft, rooms, bookings = [], onClose, onSav
<input <input
type="date" className="input" type="date" className="input"
value={form.checkIn} value={form.checkIn}
onChange={e => set('checkIn', e.target.value)} onChange={e => {
const newCheckIn = e.target.value
set('checkIn', newCheckIn)
if (newCheckIn && (!form.checkOut || form.checkOut <= newCheckIn)) {
set('checkOut', format(addDays(new Date(newCheckIn), 1), 'yyyy-MM-dd'))
}
}}
/> />
</div> </div>
<div> <div>

View File

@@ -753,17 +753,26 @@ export function BookingCalendar({ rooms, bookings, slug, onBookingCreate, onBook
)} )}
{/* Drag ghost element */} {/* Drag ghost element */}
{movingBooking && ghostPos && ( {movingBooking && ghostPos && (() => {
const nights = differenceInDays(parseISO(movingBooking.checkOut), parseISO(movingBooking.checkIn))
const ghostWidth = Math.max(80, Math.min(nights * CELL_WIDTH - 4, 320))
return (
<div <div
className={cn( 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', 'fixed z-[9999] pointer-events-none flex items-center px-2 rounded-md text-white text-xs font-semibold shadow-2xl border-l-4 opacity-90',
BOOKING_STATUS_COLORS[movingBooking.status], BOOKING_STATUS_COLORS[movingBooking.status],
)} )}
style={{ left: ghostPos.x + 14, top: ghostPos.y - 16 }} style={{
left: ghostPos.x - ghostWidth / 2,
top: ghostPos.y - ROW_HEIGHT / 2 + 4,
width: ghostWidth,
height: ROW_HEIGHT - 8,
}}
> >
{movingBooking.guestName} <span className="truncate drop-shadow-sm">{movingBooking.guestName}</span>
</div> </div>
)} )
})()}
{/* Rental booking modal */} {/* Rental booking modal */}
{rentalModal && ( {rentalModal && (