import React, { useState } from 'react'; import { useDemoStore, PosCartItem } from '../../mock/store'; import { INITIAL_CATALOG } from '../../mock/mockData'; import { Button, Badge, MaturityBadge, Modal, useToast } from '../../shared/ui'; import { formatCurrency } from '../../shared/utils/formatters'; import { Search, Plus, Minus, Trash2, CreditCard, Banknote, QrCode, Receipt, CheckCircle2, User, Printer, ChevronDown, AlertCircle, } from 'lucide-react'; const SUGGESTED_CUSTOMERS = [ { name: 'Александр Романов', phone: '+7 (913) 900-11-22', tag: 'VIP • Скидка 10%' }, { name: 'Елена Морозова', phone: '+7 (923) 456-78-90', tag: 'Постоянный гость' }, { name: 'Михаил Васильев', phone: '+7 (905) 111-22-33', tag: 'Бонусная карта 5%' }, { name: 'ООО Альфа Консалт', phone: '+7 (383) 200-40-50', tag: 'B2B безнал' }, ]; export const PosView: React.FC = () => { const { showToast } = useToast(); const { posCart, addToCart, removeFromCart, updateCartQuantity, clearCart, posDiscountPercent, setPosDiscount, posCustomerName, setPosCustomer, posOrderType, setPosOrderType, posTableNumber, setPosTableNumber, posPaymentModalOpen, setPosPaymentModalOpen, posLastReceipt, completeCheckout, getActiveProfile, activeLocation, } = useDemoStore(); const profile = getActiveProfile(); const [selectedCategory, setSelectedCategory] = useState('Все'); const [searchQuery, setSearchQuery] = useState(''); const [showReceiptModal, setShowReceiptModal] = useState(false); const [showCustomerPicker, setShowCustomerPicker] = useState(false); // Split payment state const [isSplitMode, setIsSplitMode] = useState(false); const [splitCashAmount, setSplitCashAmount] = useState(0); const [splitCardAmount, setSplitCardAmount] = useState(0); const categories = ['Все', 'Роллы', 'Горячее', 'Супы', 'Автоуслуги', 'Автосервис']; const filteredItems = INITIAL_CATALOG.filter((item) => { const matchesCat = selectedCategory === 'Все' || item.category === selectedCategory; const matchesSearch = item.name.toLowerCase().includes(searchQuery.toLowerCase()); return matchesCat && matchesSearch; }); const subtotal = posCart.reduce((sum, item) => sum + item.price * item.quantity, 0); const discountAmount = (subtotal * posDiscountPercent) / 100; const totalAmount = Math.max(0, subtotal - discountAmount); const handlePayClick = () => { if (posCart.length === 0) return; setIsSplitMode(false); setPosPaymentModalOpen(true); }; const handleInitiateSplit = () => { const half = Math.round(totalAmount / 2); setSplitCashAmount(half); setSplitCardAmount(totalAmount - half); setIsSplitMode(true); }; const handleConfirmSplitPayment = () => { if (splitCashAmount + splitCardAmount !== totalAmount) return; setPosPaymentModalOpen(false); setIsSplitMode(false); completeCheckout('split'); setShowReceiptModal(true); }; const handlePaymentSelect = (method: 'cash' | 'card' | 'qr' | 'split') => { if (method === 'split') { handleInitiateSplit(); return; } setPosPaymentModalOpen(false); completeCheckout(method); setShowReceiptModal(true); }; const handlePrintReceipt = () => { showToast({ title: 'Печать фискального чека', message: `Чек ${posLastReceipt?.orderNumber || ''} отправлен на кассовый регистратор (Атол 54-Ф)`, type: 'success', }); }; const remainingToSplit = totalAmount - (splitCashAmount + splitCardAmount); return (
{/* Left: Product Catalog Grid */}
{/* Filter bar */}
{categories.map((cat) => ( ))}
setSearchQuery(e.target.value)} placeholder="Поиск по названию..." className="w-full pl-8 pr-3 py-1.5 text-xs bg-krona-workspace border border-krona-border rounded-lg text-krona-primary placeholder:text-krona-secondary focus:outline-none focus:border-krona-green" />
{/* Products Grid */}
{filteredItems.map((item) => { const inCart = posCart.find((c) => c.id === item.id); const isStop = item.isStopListed; return (
!isStop && addToCart(item)} className={`group relative p-3.5 rounded-xl border flex flex-col justify-between transition-all select-none ${ isStop ? 'opacity-50 border-krona-danger/40 bg-krona-danger/5 cursor-not-allowed' : 'cursor-pointer border-krona-border bg-krona-surface hover:border-krona-green/60 hover:shadow-krona-soft active:scale-[0.99]' } ${inCart ? 'ring-2 ring-krona-green/40' : ''}`} >
{item.category} {isStop ? ( Стоп-лист ) : inCart ? ( {inCart.quantity} в чеке ) : null}

{item.name}

{item.description && (

{item.description}

)}
{formatCurrency(item.price)} Себест: {item.cost} ₽ ({item.marginPercent}%)
); })}
{/* Right: Cart & Order Register Panel */}
{/* Order settings header */}
Текущий чек
{activeLocation}
{/* Customer picker */}
setPosCustomer(e.target.value)} placeholder="Клиент / Выбрать..." className="w-full bg-transparent focus:outline-none text-xs text-krona-primary" />
{posOrderType === 'hall' && (
setPosTableNumber(e.target.value)} placeholder="Стол..." className="w-full px-2 py-1 bg-krona-workspace border border-krona-border rounded-md text-xs text-krona-primary text-center font-medium focus:outline-none" />
)}
{/* Quick Customer Picker Dropdown */} {showCustomerPicker && (
Быстрый выбор клиента CRM
{SUGGESTED_CUSTOMERS.map((cust, idx) => ( ))}
)}
{/* Cart items list */}
{posCart.length === 0 ? (
Чек пуст. Добавьте позиции из каталога слева.
) : ( posCart.map((item) => (
{item.name}
{formatCurrency(item.price)} × {item.quantity} = {formatCurrency(item.price * item.quantity)}
{item.quantity}
)) )}
{/* Discount & Totals */}
{/* Quick Discounts */}
Скидка:
{[0, 5, 10, 15, 20].map((pct) => ( ))}
Сумма позиций: {formatCurrency(subtotal)}
{posDiscountPercent > 0 && (
Скидка ({posDiscountPercent}%): -{formatCurrency(discountAmount)}
)}
К оплате: {formatCurrency(totalAmount)}
{/* Modal: Payment Method Selection & Split Payment */} { setPosPaymentModalOpen(false); setIsSplitMode(false); }} title={isSplitMode ? "Смешанная оплата (Наличные + Карта)" : "Оплата заказа"} subtitle={`Сумма к оплате: ${formatCurrency(totalAmount)}`} maxWidth="md" > {!isSplitMode ? (

Выберите способ расчета клиента на кассе точки «{activeLocation}»:

) : (
Общая сумма к оплате: {formatCurrency(totalAmount)}

Распределите сумму между наличным расчетом и банковской картой:

{ const val = Math.max(0, Number(e.target.value)); setSplitCashAmount(val); setSplitCardAmount(Math.max(0, totalAmount - val)); }} className="w-full p-2 bg-krona-surface border border-krona-border rounded-lg font-mono font-bold text-sm text-krona-primary focus:outline-none focus:border-krona-green" />
{ const val = Math.max(0, Number(e.target.value)); setSplitCardAmount(val); setSplitCashAmount(Math.max(0, totalAmount - val)); }} className="w-full p-2 bg-krona-surface border border-krona-border rounded-lg font-mono font-bold text-sm text-krona-primary focus:outline-none focus:border-krona-green" />
{/* Balance check indicator */}
{remainingToSplit === 0 ? ( <> Сумма распределена верно (100%) ) : ( <> {remainingToSplit > 0 ? `Не распределено: ${formatCurrency(remainingToSplit)}` : `Переплата: ${formatCurrency(Math.abs(remainingToSplit))}`} )}
{formatCurrency(splitCashAmount + splitCardAmount)} / {formatCurrency(totalAmount)}
)}
{/* Modal: Fiscal Receipt Details */} {showReceiptModal && posLastReceipt && ( setShowReceiptModal(false)} title="Чек успешно пробит!" subtitle={`Заказ ${posLastReceipt.orderNumber} • ${posLastReceipt.timestamp}`} maxWidth="sm" footer={
} >
{profile.companyName}
{posLastReceipt.location}
Касса №1 • Смена открыта
{posLastReceipt.items.map((it: PosCartItem, i: number) => (
{it.name} × {it.quantity} {formatCurrency(it.price * it.quantity)}
))}
Сумма: {formatCurrency(posLastReceipt.subtotal)}
{posLastReceipt.discount > 0 && (
Скидка: -{formatCurrency(posLastReceipt.discount)}
)}
ИТОГ К ОПЛАТЕ: {formatCurrency(posLastReceipt.total)}
Способ оплаты: {posLastReceipt.paymentType}
{posLastReceipt.customer && (
Клиент: {posLastReceipt.customer}
)}
ФП (фискальный признак): ФП: 49204910283
ФН: 996044030198 • РН ККТ: 00049281001
Спасибо за заказ в «{profile.companyName}»!
)}
); };