Add date editing with conflict detection and rental booking editing

- BookingDetailPanel: edit dates/room with inline conflict detection; options to force-save or swap conflicting booking's room
- BookingsPage + CalendarPage: pass rooms/allBookings/onBulkUpdate to panel
- RentalBookingModal: accept editBooking prop to pre-populate fields for editing
- RentalPage: add edit (pencil) button per booking row, unify create/update handler

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-16 15:13:49 +03:00
parent 84c90bcab1
commit 913ddeedc9
6 changed files with 224 additions and 38 deletions

View File

@@ -234,7 +234,7 @@ export function RentalPage() {
const [editObj, setEditObj] = useState<RentalObject | null>(null)
const [createModal, setCreateModal] = useState(false)
const [selectedObj, setSelectedObj] = useState<RentalObject | null>(null)
const [rentalModal, setRentalModal] = useState<{ obj: RentalObject; date: string } | null>(null)
const [rentalModal, setRentalModal] = useState<{ obj: RentalObject; date: string; editBooking?: RentalBooking } | null>(null)
const today = format(new Date(), 'yyyy-MM-dd')
@@ -252,8 +252,11 @@ export function RentalPage() {
if (selectedObj?.id === id) setSelectedObj(null)
}
const handleBookingCreate = (b: RentalBooking) => {
setBookings(prev => [...prev, b])
const handleBookingSave = (b: RentalBooking) => {
setBookings(prev => {
const exists = prev.find(x => x.id === b.id)
return exists ? prev.map(x => x.id === b.id ? b : x) : [...prev, b]
})
setRentalModal(null)
}
@@ -378,8 +381,8 @@ export function RentalPage() {
<table className="w-full text-sm">
<thead>
<tr className="border-b border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-700/40">
{['Дата', 'Время', 'Гость', 'Телефон', 'Сумма', 'Статус'].map(h => (
<th key={h} className="text-left px-4 py-2.5 text-xs font-semibold text-slate-500 dark:text-slate-400 uppercase tracking-wide">{h}</th>
{['Дата', 'Время', 'Гость', 'Телефон', 'Сумма', 'Статус', ''].map((h, i) => (
<th key={i} className="text-left px-4 py-2.5 text-xs font-semibold text-slate-500 dark:text-slate-400 uppercase tracking-wide">{h}</th>
))}
</tr>
</thead>
@@ -408,6 +411,15 @@ export function RentalPage() {
{b.status === 'confirmed' ? 'Подтверждено' : 'Отменено'}
</Badge>
</td>
<td className="px-4 py-2.5">
<button
onClick={e => { e.stopPropagation(); setRentalModal({ obj: selectedObj, date: b.date, editBooking: b }) }}
className="p-1.5 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-700 text-slate-400 hover:text-slate-700 dark:hover:text-slate-300 transition-colors"
title="Редактировать"
>
<Pencil size={13} />
</button>
</td>
</tr>
))}
</tbody>
@@ -443,8 +455,9 @@ export function RentalPage() {
obj={rentalModal.obj}
date={rentalModal.date}
existingBookings={bookings.filter(b => b.objectId === rentalModal.obj.id && b.date === rentalModal.date)}
editBooking={rentalModal.editBooking}
onClose={() => setRentalModal(null)}
onSave={handleBookingCreate}
onSave={handleBookingSave}
/>
)}
</div>