diff --git a/src/App.tsx b/src/App.tsx index 5c7da9c..26b24d9 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -16,6 +16,7 @@ import { ReportsPage } from './pages/ReportsPage' import { WebsitePage } from './pages/WebsitePage' import { BookingWidgetPage } from './pages/BookingWidgetPage' import { AvailabilityPage } from './pages/AvailabilityPage' +import { FloorMapPage } from './pages/FloorMapPage' import { AdminDashboard } from './pages/AdminDashboard' export default function App() { @@ -43,6 +44,7 @@ export default function App() { } /> } /> } /> + } /> {/* Admin routes */} diff --git a/src/components/bookings/BookingModal.tsx b/src/components/bookings/BookingModal.tsx index 0f2fece..bc3d3f8 100644 --- a/src/components/bookings/BookingModal.tsx +++ b/src/components/bookings/BookingModal.tsx @@ -1,8 +1,12 @@ import { useState } from 'react' import { format } from 'date-fns' +import { Star, Banknote, CreditCard, AlertCircle, Map } from 'lucide-react' import { Modal } from '../ui/Modal' import { cn, BOOKING_STATUS_LABELS, SOURCE_LABELS } from '../../lib/utils' import type { Booking, DraftBooking, Room, BookingStatus, BookingSource } from '../../types' +import { FloorMapModal } from '../floormap/FloorMapModal' + +const GUEST_TAGS = ['VIP', 'Постоянный гость', 'Корпоративный', 'Медовый месяц', 'День рождения', 'Особые пожелания'] interface BookingModalProps { open: boolean @@ -15,33 +19,42 @@ interface BookingModalProps { export function BookingModal({ open, draft, rooms, onClose, onSave, existing }: BookingModalProps) { const [form, setForm] = useState({ - roomId: existing?.roomId ?? draft.roomId, - guestName: existing?.guestName ?? '', - guestEmail: existing?.guestEmail ?? '', - checkIn: existing?.checkIn ?? draft.checkIn, - checkOut: existing?.checkOut ?? draft.checkOut, - adults: existing?.adults ?? 2, - children: existing?.children ?? 0, - source: (existing?.source ?? 'direct') as BookingSource, - status: (existing?.status ?? 'confirmed') as BookingStatus, - notes: existing?.notes ?? '', + roomId: existing?.roomId ?? draft.roomId, + guestName: existing?.guestName ?? '', + guestEmail: existing?.guestEmail ?? '', + checkIn: existing?.checkIn ?? draft.checkIn, + checkOut: existing?.checkOut ?? draft.checkOut, + adults: existing?.adults ?? 2, + children: existing?.children ?? 0, + source: (existing?.source ?? 'direct') as BookingSource, + status: (existing?.status ?? 'confirmed') as BookingStatus, + notes: existing?.notes ?? '', }) + const [guestTags, setGuestTags] = useState([]) + const [paymentMethod, setPaymentMethod] = useState<'cash' | 'terminal' | null>(null) + const [paidAmount, setPaidAmount] = useState(existing?.paidAmount ?? 0) + const [showFloorMap, setShowFloorMap] = useState(false) const room = rooms.find(r => r.id === form.roomId) const nights = form.checkIn && form.checkOut ? Math.max(0, (new Date(form.checkOut).getTime() - new Date(form.checkIn).getTime()) / 86400000) : 0 const total = (room?.baseRate ?? 0) * nights + const debt = Math.max(0, total - paidAmount) + const isFutureBooking = form.checkIn > format(new Date(), 'yyyy-MM-dd') const set = (k: K, v: typeof form[K]) => setForm(prev => ({ ...prev, [k]: v })) + const toggleTag = (tag: string) => + setGuestTags(prev => prev.includes(tag) ? prev.filter(t => t !== tag) : [...prev, tag]) + const handleSave = () => { if (!form.guestName || !form.checkIn || !form.checkOut) return onSave({ ...form, totalAmount: total, - paidAmount: existing?.paidAmount ?? 0, + paidAmount, id: existing?.id ?? `b-${Date.now()}`, hotelId: 'hotel-1', guestId: existing?.guestId ?? `g-${Date.now()}`, @@ -50,183 +63,310 @@ export function BookingModal({ open, draft, rooms, onClose, onSave, existing }: } return ( - - - - - } - > -
- {/* Room */} -
- - -
- - {/* Guest */} -
+ <> + + + + + } + > +
+ {/* Room */}
- - set('guestName', e.target.value)} - /> -
-
- - set('guestEmail', e.target.value)} - /> -
-
- - {/* Dates */} -
-
- - set('checkIn', e.target.value)} - /> -
-
- - set('checkOut', e.target.value)} - /> -
-
- - {/* Guests count */} -
-
- - set('adults', parseInt(e.target.value) || 1)} - /> -
-
- - set('children', parseInt(e.target.value) || 0)} - /> -
-
- +
+ + +
-
- {/* Source */} -
- -
- {(Object.entries(SOURCE_LABELS) as [BookingSource, string][]).map(([k, v]) => ( - + ) + })} +
+
+ + {/* Dates */} +
+
+ + set('checkIn', e.target.value)} + /> +
+
+ + set('checkOut', e.target.value)} + /> +
+
+ + {/* Guests count */} +
+
+ + set('adults', parseInt(e.target.value) || 1)} + /> +
+
+ + set('children', parseInt(e.target.value) || 0)} + /> +
+
+ + +
-
- {/* Notes */} -
- -