import { useState } from 'react' import { Plus, Pencil, Trash2, Clock, CalendarDays, X, Save } from 'lucide-react' import { format } from 'date-fns' import { ru } from 'date-fns/locale' import { cn, formatCurrency } from '../lib/utils' import { Badge } from '../components/ui/Badge' import { RENTAL_OBJECTS, MOCK_RENTAL_BOOKINGS } from '../data/rentalData' import type { RentalObject, RentalBooking } from '../data/rentalData' import { RentalBookingModal } from '../components/rental/RentalBookingModal' // ── Object form ─────────────────────────────────────────────────────────────── const ICON_OPTIONS = ['🎾', '🛁', '🏛️', '⛳', '🏊', '🎱', '🎮', '🏋️', '🎤', '🏕️', '🚲', '🛶'] const COLOR_OPTIONS = [ { value: 'bg-green-500', label: 'Зелёный' }, { value: 'bg-orange-500', label: 'Оранжевый' }, { value: 'bg-violet-500', label: 'Фиолетовый' }, { value: 'bg-blue-500', label: 'Синий' }, { value: 'bg-red-500', label: 'Красный' }, { value: 'bg-teal-500', label: 'Бирюзовый' }, { value: 'bg-amber-500', label: 'Жёлтый' }, { value: 'bg-pink-500', label: 'Розовый' }, ] const TEXT_COLORS: Record = { 'bg-green-500': 'text-green-700 dark:text-green-400', 'bg-orange-500': 'text-orange-700 dark:text-orange-400', 'bg-violet-500': 'text-violet-700 dark:text-violet-400', 'bg-blue-500': 'text-blue-700 dark:text-blue-400', 'bg-red-500': 'text-red-700 dark:text-red-400', 'bg-teal-500': 'text-teal-700 dark:text-teal-400', 'bg-amber-500': 'text-amber-700 dark:text-amber-400', 'bg-pink-500': 'text-pink-700 dark:text-pink-400', } interface ObjectFormData { name: string icon: string color: string pricePerHour: number pricePerDay: number openHour: number closeHour: number maxHoursPerSlot: number | '' bufferMinutes: number description: string } const EMPTY_FORM: ObjectFormData = { name: '', icon: '🎾', color: 'bg-green-500', pricePerHour: 1000, pricePerDay: 5000, openHour: 9, closeHour: 21, maxHoursPerSlot: '', bufferMinutes: 0, description: '', } function ObjectFormModal({ initial, onSave, onClose, }: { initial?: RentalObject onSave: (obj: RentalObject) => void onClose: () => void }) { const [form, setForm] = useState( initial ? { name: initial.name, icon: initial.icon, color: initial.color, pricePerHour: initial.pricePerHour, pricePerDay: initial.pricePerDay, openHour: initial.openHour, closeHour: initial.closeHour, maxHoursPerSlot: initial.maxHoursPerSlot ?? '', bufferMinutes: initial.bufferMinutes ?? 0, description: '', } : EMPTY_FORM, ) const set = (k: K, v: ObjectFormData[K]) => setForm(prev => ({ ...prev, [k]: v })) const handleSave = () => { if (!form.name.trim()) return onSave({ id: initial?.id ?? `obj-${Date.now()}`, name: form.name.trim(), icon: form.icon, color: form.color, textColor: TEXT_COLORS[form.color] ?? 'text-slate-700', pricePerHour: form.pricePerHour, pricePerDay: form.pricePerDay, openHour: form.openHour, closeHour: form.closeHour, maxHoursPerSlot: form.maxHoursPerSlot !== '' ? Number(form.maxHoursPerSlot) : undefined, bufferMinutes: form.bufferMinutes > 0 ? form.bufferMinutes : undefined, }) } return (

{initial ? 'Редактировать объект' : 'Новый объект аренды'}

{/* Name */}
set('name', e.target.value)} />
{/* Icon + Color */}
{ICON_OPTIONS.map(ico => ( ))}
{COLOR_OPTIONS.map(c => (
{/* Prices */}
set('pricePerHour', parseInt(e.target.value) || 0)} />
set('pricePerDay', parseInt(e.target.value) || 0)} />
{/* Buffer time */}

Время для уборки СПА, подготовки корта и т.д.

{/* Hours */}
set('maxHoursPerSlot', e.target.value === '' ? '' : parseInt(e.target.value))} />
{/* Preview */}
{form.icon}

{form.name || 'Название объекта'}

{formatCurrency(form.pricePerHour)}/ч · {formatCurrency(form.pricePerDay)}/день · {String(form.openHour).padStart(2, '0')}:00–{String(form.closeHour).padStart(2, '0')}:00

) } // ── Main page ───────────────────────────────────────────────────────────────── export function RentalPage() { const [objects, setObjects] = useState(RENTAL_OBJECTS) const [bookings, setBookings] = useState(MOCK_RENTAL_BOOKINGS) const [editObj, setEditObj] = useState(null) const [createModal, setCreateModal] = useState(false) const [selectedObj, setSelectedObj] = useState(null) const [rentalModal, setRentalModal] = useState<{ obj: RentalObject; date: string; editBooking?: RentalBooking } | null>(null) const today = format(new Date(), 'yyyy-MM-dd') const handleSaveObject = (obj: RentalObject) => { setObjects(prev => { const exists = prev.find(o => o.id === obj.id) return exists ? prev.map(o => o.id === obj.id ? obj : o) : [...prev, obj] }) setEditObj(null) setCreateModal(false) } const handleDeleteObject = (id: string) => { setObjects(prev => prev.filter(o => o.id !== id)) if (selectedObj?.id === id) setSelectedObj(null) } 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) } const totalRevenue = bookings .filter(b => b.status === 'confirmed') .reduce((s, b) => s + b.totalAmount, 0) return (
{/* Header */}

Аренда объектов

{objects.length} объектов · управление и расписание

{/* Stats */}
{[ { label: 'Объектов', value: objects.length, color: 'text-slate-900 dark:text-slate-100' }, { label: 'Броней сегодня', value: bookings.filter(b => b.date === today).length, color: 'text-brand-600 dark:text-brand-400' }, { label: 'Всего броней', value: bookings.filter(b => b.status === 'confirmed').length, color: 'text-emerald-600 dark:text-emerald-400' }, { label: 'Общая выручка', value: formatCurrency(totalRevenue), color: 'text-emerald-600 dark:text-emerald-400' }, ].map(s => (

{s.value}

{s.label}

))}
{/* Objects list */}

Объекты аренды

{objects.map(obj => { const objBookings = bookings.filter(b => b.objectId === obj.id && b.status === 'confirmed') const todayB = objBookings.filter(b => b.date === today) const isSelected = selectedObj?.id === obj.id return (
setSelectedObj(isSelected ? null : obj)} className={cn( 'card p-4 cursor-pointer transition-all', isSelected ? 'ring-2 ring-brand-500' : 'hover:shadow-md', )} >
{obj.icon}

{obj.name}

{formatCurrency(obj.pricePerHour)}/ч · {String(obj.openHour).padStart(2, '0')}:00–{String(obj.closeHour).padStart(2, '0')}:00

{todayB.length > 0 && ( {todayB.length} сегодня )} {objBookings.length} всего
) })} {objects.length === 0 && (

Нет объектов аренды

)}
{/* Right: bookings for selected object */}
{selectedObj ? (

Бронирования — {selectedObj.name}

{['Дата', 'Время', 'Гость', 'Телефон', 'Сумма', 'Статус', ''].map((h, i) => ( ))} {bookings.filter(b => b.objectId === selectedObj.id) .sort((a, b) => b.date.localeCompare(a.date)) .map(b => ( ))}
{h}
{format(new Date(b.date), 'd MMM', { locale: ru })} {b.date === today && сегодня} {b.isFullDay ? ( Весь день ) : `${b.startHour}:00 – ${b.endHour}:00`} {b.guestName} {b.guestPhone || '—'} {formatCurrency(b.totalAmount)} {b.status === 'confirmed' ? 'Подтверждено' : 'Отменено'}
{bookings.filter(b => b.objectId === selectedObj.id).length === 0 && (
Нет бронирований для этого объекта
)}
) : (

Выберите объект слева для просмотра бронирований

)}
{/* Object form modals */} {(createModal || editObj) && ( { setCreateModal(false); setEditObj(null) }} /> )} {/* Rental booking modal */} {rentalModal && ( b.objectId === rentalModal.obj.id && b.date === rentalModal.date)} editBooking={rentalModal.editBooking} onClose={() => setRentalModal(null)} onSave={handleBookingSave} /> )}
) }