'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
Her gün 18.00-23.00 arasında servis edilir
Bu yemekler paylaşmak için idealdir
Ekşi maya ekmek yanında humus, pancar ve yoğurtlu beyaz peynir dip sos
Mevsim yeşillikleri ve kavrulmuş bademli yeşil salata
Mühürlenmiş taze ton balığı, taze otlar ve hafif bir acılık
Hepsi yerel ve günlük olarak temin edilen çok çeşitli lezzetler
Fesleğenli pesto sosu içinde peynir karışımı dolgulu el yapımı geleneksel ravyoli
Yer Fıstıklı Çıtır Biftek
Buharda pişmiş sebzeler eşliğinde servis edilen, damak zevkinize göre pişirilmiş yumuşak ve sulu biftek
Kuşkonmaz ve tatlı patates kreması eşliğinde günlük tutulmuş balık
Soya ve susam karışımında marine edilmiş ızgara tofu şiş, mevsim sebzeleri eşliğinde
Marul, turşu, ata tohumu domates eşliğinde klasik burgerimiz, yanında kızarmış patates
Baharat ve parmesan ile kaplı, çıtır çıtır ve altın gibi kızarmış
Tatlılarımız kendi mutfağımızda pasta şefimiz tarafından yapılır
Hurmalı Islak Kek ve Dondurma
Vanilyalı dondurma, karamela sosu ve yer fıstığı parçaları ile servis edilir
Üzerinde ahududu reçeli ve çilek dilimleri ile servis edilir
Krem şanti ile sevis edilen antep fıstığı parçaları ile süslü limonlu mereng
Hafif ancak yoğun lezzetli, ünlü çikolatalı mus tatlımız
Krem peyniri kremalı, hafif baharatlı havuçlu kek
Bitter çikolata parçacıklı ve cevizli, fırından yeni çıkmış brownie
Sağlıklı smoothie çeşitlerimizle vücudunuzu besleyin
Taze sıkılmış portakal, karpuz, havuç ve zencefil karışımı
Soda, Sprite, Pepsi ve Diyet Kola
Aperol Spritz, Cin Tonik, Mojito
bottom of page