// TableModal.jsx — Masa sipariş yönetimi
const { useState, useEffect, useRef } = React;
function TableModal({ tableId, tables, onClose, onUpdate, lang, user }) {
const T = window.TRANS[lang];
const table = tables.find(t => t.id === tableId);
if (!table) return null;
const isWaiter = user && user.role === 'waiter';
// Empty tables now ALWAYS start with an explicit "Masayı Aç" confirm step,
// regardless of role. From there:
// waiter user → 'opening' (auto open)
// admin user → 'waiter' (pick a name)
const initialStep = table.occupied ? 'order' : 'confirm';
const [step, setStep] = useState(initialStep);
const [activeCat, setActiveCat] = useState(null);
const [showPayment, setShowPayment] = useState(false);
const [showReceipt, setShowReceipt] = useState(null);
// Waiter pick is only shown to admin; waiters auto-open with their own name.
const waiters = Store.getUsers().filter(u => u.role === 'waiter' && u.active);
const menu = Store.getMenu().filter(m => m.active);
const categories = Store.getCategories().filter(c => menu.some(m => m.cat === c));
useEffect(() => {
if (!activeCat && categories.length) setActiveCat(categories[0]);
}, []);
// When we enter the 'opening' step (waiter clicked "Masayı Aç"),
// open the table on the server with their own name.
useEffect(() => {
if (step !== 'opening') return;
let cancelled = false;
(async () => {
try {
const updated = await Store.openTable(table.id, user.name);
if (cancelled) return;
onUpdate(updated);
setStep('order');
} catch (e) {
if (!cancelled) onClose();
}
})();
return () => { cancelled = true; };
}, [step]);
const orders = table.orders || [];
const total = orders.reduce((s, o) => s + o.price * o.qty, 0);
const catItems = menu.filter(m => m.cat === activeCat);
const handleWaiterSelect = async (name) => {
const updated = await Store.openTable(table.id, name);
onUpdate(updated);
setStep('order');
};
const handleAddItem = async (item) => {
const updated = await Store.addOrderItem(table.id, { id: item.id, name: item.name, price: item.price });
onUpdate(updated);
};
const handleRemove = async (itemId) => {
const updated = await Store.removeOrderItem(table.id, itemId);
onUpdate(updated);
};
const handlePayment = async (method) => {
const t = tables.find(x => x.id === tableId);
const receipt = {
tableName: t.name, waiter: t.waiter,
items: [...t.orders], total, method,
closedAt: new Date(),
};
const updated = await Store.closeTable(table.id, method);
onUpdate(updated);
setShowPayment(false);
setShowReceipt(receipt);
};
const handleCancel = async () => {
const updated = await Store.cancelTable(table.id);
onUpdate(updated);
onClose();
};
// React to live updates that change the table state remotely.
useEffect(() => {
if (showReceipt || showPayment) return;
if (step === 'order' && !table.occupied) {
onClose();
} else if ((step === 'waiter' || step === 'opening' || step === 'confirm') && table.occupied) {
setStep('order');
}
}, [table.occupied]);
// "Masayı Aç" pressed on the confirm screen.
const handleOpenPress = () => {
if (isWaiter) {
setStep('opening');
} else {
setStep('waiter');
}
};
// Empty table — explicit "Masayı Aç" confirm.
if (step === 'confirm') {
return (
e.stopPropagation()}>
{isWaiter
? <>Masa {user.name} adına açılacak.>
: <>Masayı aç ve garson seç.>}
);
}
if (step === 'opening') {
return (
);
}
if (showReceipt) {
return (
e.stopPropagation()}>
🧾
{showReceipt.tableName}
{showReceipt.waiter} • {showReceipt.method === 'cash' ? T.cash : T.card}
{showReceipt.items.map(item => (
{item.qty}x {item.name}
{fmt(item.price * item.qty)}
))}
{T.total}
{fmt(showReceipt.total)}
);
}
if (showPayment) {
return (
setShowPayment(false)}>
e.stopPropagation()}>
{T.confirmPayment}
{T.total}: {fmt(total)}
);
}
if (step === 'waiter') {
return (
e.stopPropagation()}>
{table.name}
Masayı kim açıyor?
{waiters.length === 0 ? (
Aktif garson yok. Yönetim → Kullanıcılar'dan ekle.
) : waiters.map(w => (
))}
);
}
return (
e.stopPropagation()}>
{table.name}
{T.waiter}: {table.waiter}
{table.openedAt && ⏱ {elapsed(table.openedAt)}}
{/* ✕ alone — destructive actions live in the order panel footer
so an accidental tap on close doesn't free the table. */}
{categories.map(cat => (
))}
{catItems.map(item => {
const inOrder = orders.find(o => o.id === item.id);
const qty = inOrder ? inOrder.qty : 0;
return (
handleAddItem(item)}
style={{
padding: '12px 10px', borderRadius: 10, border: '1.5px solid',
borderColor: qty > 0 ? 'var(--accent)' : 'var(--border)',
background: qty > 0 ? 'var(--accent-light)' : 'var(--surface)',
cursor: 'pointer', fontFamily: 'inherit', transition: 'all 0.15s',
display: 'flex', flexDirection: 'column',
userSelect: 'none', WebkitTapHighlightColor: 'transparent',
}}>
{item.name}
{fmt(item.price)}
{qty > 0 && (
e.stopPropagation()}
style={{
display: 'flex', alignItems: 'center', justifyContent: 'space-between',
marginTop: 10, paddingTop: 10,
borderTop: '1px solid rgba(232,89,12,0.25)',
gap: 8,
}}>
{qty}
)}
);
})}
Sipariş ({orders.length} ürün)
{orders.length === 0 ? (
{T.noOrders}
) : orders.map(o => (
{o.name}
{fmt(o.price)} × {o.qty}
{fmt(o.price * o.qty)}
))}
{T.total}
{fmt(total)}
{orders.length > 0 ? (
) : (
)}
);
}
Object.assign(window, { TableModal });