'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

Online Sipariş

Online sipariş verebilirsiniz! Menümüze göz atın ve sipariş vermek istediğiniz ögeleri seçin.

Siparişe Açık

Teslimat ücreti -

Minimum sipariş - ₺0,00

üzeri siparişlerde ücretsiz teslimat

Gel Al

Adrese Teslimat

Restoranda Servis

Gel al zamanı: 30 dakikaya kadar

Gel Al Adresi: 500 Terry Francine Street, San Francisco, CA 94158

Akşam Yemeği Menüsü

Her gün 18.00-23.00 arasında servis edilir

Arranged Food and Objects

İştah Açıcılar

Bu yemekler paylaşmak için idealdir

This section is next available for ordering on September 20th at 9:00AM.

Arranged Food and Objects

Ana Yemekler

Hepsi yerel ve günlük olarak temin edilen çok çeşitli lezzetler

This section is next available for ordering on September 20th at 9:00AM.

Arranged Food and Objects

Tatlılar

Tatlılarımız kendi mutfağımızda pasta şefimiz tarafından yapılır

This section is next available for ordering on September 20th at 9:00AM.

Arranged Food and Objects

İçecekler

This section is next available for ordering on September 20th at 9:00AM.

Sipariş vermeye hazır mısınız?

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