'Affogato', option: '', qty: 1, notes: 'Kahvesi bol dökülsün', status: 'Hazırlanıyor', time: Date.now() - 1200000, category: 'Bar' } ]); // Güvenlik & İşlem Logları const [auditLogs, setAuditLogs] = useState([ { id: 'log1', time: '12:30', user: 'Yönetici', action: 'Sistem yerel sunucu ağında başlatıldı.' }, { id: 'log2', time: '12:35', user: 'Garson Ahmet', action: 'Masa 2 için yeni sipariş girdi.' } ]); // Muhasebe & Depo Yönetim State'leri const [inventoryItems, setInventoryItems] = useState(INITIAL_INVENTORY_ITEMS); const [inventoryLogs, setInventoryLogs] = useState(INITIAL_INVENTORY_LOGS); const [expenses, setExpenses] = useState(INITIAL_EXPENSES); const [completedSales, setCompletedSales] = useState(INITIAL_COMPLETED_SALES); // Envanter Tanımlama State'i const [newInvItem, setNewInvItem] = useState({ name: '', category: 'Kahveler', initialStock: '', costPrice: '' }); // Envanter Hareket State'i (Sürekli Hızlı Stok Giriş/Çıkış Formu) const [stockMovement, setStockMovement] = useState({ itemId: '', type: 'Stok Girişi', qty: '', price: '', note: '' }); // Gider Ekleme State'i const [newExpense, setNewExpense] = useState({ title: '', amount: '', category: 'Günlük Alışveriş' }); // Admin PIN Onay Modalı (Hassas işlemler için) const [adminVerifyAction, setAdminVerifyAction] = useState(null); const [adminPinInput, setAdminPinInput] = useState(''); const [adminPinError, setAdminPinError] = useState(''); // Yönetici Paneli Görünümü Aktifliği const [showAdminPanel, setShowAdminPanel] = useState(false); const [adminTab, setAdminTab] = useState('menu'); // 'menu' | 'tables' | 'inventory' | 'expenses' | 'users' | 'logs' // Yeni Ürün Ekleme Form State'leri const [newProduct, setNewProduct] = useState({ name: '', category: 'Sıcak İçecekler', price: '', stock: '', options: '' }); // Yeni Masa Ekleme Form State'leri const [newTable, setNewTable] = useState({ name: '', section: 'İç Mekan' }); // Fiyat Hızlı Düzenleme State const [editingProductId, setEditingProductId] = useState(null); const [editingProductPrice, setEditingProductPrice] = useState(''); // Yeni Şifre Düzenleme State'leri const [editingRoleKey, setEditingRoleKey] = useState(null); const [newRolePinInput, setNewRolePinInput] = useState(''); const [rolePinError, setRolePinError] = useState(''); // Yeni Garson Ekleme State'i const [newWaiterName, setNewWaiterName] = useState(''); // Termal Fiş Yazıcı Simülatörü Modalı const [receiptData, setReceiptData] = useState(null); // İnaktivite Sayacı (30 Saniye) const [secondsRemaining, setSecondsRemaining] = useState(30); const timerRef = useRef(null); useEffect(() => { if (currentUser && currentUser.code !== roles.KITCHEN.code) { resetTimer(); timerRef.current = setInterval(() => { setSecondsRemaining(prev => { if (prev <= 1) { handleLogout(); return 30; } return prev - 1; }); }, 1000); } return () => { if (timerRef.current) clearInterval(timerRef.current); }; }, [currentUser, roles]); // Ekran tıklandığında süreyi sıfırla const handleUserActivity = () => { resetTimer(); }; const resetTimer = () => { setSecondsRemaining(30); }; const handleLogout = () => { setCurrentUser(null); setPinInput(''); setPinError(''); setSelectedTable(null); setPaymentTable(null); setShowAdminPanel(false); if (timerRef.current) clearInterval(timerRef.current); }; const handlePinSubmit = (e) => { e?.preventDefault(); const matchedRole = Object.values(roles).find(r => r.code === pinInput); if (matchedRole) { setCurrentUser(matchedRole); setPinInput(''); setPinError(''); addLog(matchedRole.name, 'Sistem oturumu açtı.'); } else { setPinError('Hatalı PIN Kodu! Lütfen tekrar deneyin.'); setPinInput(''); } }; const handlePinKeyPress = (num) => { setPinError(''); if (pinInput.length < 4) { setPinInput(prev => prev + num); } }; const addLog = (user, action) => { const timeString = new Date().toLocaleTimeString('tr-TR', { hour: '2-digit', minute: '2-digit', second: '2-digit' }); setAuditLogs(prev => [{ id: 'log_' + Date.now(), time: timeString, user, action }, ...prev]); }; const handleTableClick = (table) => { resetTimer(); if (currentUser.code === roles.KITCHEN.code) return; // Mutfak masalara müdahale edemez. setSelectedTable(table); setCurrentOrderCart(table.orders || []); }; const handleAddToOrderCart = (item) => { resetTimer(); if (item.stock <= 0) { alert("Bu ürünün stoğu kalmamıştır!"); return; } if (item.options && item.options.length > 0) { setSelectedItemForOptions(item); setSelectedOption(item.options[0]); } else { addToCartWithOption(item, ''); } }; const addToCartWithOption = (item, option) => { const optionExtraPrice = option.includes('+') ? parseInt(option.split('+')[1]) : 0; const finalPrice = item.price + optionExtraPrice; setCurrentOrderCart(prev => { const existing = prev.find(x => x.name === item.name && x.option === option); if (existing) { return prev.map(x => (x.name === item.name && x.option === option) ? { ...x, qty: x.qty + 1 } : x); } else { return [...prev, { name: item.name, price: finalPrice, option, qty: 1, notes: orderNotes }]; } }); setMenuItems(prev => prev.map(m => m.id === item.id ? { ...m, stock: m.stock - 1 } : m)); setOrderNotes(''); setSelectedItemForOptions(null); }; const handleUpdateCartQty = (index, delta) => { resetTimer(); const cartItem = currentOrderCart[index]; const menuItem = menuItems.find(m => m.name === cartItem.name); if (delta > 0 && menuItem && menuItem.stock <= 0) { alert("Yeterli stok yok!"); return; } setCurrentOrderCart(prev => { const updated = [...prev]; updated[index].qty += delta; if (updated[index].qty <= 0) { if (currentUser.code !== roles.ADMIN.code) { // Garson silmeye çalışırsa şifre isteyeceğiz setAdminVerifyAction({ actionType: 'DELETE_CART_ITEM', data: { index, cartItem } }); return prev; } else { addLog(currentUser.name, `${selectedTable.name} masasından ${cartItem.name} siparişi silindi.`); updated.splice(index, 1); } } return updated; }); if (menuItem) { setMenuItems(prev => prev.map(m => m.id === menuItem.id ? { ...m, stock: m.stock - delta } : m)); } }; const handleConfirmOrder = () => { resetTimer(); if (currentOrderCart.length === 0) return; const updatedTables = tables.map(t => { if (t.id === selectedTable.id) { const totalAmount = currentOrderCart.reduce((acc, curr) => acc + (curr.price * curr.qty), 0); return { ...t, status: 'Dolu', orders: currentOrderCart, waiter: selectedTable.waiter || currentUser.name, total: totalAmount }; } return t; }); const newKdsOrders = currentOrderCart.map(cart => ({ id: 'kds_' + Date.now() + '_' + Math.random(), tableName: selectedTable.name, item: cart.name, option: cart.option, qty: cart.qty, notes: cart.notes, status: 'Hazırlanıyor', time: Date.now(), category: ['Sıcak İçecekler', 'Türk Kahvesi', 'Çay'].some(k => cart.name.includes(k)) ? 'Mutfak' : 'Bar' })); setKdsOrders(prev => [...prev, ...newKdsOrders]); setTables(updatedTables); addLog(currentUser.name, `${selectedTable.name} için siparişleri onayladı. Atanan Garson: ${selectedTable.waiter || currentUser.name}, Toplam: ${currentOrderCart.reduce((a, b) => a + (b.price * b.qty), 0)}₺`); setSelectedTable(null); }; const handleAdminVerify = (e) => { e.preventDefault(); if (adminPinInput === roles.ADMIN.code) { if (adminVerifyAction.actionType === 'DELETE_CART_ITEM') { const { index, cartItem } = adminVerifyAction.data; setCurrentOrderCart(prev => prev.filter((_, idx) => idx !== index)); addLog('Yönetici Onaylı', `${selectedTable.name} masasından ${cartItem.name} iptal edildi.`); } else if (adminVerifyAction.actionType === 'APPLY_CUSTOM_DISCOUNT') { setDiscountPercent(adminVerifyAction.data); addLog('Yönetici Onaylı', `İndirim uygulandı: %${adminVerifyAction.data}`); } setAdminVerifyAction(null); setAdminPinInput(''); setAdminPinError(''); } else { setAdminPinError('Yönetici PIN hatalı!'); setAdminPinInput(''); } }; const handleOpenPayment = (table) => { resetTimer(); setPaymentTable(table); setDiscountPercent(0); setNumSplits(1); setRemainingSplitAmount(table.total); setPaymentHistory([]); }; const handlePayPartial = (type, amount) => { resetTimer(); const nextRemaining = remainingSplitAmount - amount; const historyEntry = { id: 'p_' + Date.now(), type, amount }; setPaymentHistory(prev => [...prev, historyEntry]); setRemainingSplitAmount(nextRemaining); if (nextRemaining <= 1) { finalizeReceipt(paymentTable, paymentHistory.concat(historyEntry), discountPercent); } }; const finalizeReceipt = (table, payments, discount) => { const discountedTotal = table.total * (1 - discount / 100); // Satış Detayını Raporlama İçin Kaydet const paymentMethodsText = payments.map(p => `${p.type} (${p.amount}₺)`).join(', '); const newSale = { id: 'sale_' + Date.now(), tableName: table.name, total: discountedTotal, paymentMethod: paymentMethodsText, date: new Date().toLocaleDateString('tr-TR') }; setCompletedSales(prev => [newSale, ...prev]); setReceiptData({ tableName: table.name, waiter: table.waiter, orders: table.orders, discount, total: table.total, finalTotal: discountedTotal, payments, date: new Date().toLocaleString('tr-TR') }); setTables(prev => prev.map(t => t.id === table.id ? { ...t, status: 'Boş', orders: [], waiter: '', total: 0 } : t)); addLog(currentUser.name, `${table.name} hesabı kapatıldı. Toplam tahsilat: ${discountedTotal}₺`); setPaymentTable(null); }; const handleKdsStatusChange = (orderId, newStatus) => { setKdsOrders(prev => prev.map(o => o.id === orderId ? { ...o, status: newStatus } : o)); const target = kdsOrders.find(o => o.id === orderId); if (target) { addLog('Mutfak/Bar', `${target.tableName} için ${target.item} ${newStatus === 'Hazır' ? 'Hazırlandı' : 'Teslim Edildi'}`); } }; // --- YÖNETİCİ GEREKSİNİMLERİ (Menü & Masa & Şifre İşlemleri) --- // 1. Yeni Ürün Ekleme const handleAddProductSubmit = (e) => { e.preventDefault(); if (!newProduct.name || !newProduct.price) { alert("Lütfen ürün adı ve fiyatını giriniz."); return; } const newId = 'm_' + Date.now(); const formattedOptions = newProduct.options ? newProduct.options.split(',').map(o => o.trim()) : []; const newItem = { id: newId, category: newProduct.category, name: newProduct.name, price: parseFloat(newProduct.price), stock: parseInt(newProduct.stock) || 100, options: formattedOptions }; setMenuItems(prev => [...prev, newItem]); addLog(currentUser.name, `YENİ ÜRÜN EKLEDİ: ${newProduct.name} - ${newProduct.price}₺`); setNewProduct({ name: '', category: 'Sıcak İçecekler', price: '', stock: '', options: '' }); }; // 2. Ürün Fiyatı Inline Düzenleme const startEditingPrice = (item) => { setEditingProductId(item.id); setEditingProductPrice(item.price.toString()); }; const saveProductPrice = (id) => { const priceNum = parseFloat(editingProductPrice); if (isNaN(priceNum) || priceNum <= 0) { alert("Geçersiz fiyat girdiniz!"); return; } setMenuItems(prev => prev.map(item => { if (item.id === id) { addLog(currentUser.name, `${item.name} ürününün fiyatını ${item.price}₺ -> ${priceNum}₺ olarak güncelledi.`); return { ...item, price: priceNum }; } return item; })); setEditingProductId(null); }; // 3. Ürün Silme const handleDeleteProduct = (id, name) => { if (window.confirm(`${name} ürününü menüden tamamen silmek istediğinizden emin misiniz?`)) { setMenuItems(prev => prev.filter(item => item.id !== id)); addLog(currentUser.name, `ÜRÜN SİLİNDİ: ${name}`); } }; // 4. Yeni Masa Ekleme const handleAddTableSubmit = (e) => { e.preventDefault(); if (!newTable.name) { alert("Lütfen bir masa ismi yazın."); return; } const newId = 't_' + Date.now(); const tableItem = { id: newId, name: newTable.name, section: newTable.section, status: 'Boş', orders: [], waiter: '', total: 0 }; setTables(prev => [...prev, tableItem]); addLog(currentUser.name, `YENİ MASA EKLEDİ: ${newTable.name} (${newTable.section})`); setNewTable({ name: '', section: 'İç Mekan' }); }; // 5. Masa Silme const handleDeleteTable = (id, name) => { if (window.confirm(`${name} masasını sistemden kaldırmak istiyor musunuz?`)) { setTables(prev => prev.filter(t => t.id !== id)); addLog(currentUser.name, `MASA SİLİNDİ: ${name}`); } }; // 6. Masa Garsonu Değiştirme const handleTableWaiterChange = (tableId, waiterName) => { setTables(prev => prev.map(t => { if (t.id === tableId) { addLog(currentUser.name, `${t.name} masasına yeni sorumlu garson atandı: ${waiterName || 'YOK'}`); return { ...t, waiter: waiterName }; } return t; })); }; // 7. PIN Güncelleme İşlemi const startEditingRolePin = (roleKey, currentPin) => { setEditingRoleKey(roleKey); setNewRolePinInput(currentPin); setRolePinError(''); }; const saveRolePin = (roleKey) => { // 4 Haneli Sayı Kontrolü const pinRegex = /^[0-9]{4}$/; if (!pinRegex.test(newRolePinInput)) { setRolePinError('Şifre tam olarak 4 haneli rakamdan oluşmalıdır!'); return; } // Şifre Çakışması Kontrolü const otherRolesUsingPin = Object.entries(roles).filter(([k, r]) => k !== roleKey && r.code === newRolePinInput); if (otherRolesUsingPin.length > 0) { setRolePinError('Bu şifre başka bir rol tarafından kullanılıyor!'); return; } setRoles(prev => { const updated = { ...prev }; updated[roleKey] = { ...updated[roleKey], code: newRolePinInput }; addLog(currentUser.name, `${updated[roleKey].name} rolünün terminal giriş şifresini güncelledi.`); // Eğer kendi şifresini güncellediyse aktif kullanıcın import React, { useState, useEffect, useRef } from 'react'; import { LogIn, LogOut, Utensils, ClipboardList, Layers, Settings, Users, CheckCircle, RefreshCw, Trash2, Plus, Minus, DollarSign, Clock, ShieldAlert, Award, FileText, ShoppingBag, Coffee, ChevronRight, AlertTriangle, Printer, Edit, Save, PlusCircle, X, UserCheck, TrendingUp, TrendingDown, Box, FileSpreadsheet, Calendar } from 'lucide-react'; // Orijinal "noc" Geometrisine Sahip Bağımsız, Kusursuz Yan Yana Logo Tasarımı (Overlapping Yoktur) function NocLogo({ className = "w-28 h-10", color = "currentColor", subtext = true }) { return (
{/* 'n' Harfi - Kusursuz Kemer Yapısı ve Düz Ayaklar */} {/* 'o' Harfi - Tam Çember, 'n' ile Eşit Boşlukta */} {/* 'c' Harfi - Sağ Tarafı Açık Çember, 'o' ile Eşit Boşlukta ve Kesişmesiz */} {subtext && ( coffee )}
); } // Noc Coffee Görsellerinden Aktarılan Eksiksiz Menü Verisi const NOC_MENU_ITEMS = [ // Sıcak Kahveler & İçecekler (Görsel 1) { id: 'm1', category: 'Sıcak İçecekler', name: 'Espresso', price: 150, stock: 100, options: ['Tek Shot', 'Duble (+35₺)', 'Farklı Süt (+35₺)'] }, { id: 'm2', category: 'Sıcak İçecekler', name: 'Espresso Macchiato', price: 160, stock: 80, options: ['Ekstra Şurup (+35₺)', 'Ekstra Shot (+35₺)'] }, { id: 'm3', category: 'Sıcak İçecekler', name: 'Espresso Caramel Macchiato', price: 180, stock: 85, options: ['Ekstra Şurup (+35₺)', 'Farklı Süt (+35₺)'] }, { id: 'm4', category: 'Sıcak İçecekler', name: 'Americano', price: 180, stock: 120, options: ['Ekstra Shot (+35₺)'] }, { id: 'm5', category: 'Sıcak İçecekler', name: 'Filter Coffee', price: 180, stock: 90, options: ['Sade', 'Sütlü (+15₺)', 'Farklı Süt (+35₺)'] }, { id: 'm6', category: 'Sıcak İçecekler', name: 'Cortado', price: 170, stock: 70, options: ['Normal', 'Farklı Süt (+35₺)'] }, { id: 'm7', category: 'Sıcak İçecekler', name: 'Flat White', price: 180, stock: 75, options: ['Normal', 'Farklı Süt (+35₺)'] }, { id: 'm8', category: 'Sıcak İçecekler', name: 'Latte', price: 190, stock: 150, options: ['Normal Süt', 'Farklı Süt (+35₺)', 'Ekstra Şurup (+35₺)'] }, { id: 'm9', category: 'Sıcak İçecekler', name: 'Caramel Latte', price: 200, stock: 100, options: ['Normal Süt', 'Farklı Süt (+35₺)'] }, { id: 'm10', category: 'Sıcak İçecekler', name: 'Lotus Latte', price: 200, stock: 80, options: ['Normal Süt', 'Farklı Süt (+35₺)'] }, { id: 'm11', category: 'Sıcak İçecekler', name: 'Cookie Latte', price: 200, stock: 80, options: ['Normal Süt', 'Farklı Süt (+35₺)'] }, { id: 'm12', category: 'Sıcak İçecekler', name: 'Hazzel Nut Latte', price: 200, stock: 85, options: ['Normal Süt', 'Farklı Süt (+35₺)'] }, { id: 'm13', category: 'Sıcak İçecekler', name: 'Vanilia Latte', price: 200, stock: 90, options: ['Normal Süt', 'Farklı Süt (+35₺)'] }, { id: 'm14', category: 'Sıcak İçecekler', name: 'Spanish Latte', price: 200, stock: 75, options: ['Normal Süt', 'Farklı Süt (+35₺)'] }, { id: 'm15', category: 'Sıcak İçecekler', name: 'Tiramisu Latte', price: 200, stock: 80, options: ['Normal Süt', 'Farklı Süt (+35₺)'] }, { id: 'm16', category: 'Sıcak İçecekler', name: 'Mocha', price: 210, stock: 95, options: ['Normal Süt', 'Farklı Süt (+35₺)'] }, { id: 'm17', category: 'Sıcak İçecekler', name: 'White Mocha', price: 210, stock: 90, options: ['Normal Süt', 'Farklı Süt (+35₺)'] }, { id: 'm18', category: 'Sıcak İçecekler', name: 'Hot Chocolate', price: 190, stock: 110, options: ['Normal Süt', 'Farklı Süt (+35₺)'] }, { id: 'm19', category: 'Sıcak İçecekler', name: 'Türk Kahvesi', price: 150, stock: 300, options: ['Sade', 'Az Şekerli', 'Orta', 'Şekerli'] }, { id: 'm20', category: 'Sıcak İçecekler', name: 'Damla Sakızlı Türk Kahvesi', price: 150, stock: 120, options: ['Sade', 'Az Şekerli', 'Orta', 'Şekerli'] }, { id: 'm21', category: 'Sıcak İçecekler', name: 'Dibek', price: 150, stock: 130, options: ['Sade', 'Az Şekerli', 'Orta', 'Şekerli'] }, { id: 'm22', category: 'Sıcak İçecekler', name: 'Çay', price: 90, stock: 600, options: ['Açık', 'Demli', 'Duble (+30₺)'] }, // Soğuk Kahveler & Frappeler (Görsel 3) { id: 'm23', category: 'Soğuk İçecekler', name: 'Iced Americano', price: 190, stock: 150, options: ['Ekstra Shot (+35₺)'] }, { id: 'm24', category: 'Soğuk İçecekler', name: 'Iced Latte', price: 200, stock: 180, options: ['Normal Süt', 'Farklı Süt (+35₺)', 'Ekstra Şurup (+35₺)'] }, { id: 'm25', category: 'Soğuk İçecekler', name: 'Iced Lotus Latte', price: 210, stock: 90, options: ['Farklı Süt (+35₺)'] }, { id: 'm26', category: 'Soğuk İçecekler', name: 'Iced Spanish Latte', price: 210, stock: 85, options: ['Farklı Süt (+35₺)'] }, { id: 'm27', category: 'Soğuk İçecekler', name: 'Iced Hazel Nut Latte', price: 210, stock: 80, options: ['Farklı Süt (+35₺)'] }, { id: 'm28', category: 'Soğuk İçecekler', name: 'Iced Vanilia Latte', price: 210, stock: 90, options: ['Farklı Süt (+35₺)'] }, { id: 'm29', category: 'Soğuk İçecekler', name: 'Iced Caramel Latte', price: 210, stock: 95, options: ['Farklı Süt (+35₺)'] }, { id: 'm30', category: 'Soğuk İçecekler', name: 'Iced Tiramisu Latte', price: 210, stock: 80, options: ['Farklı Süt (+35₺)'] }, { id: 'm31', category: 'Soğuk İçecekler', name: 'Frappe Chocolate', price: 210, stock: 100, options: ['Farklı Süt (+35₺)'] }, { id: 'm32', category: 'Soğuk İçecekler', name: 'Frappe White Chocolate', price: 210, stock: 95, options: ['Farklı Süt (+35₺)'] }, { id: 'm33', category: 'Soğuk İçecekler', name: 'Frappe Cookie', price: 210, stock: 100, options: ['Farklı Süt (+35₺)'] }, { id: 'm34', category: 'Soğuk İçecekler', name: 'Frappe Caramel', price: 210, stock: 105, options: ['Farklı Süt (+35₺)'] }, { id: 'm35', category: 'Soğuk İçecekler', name: 'Frappe Tiramisu', price: 210, stock: 90, options: ['Farklı Süt (+35₺)'] }, { id: 'm36', category: 'Soğuk İçecekler', name: 'Frappe Vanilia', price: 210, stock: 95, options: ['Farklı Süt (+35₺)'] }, { id: 'm37', category: 'Soğuk İçecekler', name: 'Frappe Hazel Nut Latte', price: 210, stock: 90, options: ['Farklı Süt (+35₺)'] }, { id: 'm38', category: 'Soğuk İçecekler', name: 'Frappe Lotus', price: 210, stock: 90, options: ['Farklı Süt (+35₺)'] }, { id: 'm39', category: 'Soğuk İçecekler', name: 'Affogato', price: 170, stock: 60, options: [] }, { id: 'm40', category: 'Soğuk İçecekler', name: 'Iced White Mocha', price: 220, stock: 85, options: ['Farklı Süt (+35₺)'] }, { id: 'm41', category: 'Soğuk İçecekler', name: 'Iced Mocha', price: 220, stock: 90, options: ['Farklı Süt (+35₺)'] }, // Frozen & Shake (Görsel 2) { id: 'm42', category: 'Frozen & Shake', name: 'Frozen', price: 210, stock: 200, options: ['Limon', 'Kavun', 'Vişne', 'Kivi', 'Yabanmersini', 'Şeftali', 'Mango', 'Yuju', 'Elma', 'Karpuz'] }, { id: 'm43', category: 'Frozen & Shake', name: 'Vanilya Shake', price: 210, stock: 100, options: [] }, { id: 'm44', category: 'Frozen & Shake', name: 'Chocoate Shake', price: 210, stock: 100, options: [] }, { id: 'm45', category: 'Frozen & Shake', name: 'Caramel Shake', price: 210, stock: 100, options: [] }, { id: 'm46', category: 'Frozen & Shake', name: 'Çilek Shake', price: 210, stock: 100, options: [] }, { id: 'm47', category: 'Frozen & Shake', name: 'Antep Shake', price: 210, stock: 80, options: [] }, { id: 'm48', category: 'Frozen & Shake', name: 'Oreo Shake', price: 230, stock: 90, options: [] }, { id: 'm49', category: 'Frozen & Shake', name: 'Lotus Shake', price: 230, stock: 85, options: [] }, // Özel Karışımlar (Görsel 2) { id: 'm50', category: 'Özel Karışımlar', name: 'Satori', price: 260, stock: 60, options: [] }, { id: 'm51', category: 'Özel Karışımlar', name: 'Berry Hibiscus', price: 200, stock: 120, options: [] }, { id: 'm52', category: 'Özel Karışımlar', name: 'Cool Lime', price: 200, stock: 150, options: [] }, { id: 'm53', category: 'Özel Karışımlar', name: 'Orangethelime', price: 220, stock: 110, options: [] }, { id: 'm54', category: 'Özel Karışımlar', name: 'Kensho', price: 260, stock: 65, options: [] }, { id: 'm55', category: 'Özel Karışımlar', name: 'Melonandmango', price: 220, stock: 100, options: [] }, { id: 'm56', category: 'Özel Karışımlar', name: 'Blue Glassy', price: 220, stock: 90, options: [] }, { id: 'm57', category: 'Özel Karışımlar', name: 'Peach For Sugar', price: 220, stock: 80, options: [] }, { id: 'm58', category: 'Özel Karışımlar', name: 'Likeatekila', price: 220, stock: 75, options: [] }, { id: 'm59', category: 'Özel Karışımlar', name: 'Applelian', price: 220, stock: 85, options: [] } ]; const INITIAL_TABLES = [ { id: 't1', name: 'Masa 1', section: 'İç Mekan', status: 'Boş', orders: [], waiter: '', total: 0 }, { id: 't2', name: 'Masa 2', section: 'İç Mekan', status: 'Dolu', orders: [ { name: 'Latte', price: 190, option: 'Farklı Süt (+35₺)', qty: 2, notes: 'Çok sıcak olsun' }, { name: 'Oreo Shake', price: 230, option: '', qty: 1, notes: '' } ], waiter: 'Garson Ahmet', total: 610 }, { id: 't3', name: 'Masa 3', section: 'İç Mekan', status: 'Hesap İstendi', orders: [ { name: 'Satori', price: 260, option: '', qty: 1, notes: '' }, { name: 'Türk Kahvesi', price: 150, option: 'Orta', qty: 1, notes: 'Yanında çifte kavrulmuş lokum' } ], waiter: 'Garson Ayşe', total: 410 }, { id: 't4', name: 'Masa 4', section: 'İç Mekan', status: 'Boş', orders: [], waiter: '', total: 0 }, { id: 't5', name: 'Masa 5', section: 'İç Mekan', status: 'Rezerve', orders: [], waiter: '', total: 0 }, { id: 't6', name: 'Bahçe 1', section: 'Bahçe', status: 'Boş', orders: [], waiter: '', total: 0 }, { id: 't7', name: 'Bahçe 2', section: 'Bahçe', status: 'Dolu', orders: [ { name: 'Espresso', price: 150, option: 'Duble (+35₺)', qty: 1, notes: '' }, { name: 'Affogato', price: 170, option: '', qty: 1, notes: 'Kahvesi bol dökülsün' } ], waiter: 'Garson Ahmet', total: 320 }, { id: 't8', name: 'Bahçe 3', section: 'Bahçe', status: 'Boş', orders: [], waiter: '', total: 0 }, { id: 't9', name: 'Teras 1', section: 'Teras', status: 'Dolu', orders: [ { name: 'Frappe Caramel', price: 210, option: '', qty: 2, notes: '' } ], waiter: 'Garson Ayşe', total: 420 }, { id: 't10', name: 'Teras 2', section: 'Teras', status: 'Boş', orders: [], waiter: '', total: 0 } ]; // Başlangıç Rol Şifreleri (Dinamik) const INITIAL_ROLES = { ADMIN: { code: '1111', name: 'Yönetici (Mert Bey)', permissions: ['all'] }, CASHIER: { code: '2222', name: 'Kasiyer Can', permissions: ['tables', 'payments', 'orders'] }, WAITER: { code: '3333', name: 'Garson Ahmet', permissions: ['tables', 'orders'] }, KITCHEN: { code: '4444', name: 'Mutfak / Şef', permissions: ['kds'] } }; const INITIAL_WAITER_LIST = ['Garson Ahmet', 'Garson Ayşe', 'Garson Mehmet', 'Garson Elif']; // Başlangıç Depo ve Gider Listeleri const INITIAL_INVENTORY_ITEMS = [ { id: 'inv1', name: 'Espresso Kahve Çekirdeği (kg)', stock: 15, costPrice: 420, category: 'Kahveler' }, { id: 'inv2', name: 'Sütaş Barista Sütü (Litre)', stock: 64, costPrice: 32, category: 'Sütler' }, { id: 'inv3', name: 'Monin Karamel Şurubu (Adet)', stock: 8, costPrice: 280, category: 'Şuruplar' }, { id: 'inv4', name: 'Karton Bardak 8oz (Koli)', stock: 3, costPrice: 650, category: 'Sarf Malzemesi' }, { id: 'inv5', name: 'Lotus Bisküvi Ezmesi (Kavanoz)', stock: 4, costPrice: 190, category: 'Mutfak Malzemesi' } ]; const INITIAL_INVENTORY_LOGS = [ { id: 'ilog1', itemId: 'inv1', type: 'Stok Girişi', qty: 10, price: 420, date: '19.05.2026', note: 'Özdemir Kahve Toptancısı' }, { id: 'ilog2', itemId: 'inv2', type: 'Stok Girişi', qty: 24, price: 32, date: '19.05.2026', note: 'Sütaş Yerel Dağıtıcı' }, { id: 'ilog3', itemId: 'inv3', type: 'Zayi Çıkışı', qty: 1, price: 280, date: '19.05.2026', note: 'Zayi: Şişe bar arkasında kırıldı' } ]; const INITIAL_EXPENSES = [ { id: 'exp1', title: 'Günlük Taze Pastane Alımları', amount: 850, category: 'Günlük Alışveriş', date: '19.05.2026' }, { id: 'exp2', title: 'Dükkan Elektrik Faturası', amount: 5400, category: 'Fatura', date: '18.05.2026' }, { id: 'exp3', title: 'Barista Temizlik Malzemeleri', amount: 320, category: 'Temizlik', date: '19.05.2026' } ]; // Satış Raporu İçin Kapatılan Adisyonların Hafızası const INITIAL_COMPLETED_SALES = [ { id: 'sale1', tableName: 'Masa 4', total: 480, paymentMethod: 'Kredi Kartı', date: '19.05.2026' }, { id: 'sale2', tableName: 'Bahçe 1', total: 310, paymentMethod: 'Nakit', date: '19.05.2026' } ]; export default function App() { const [currentUser, setCurrentUser] = useState(null); const [pinInput, setPinInput] = useState(''); const [pinError, setPinError] = useState(''); // Dinamik Şifreler, Roller ve Personel State'leri const [roles, setRoles] = useState(INITIAL_ROLES); const [waiters, setWaiters] = useState(INITIAL_WAITER_LIST); const [tables, setTables] = useState(INITIAL_TABLES); const [menuItems, setMenuItems] = useState(NOC_MENU_ITEMS); const [activeSection, setActiveSection] = useState('İç Mekan'); const [selectedTable, setSelectedTable] = useState(null); // Sipariş Kurguları const [activeCategory, setActiveCategory] = useState('Sıcak İçecekler'); const [currentOrderCart, setCurrentOrderCart] = useState([]); const [selectedItemForOptions, setSelectedItemForOptions] = useState(null); const [selectedOption, setSelectedOption] = useState(''); const [orderNotes, setOrderNotes] = useState(''); // Ödeme Ekranı Kurguları const [paymentTable, setPaymentTable] = useState(null); const [discountPercent, setDiscountPercent] = useState(0); const [numSplits, setNumSplits] = useState(1); const [remainingSplitAmount, setRemainingSplitAmount] = useState(0); const [paymentHistory, setPaymentHistory] = useState([]); // KDS (Mutfak Siparişleri) const [kdsOrders, setKdsOrders] = useState([ { id: 'kds1', tableName: 'Masa 2', item: 'Latte', option: 'Farklı Süt (+35₺)', qty: 2, notes: 'Çok sıcak olsun', status: 'Hazırlanıyor', time: Date.now() - 600000, category: 'Bar' }, { id: 'kds2', tableName: 'Bahçe 2', item:
top of page

There’s Nothing Here...

We can’t find the page you’re looking for.
Check the URL, or head back home.

551 179 1899 

Yeni İnsanları Anında Keşfedin! Sadece parmağınızı kaydırarak video üzerinden dünyanın dört bir yanından milyonlarca yeni insanla yüz yüze tanışın.

  • White Facebook Icon
  • White Twitter Icon
  • White YouTube Icon
bottom of page