import { useState, useEffect } from 'react' import { CreditCard, Banknote, Clock, LogIn, LogOut, CheckCircle2, Receipt, Zap, Building2, Coffee, Car, Package, ChevronRight, User, AlertCircle, Printer, } from 'lucide-react' import { format } from 'date-fns' import { ru } from 'date-fns/locale' import { cn, formatCurrency } from '../lib/utils' // ── Types ───────────────────────────────────────────────────────────────────── interface RoomBalance { roomId: string roomNumber: string guestName: string checkIn: string checkOut: string totalAmount: number paidAmount: number nights: number } type PaymentMethod = 'cash' | 'terminal' | 'atol' type ChargePurpose = 'stay' | 'breakfast' | 'transfer' | 'parking' | 'extra' interface ReceiptRecord { id: string roomNumber: string guestName: string purposeLabel: string amount: number method: PaymentMethod createdAt: Date shiftId: string } // ── Mock data ────────────────────────────────────────────────────────────────── const MOCK_BALANCES: RoomBalance[] = [ { roomId: 'r1', roomNumber: '101', guestName: 'Дмитрий Волков', checkIn: '2026-03-10', checkOut: '2026-03-12', totalAmount: 9000, paidAmount: 4500, nights: 2 }, { roomId: 'r2', roomNumber: '201', guestName: 'Игорь Соколов', checkIn: '2026-03-09', checkOut: '2026-03-11', totalAmount: 14000, paidAmount: 14000, nights: 2 }, { roomId: 'r3', roomNumber: '301', guestName: 'Наталья Александрова',checkIn: '2026-03-11', checkOut: '2026-03-15', totalAmount: 48000, paidAmount: 24000, nights: 4 }, { roomId: 'r4', roomNumber: '401', guestName: 'Михаил Орлов', checkIn: '2026-03-10', checkOut: '2026-03-13', totalAmount: 36000, paidAmount: 0, nights: 3 }, ] const PURPOSE_LABELS: Record = { stay: 'Проживание', breakfast: 'Завтрак', transfer: 'Трансфер', parking: 'Парковка', extra: 'Доп. услуга', } const QUICK_CHARGES: { purpose: ChargePurpose; label: string; amount: number | null; Icon: any }[] = [ { purpose: 'stay', label: 'Проживание', amount: null, Icon: Building2 }, { purpose: 'breakfast', label: 'Завтрак', amount: 650, Icon: Coffee }, { purpose: 'transfer', label: 'Трансфер', amount: 2500, Icon: Car }, { purpose: 'parking', label: 'Парковка', amount: 500, Icon: Package }, { purpose: 'extra', label: 'Доп. услуга', amount: null, Icon: Zap }, ] const SEED_RECEIPTS: ReceiptRecord[] = [ { id: 'rc1', roomNumber: '201', guestName: 'Игорь Соколов', purposeLabel: 'Проживание', amount: 14000, method: 'terminal', createdAt: new Date(Date.now() - 3600000 * 3), shiftId: 'shift-today' }, { id: 'rc2', roomNumber: '101', guestName: 'Дмитрий Волков', purposeLabel: 'Проживание', amount: 4500, method: 'cash', createdAt: new Date(Date.now() - 3600000 * 2), shiftId: 'shift-today' }, { id: 'rc3', roomNumber: '301', guestName: 'Наталья Александрова', purposeLabel: 'Проживание', amount: 24000, method: 'terminal', createdAt: new Date(Date.now() - 3600000), shiftId: 'shift-today' }, { id: 'rc4', roomNumber: '101', guestName: 'Дмитрий Волков', purposeLabel: 'Завтрак', amount: 1300, method: 'cash', createdAt: new Date(Date.now() - 1800000), shiftId: 'shift-today' }, ] // ── Component ───────────────────────────────────────────────────────────────── export function PosPage() { const [shiftOpen, setShiftOpen] = useState(true) const [shiftStartTime] = useState(new Date(Date.now() - 3600000 * 3)) const [shiftTimer, setShiftTimer] = useState('') const [receipts, setReceipts] = useState(SEED_RECEIPTS) const [selectedRoom, setSelectedRoom] = useState(MOCK_BALANCES[0]) const [purpose, setPurpose] = useState('stay') const [amount, setAmount] = useState(0) const [method, setMethod] = useState('terminal') const [notes, setNotes] = useState('') const [lastReceipt, setLastReceipt] = useState(null) const shiftId = 'shift-today' // Update amount when room or purpose changes useEffect(() => { if (!selectedRoom) { setAmount(0); return } if (purpose === 'stay') { setAmount(Math.max(0, selectedRoom.totalAmount - selectedRoom.paidAmount)) } else { const qc = QUICK_CHARGES.find(q => q.purpose === purpose) setAmount(qc?.amount ?? 0) } }, [selectedRoom, purpose]) // Shift timer useEffect(() => { if (!shiftOpen) return const tick = () => { const diff = Math.floor((Date.now() - shiftStartTime.getTime()) / 1000) const h = Math.floor(diff / 3600) const m = Math.floor((diff % 3600) / 60) const s = diff % 60 setShiftTimer(`${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`) } tick() const id = setInterval(tick, 1000) return () => clearInterval(id) }, [shiftOpen, shiftStartTime]) const shiftReceipts = receipts.filter(r => r.shiftId === shiftId) const shiftRevenue = shiftReceipts.reduce((s, r) => s + r.amount, 0) const cashRevenue = shiftReceipts.filter(r => r.method === 'cash').reduce((s, r) => s + r.amount, 0) const termRevenue = shiftReceipts.filter(r => r.method === 'terminal').reduce((s, r) => s + r.amount, 0) const handlePay = () => { if (!selectedRoom || amount <= 0 || !shiftOpen) return const rec: ReceiptRecord = { id: `rc-${Date.now()}`, roomNumber: selectedRoom.roomNumber, guestName: selectedRoom.guestName, purposeLabel: PURPOSE_LABELS[purpose], amount, method, createdAt: new Date(), shiftId, } setReceipts(prev => [rec, ...prev]) setLastReceipt(rec) setNotes('') } const balance = selectedRoom ? Math.max(0, selectedRoom.totalAmount - selectedRoom.paidAmount) : 0 const isPaid = selectedRoom ? selectedRoom.paidAmount >= selectedRoom.totalAmount : false return (
{/* ── Top bar ── */}

Касса

{format(new Date(), 'd MMMM yyyy', { locale: ru })} · Елена Смирнова

{shiftOpen && (
{shiftTimer}
)}
{/* Shift stats */} {shiftOpen && (
{[ { label: 'Выручка за смену', value: formatCurrency(shiftRevenue), color: 'text-slate-900 dark:text-slate-100' }, { label: 'Наличные', value: formatCurrency(cashRevenue), color: 'text-emerald-600 dark:text-emerald-400' }, { label: 'Терминал / АТОЛ', value: formatCurrency(termRevenue), color: 'text-blue-600 dark:text-blue-400' }, { label: 'Чеков', value: shiftReceipts.length, color: 'text-slate-900 dark:text-slate-100' }, ].map(s => (

{s.value}

{s.label}

))}
)}
{/* ── Shift closed ── */} {!shiftOpen ? (

Смена закрыта

Откройте смену для начала работы

) : (
{/* ── Left: active bookings ── */}

Активные заезды

{MOCK_BALANCES.map(rb => { const debt = Math.max(0, rb.totalAmount - rb.paidAmount) const paid = debt === 0 const sel = selectedRoom?.roomId === rb.roomId return ( ) })}
{/* ── Center: payment form ── */}
{selectedRoom ? ( <> {/* Guest info */}

{selectedRoom.guestName}

Номер {selectedRoom.roomNumber} · {selectedRoom.nights} {selectedRoom.nights === 1 ? 'ночь' : selectedRoom.nights < 5 ? 'ночи' : 'ночей'}

К оплате

{formatCurrency(balance)}

{/* Balance bar */}
Оплачено {formatCurrency(selectedRoom.paidAmount)} Всего {formatCurrency(selectedRoom.totalAmount)}
{/* Quick charge buttons */}

Назначение платежа

{QUICK_CHARGES.map(qc => ( ))}
{/* Amount */}
setAmount(Math.max(0, parseInt(e.target.value) || 0))} placeholder="0" />
{/* Payment method */}

Способ оплаты

{([ { key: 'cash', label: 'Наличные', Icon: Banknote, cls: 'emerald' }, { key: 'terminal', label: 'Терминал', Icon: CreditCard, cls: 'blue' }, { key: 'atol', label: 'АТОЛ', Icon: Printer, cls: 'violet' }, ] as const).map(m => ( ))}
{method === 'atol' && (

АТОЛ: интеграция будет настроена в разделе Настройки → Оборудование

)}
{/* Notes */}
setNotes(e.target.value)} />
{/* Pay button */} ) : (

Выберите гостя из списка слева

)}
{/* ── Right: receipts ── */}

Чеки за смену

{shiftReceipts.length}
{shiftReceipts.map(r => (
№{r.roomNumber}
{r.method === 'cash' ? : r.method === 'terminal' ? : } {format(r.createdAt, 'HH:mm')}

{r.guestName}

{r.purposeLabel} {formatCurrency(r.amount)}
))}
)} {/* ── Receipt success overlay ── */} {lastReceipt && (

Оплата принята

{formatCurrency(lastReceipt.amount)}

{lastReceipt.method === 'cash' ? 'Наличными' : lastReceipt.method === 'terminal' ? 'Терминал' : 'АТОЛ'} · {format(lastReceipt.createdAt, 'HH:mm')}

Гость {lastReceipt.guestName}
Номер №{lastReceipt.roomNumber}
Назначение {lastReceipt.purposeLabel}
)}
) }