'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 (
{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.
üzeri siparişlerde ücretsiz teslimat
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
İştah Açıcılar
Bu yemekler paylaşmak için idealdir
This section is next available for ordering on September 20th at 9:00AM.
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.
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.
İçecekler
This section is next available for ordering on September 20th at 9:00AM.
Sipariş vermeye hazır mısınız?
bottom of page