Add floor map, rental module wiring, VIP tags and payment tracking in BookingModal
- New: Поэтажный план (/floor-map) — room status visualization per floor with color coding (occupied/arriving/departing/available/dirty/maintenance), click free room to create booking - New: FloorMapModal — embeddable in BookingModal via "Поэтажный план" button near room selector - New: RentalBookingModal — full-day toggle, hour start/end selects, conflict detection, price summary - CalendarPage: rental objects/bookings shown in шахматка when rental module is active - BookingsPage: "Аренда" tab with rental bookings table when rental module is active - BookingModal: guest tags (VIP, Постоянный гость, etc.), payment method (cash/terminal), paidAmount input, debt/задолженность display, floor map quick-access button - Sidebar: "План этажей" nav link added under Управление Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
84
src/pages/FloorMapPage.tsx
Normal file
84
src/pages/FloorMapPage.tsx
Normal file
@@ -0,0 +1,84 @@
|
||||
import { useState } from 'react'
|
||||
import { format, addDays } from 'date-fns'
|
||||
import { RefreshCw } from 'lucide-react'
|
||||
import { MOCK_ROOMS, MOCK_BOOKINGS } from '../data/mockData'
|
||||
import { FloorMap } from '../components/floormap/FloorMap'
|
||||
import { BookingModal } from '../components/bookings/BookingModal'
|
||||
import type { Booking } from '../types'
|
||||
|
||||
export function FloorMapPage() {
|
||||
const [bookings, setBookings] = useState<Booking[]>(MOCK_BOOKINGS)
|
||||
const [createForRoom, setCreateForRoom] = useState<string | null>(null)
|
||||
const [lastUpdate] = useState(new Date())
|
||||
|
||||
const handleSelectRoom = (id: string) => {
|
||||
setCreateForRoom(id)
|
||||
}
|
||||
|
||||
const stats = {
|
||||
total: MOCK_ROOMS.length,
|
||||
occupied: MOCK_ROOMS.filter(r => r.status === 'occupied').length,
|
||||
available: MOCK_ROOMS.filter(r => r.status === 'available').length,
|
||||
maintenance: MOCK_ROOMS.filter(r => r.status === 'maintenance' || r.status === 'blocked').length,
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-4 md:p-6 space-y-4">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-xl font-bold text-slate-900 dark:text-slate-100">Поэтажный план</h1>
|
||||
<p className="text-sm text-slate-500 dark:text-slate-400">
|
||||
Обновлено: {format(lastUpdate, 'HH:mm')} · Нажмите на свободный номер чтобы создать бронирование
|
||||
</p>
|
||||
</div>
|
||||
<button className="btn-secondary flex items-center gap-1.5">
|
||||
<RefreshCw size={14} />
|
||||
Обновить
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Quick stats */}
|
||||
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
|
||||
{[
|
||||
{ label: 'Всего номеров', value: stats.total, color: 'text-slate-900 dark:text-slate-100' },
|
||||
{ label: 'Занято', value: stats.occupied, color: 'text-red-600 dark:text-red-400' },
|
||||
{ label: 'Свободно', value: stats.available, color: 'text-emerald-600 dark:text-emerald-400' },
|
||||
{ label: 'Ремонт/закрыт', value: stats.maintenance, color: 'text-slate-500 dark:text-slate-400' },
|
||||
].map(s => (
|
||||
<div key={s.label} className="card px-4 py-3">
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400 mb-0.5">{s.label}</p>
|
||||
<p className={`text-2xl font-bold ${s.color}`}>{s.value}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Floor map */}
|
||||
<div className="card">
|
||||
<FloorMap
|
||||
rooms={MOCK_ROOMS}
|
||||
bookings={bookings}
|
||||
onSelectRoom={handleSelectRoom}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Create booking modal */}
|
||||
{createForRoom && (
|
||||
<BookingModal
|
||||
open
|
||||
draft={{
|
||||
roomId: createForRoom,
|
||||
checkIn: format(new Date(), 'yyyy-MM-dd'),
|
||||
checkOut: format(addDays(new Date(), 1), 'yyyy-MM-dd'),
|
||||
}}
|
||||
rooms={MOCK_ROOMS}
|
||||
onClose={() => setCreateForRoom(null)}
|
||||
onSave={(data) => {
|
||||
setBookings(prev => [...prev, data as Booking])
|
||||
setCreateForRoom(null)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user