import React, { useState, useEffect } from 'react'; import { Coffee, Settings, Barcode, CreditCard, Users, Printer, Plus, Minus, Trash2, Search, Check, Sparkles, TrendingUp, Package, Clock, UtensilsCrossed, Sliders, FileSpreadsheet, Tv, Bell, ChefHat, Database, Building2, HardDrive, Download, FolderOpen, MapPin, Lock, Unlock, AlertTriangle, RefreshCw, Smartphone, Tablet, QrCode, Tags, CheckCircle2, UserCheck, RotateCcw } from 'lucide-react'; const BRAND_SETTINGS = { businessName: "La Greenzaa", subBranding: "Restaurant & Cafe", developerBrand: "Umang Developers", currency: "₹", taxRate: 5, enableServiceCharge: true, serviceChargePercent: 2.5 }; const currencySymbol = BRAND_SETTINGS.currency; const INITIAL_PRODUCTS = [ { id: 'p1', name: 'Premium Espresso', category: 'Hot Coffee', price: 120, costPrice: 30, tax: '5%', sku: 'HOT-ESP-01', image: '☕', stockOnHand: 80, committedStock: 0, availableForSale: 80, openingStock: 100, unit: 'pcs', manufacturer: 'La Greenzaa Farms', reorderPoint: 15 }, { id: 'p2', name: 'Classic Cappuccino', category: 'Hot Coffee', price: 150, costPrice: 40, tax: '5%', sku: 'HOT-CAP-02', image: '☕', stockOnHand: 120, committedStock: 4, availableForSale: 116, openingStock: 150, unit: 'pcs', manufacturer: 'La Greenzaa Farms', reorderPoint: 20 }, { id: 'p3', name: 'Irish Cold Coffee', category: 'Cold Coffee', price: 180, costPrice: 50, tax: '12%', sku: 'CLD-COF-03', image: '🥤', stockOnHand: 140, committedStock: 20, availableForSale: 120, openingStock: 200, unit: 'pcs', manufacturer: 'La Greenzaa Roasters', reorderPoint: 30 }, { id: 'p4', name: 'Lemon Infusion Iced Tea', category: 'Teas & Infusions', price: 120, costPrice: 25, tax: '5%', sku: 'TEA-LIT-04', image: '🍹', stockOnHand: 95, committedStock: 5, availableForSale: 90, openingStock: 100, unit: 'pcs', manufacturer: 'Nectar Teas', reorderPoint: 10 }, { id: 'p5', name: 'Mango Blast Smoothie', category: 'Smoothies', price: 210, costPrice: 60, tax: '12%', sku: 'SMO-MAN-05', image: '🥭', stockOnHand: 60, committedStock: 2, availableForSale: 58, openingStock: 80, unit: 'pcs', manufacturer: 'La Greenzaa Orchard', reorderPoint: 8 }, { id: 'p6', name: 'Avocado Cream Smoothie', category: 'Smoothies', price: 250, costPrice: 80, tax: '12%', sku: 'SMO-AVO-06', image: '🥑', stockOnHand: 45, committedStock: 0, availableForSale: 45, openingStock: 50, unit: 'pcs', manufacturer: 'La Greenzaa Orchard', reorderPoint: 5 }, { id: 'p7', name: 'Paneer Tikka Pizza', category: 'Pizzas', price: 250, costPrice: 90, tax: '12%', sku: 'PIZ-PTP-09', image: '🍕', stockOnHand: 50, committedStock: 10, availableForSale: 40, openingStock: 60, unit: 'pcs', manufacturer: 'La Greenzaa Main Kitchen', reorderPoint: 12 }, { id: 'p8', name: 'Dark Chocolate Cake', category: 'Baked Goods', price: 180, costPrice: 55, tax: '5%', sku: 'BAK-DCC-12', image: '🍫', stockOnHand: 40, committedStock: 2, availableForSale: 38, openingStock: 50, unit: 'pcs', manufacturer: 'La Greenzaa Bakery', reorderPoint: 6 } ]; const CATEGORIES = ['All Items', 'Hot Coffee', 'Cold Coffee', 'Teas & Infusions', 'Smoothies', 'Baked Goods', 'Pizzas']; const INITIAL_CUSTOMERS = [ { id: 'c1', name: "Mr. Devesh Rajguru", phone: "+91 99092 12345", outstandingBalance: 200.00, loyaltyPoints: 340, email: "devesh@rajguru.com" }, { id: 'c2', name: "Aarav Patel", phone: "+91 98765 11223", outstandingBalance: 0.00, loyaltyPoints: 120, email: "aarav@patel.com" }, { id: 'c3', name: "Neha Sharma", phone: "+91 91122 33445", outstandingBalance: 150.00, loyaltyPoints: 450, email: "neha@sharma.in" } ]; class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false, error: null }; } static getDerivedStateFromError(error) { return { hasError: true, error }; } componentDidCatch(error, errorInfo) { console.error("ErrorBoundary caught a runtime exception:", error, errorInfo); } render() { if (this.state.hasError) { return (

La Greenzaa POS Lifecycle Recovery

The application state experienced a validation error. Click below to restore database properties back to original defaults.

); } return this.props.children; } } function POSApp() { // --- APPLICATION STATE DIRECTORIES --- // roles: kiosk | qr_ordering | waiter | biller | kds | status | owner | inventory const [currentRole, setCurrentRole] = useState('kiosk'); // Data State Pools const [products, setProducts] = useState(INITIAL_PRODUCTS); const [orders, setOrders] = useState([]); const [customers, setCustomers] = useState(INITIAL_CUSTOMERS); const [selectedInventoryItem, setSelectedInventoryItem] = useState(null); const [selectedCustomer, setSelectedCustomer] = useState(INITIAL_CUSTOMERS[0]); // Terminal Cart Pools const [kioskCart, setKioskCart] = useState([]); const [waiterCart, setWaiterCart] = useState([]); const [cashierCart, setCashierCart] = useState([]); const [qrCart, setQrCart] = useState([]); // Modifiers System const [activeModifierItem, setActiveModifierItem] = useState(null); // { cartKey, modifiers: [] } const [showModifierModal, setShowModifierModal] = useState(false); const [tempModifiers, setTempModifiers] = useState([]); // Waiter Dedicated Variables const [waiterTable, setWaiterTable] = useState('Table 1'); const [waiterGuestName, setWaiterGuestName] = useState('Table Guest'); // Kiosk Specific Navigation Flow const [kioskMode, setKioskMode] = useState('welcome'); // welcome | select-dining-mode | select-table | catalog | finished const [kioskDiningMode, setKioskDiningMode] = useState('Dine-In Self-Service'); const [kioskTable, setKioskTable] = useState('Table 1'); const [kioskPaymentMode, setKioskPaymentMode] = useState('Pay at Counter'); const [kioskLastOrder, setKioskLastOrder] = useState(null); // Table QR Self-Ordering Simulator State const [qrTable, setQrTable] = useState('Table 3'); const [qrOrderPlaced, setQrOrderPlaced] = useState(false); // Cashier Terminal Specific States const [selectedUnpaidKioskOrder, setSelectedUnpaidKioskOrder] = useState(null); const [cashierSearchQuery, setCashierSearchQuery] = useState(''); const [cashierSelectedCategory, setCashierSelectedCategory] = useState('All Items'); const [activeCategory, setActiveCategory] = useState('All Items'); const [billingOrderType, setBillingOrderType] = useState('Walk-In'); // New Smart Recall Tracking State const [recalledOrderId, setRecalledOrderId] = useState(null); const [orderRecallFilter, setOrderRecallFilter] = useState(''); // PIN Locking System (Owner: 8888, Inventory: 9999) const [pinInput, setPinInput] = useState(''); const [securityTarget, setSecurityTarget] = useState(null); // 'owner' | 'inventory' const [authorizedOwner, setAuthorizedOwner] = useState(false); const [authorizedInventory, setAuthorizedInventory] = useState(false); const [lockErrorMessage, setLockErrorMessage] = useState(''); // KOT Thermal Printer Dialog const [activeKOTPrint, setActiveKOTPrint] = useState(null); const [showPrintModal, setShowPrintModal] = useState(false); // Custom Notifications / Alert Box const [systemAlert, setSystemAlert] = useState(null); // { type: 'success'|'error', text: '' } // Customer registration state (Biller-accessible) const [showRegisterCustomerModal, setShowRegisterCustomerModal] = useState(false); const [newCustName, setNewCustName] = useState(''); const [newCustPhone, setNewCustPhone] = useState(''); const [newCustEmail, setNewCustEmail] = useState(''); // KDS Advanced Station Filtering & Recalled order reference const [kdsStationFilter, setKdsStationFilter] = useState('All Stations'); const [recentlyCompletedOrder, setRecentlyCompletedOrder] = useState(null); // Barcode Printer Modal const [selectedBarcodeItem, setSelectedBarcodeItem] = useState(null); const [showBarcodePrintModal, setShowBarcodePrintModal] = useState(false); // Custom Deletion Confirmation Modal State const [confirmDeleteId, setConfirmDeleteId] = useState(null); // --- OFFLINE DATA LOAD ON MOUNT --- useEffect(() => { try { const storedCatalog = localStorage.getItem('lg_catalog_state_v3'); const storedOrders = localStorage.getItem('lg_orders_state_v3'); const storedCustomers = localStorage.getItem('lg_customers_state_v3'); if (storedCatalog) { const parsedCatalog = JSON.parse(storedCatalog); if (parsedCatalog && parsedCatalog.length > 0) { setProducts(parsedCatalog); setSelectedInventoryItem(parsedCatalog[0]); } } else { setProducts(INITIAL_PRODUCTS); setSelectedInventoryItem(INITIAL_PRODUCTS[0]); } if (storedOrders) { const parsedOrders = JSON.parse(storedOrders); if (parsedOrders) setOrders(parsedOrders); } else { setOrders([ { id: 'ord-101', tokenNo: 101, items: [{ name: 'Classic Cappuccino', quantity: 2, price: 150, modifiers: ['No Sugar', 'Keep Vegan'] }], grandTotal: 300, customerName: 'Mr. Devesh Rajguru', orderType: 'Dine-In Self-Service', tableNo: 'Table 4', status: 'Pending', timestamp: '10:12 AM', station: 'Beverage Bar', paid: true, createdAt: Date.now() - 360000 }, { id: 'ord-102', tokenNo: 102, items: [{ name: 'Paneer Tikka Pizza', quantity: 1, price: 250, modifiers: ['Extra Cheese'] }], grandTotal: 250, customerName: 'Aarav Patel', orderType: 'Takeaway Parcel', tableNo: 'N/A', status: 'Cooking', timestamp: '10:20 AM', station: 'Main Kitchen', paid: false, createdAt: Date.now() - 120000 } ]); } if (storedCustomers) { const parsedCustomers = JSON.parse(storedCustomers); if (parsedCustomers) setCustomers(parsedCustomers); } else { setCustomers(INITIAL_CUSTOMERS); } } catch (e) { console.error("Local sync bypassed safely: ", e); } }, []); const saveStateToStorage = (updatedCatalog, updatedOrders, updatedCustomers) => { try { if (updatedCatalog) localStorage.setItem('lg_catalog_state_v3', JSON.stringify(updatedCatalog)); if (updatedOrders) localStorage.setItem('lg_orders_state_v3', JSON.stringify(updatedOrders)); if (updatedCustomers) localStorage.setItem('lg_customers_state_v3', JSON.stringify(updatedCustomers)); } catch (e) { console.error("Local writes failed: ", e); } }; const showNotification = (text, type = 'success') => { setSystemAlert({ text, type }); setTimeout(() => setSystemAlert(null), 4500); }; const [timerTick, setTimerTick] = useState(0); useEffect(() => { const interval = setInterval(() => { setTimerTick(prev => prev + 1); }, 1000); return () => clearInterval(interval); }, []); const getElapsedTimeText = (createdAt) => { if (!createdAt) return "00:00"; const elapsedSeconds = Math.floor((Date.now() - createdAt) / 1000); if (elapsedSeconds < 0) return "00:00"; const minutes = Math.floor(elapsedSeconds / 60); const seconds = elapsedSeconds % 60; return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; }; // --- AUDIO ALERTS --- const triggerAudioChime = () => { try { const audioCtx = new (window.AudioContext || window.webkitAudioContext)(); const osc = audioCtx.createOscillator(); const gainNode = audioCtx.createGain(); osc.connect(gainNode); gainNode.connect(audioCtx.destination); osc.type = 'sine'; osc.frequency.setValueAtTime(587.33, audioCtx.currentTime); // D5 osc.frequency.setValueAtTime(698.46, audioCtx.currentTime + 0.15); // F5 gainNode.gain.setValueAtTime(0.08, audioCtx.currentTime); gainNode.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 0.35); osc.start(); osc.stop(audioCtx.currentTime + 0.35); } catch (e) { console.log("Audio alert chime executed."); } }; // --- REAL-TIME OFFLINE DATA EXPORT BACKUPS --- const handleDownloadStats = () => { try { const fileReport = { meta: { brand: BRAND_SETTINGS.businessName, developer: BRAND_SETTINGS.developerBrand, timestamp: new Date().toISOString(), format: "La Greenzaa Central Sales Audit Backup" }, financials: { grossMonthlySales: 445790.00, ordersProcessed: orders?.length || 0, inventoryUniqueSKUs: products?.length || 0 }, ordersLedger: orders, activeInventoryLevels: products, registeredCustomers: customers }; const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(fileReport, null, 2)); const downloadAnchor = document.createElement('a'); downloadAnchor.setAttribute("href", dataStr); downloadAnchor.setAttribute("download", `la_greenzaa_offline_report_${new Date().toISOString().split('T')[0]}.json`); document.body.appendChild(downloadAnchor); downloadAnchor.click(); downloadAnchor.remove(); showNotification("SaaS offline backup logs generated and downloaded!"); } catch (err) { console.error("Backup log write failed:", err); showNotification("Log write exception occurred", "error"); } }; const handleVerifyPINSubmit = (e) => { e.preventDefault(); if (securityTarget === 'owner' && pinInput === '8888') { setAuthorizedOwner(true); setCurrentRole('owner'); setSecurityTarget(null); setLockErrorMessage(''); showNotification("Authorized Owner Panel Successfully."); } else if (securityTarget === 'inventory' && pinInput === '9999') { setAuthorizedInventory(true); setCurrentRole('inventory'); setSecurityTarget(null); setLockErrorMessage(''); showNotification("Authorized Inventory Suite Successfully."); } else { setLockErrorMessage('Incorrect Passcode. Access Restricted.'); setPinInput(''); } }; const handleSwitchDeviceRole = (role) => { if (role === 'owner') { if (authorizedOwner) setCurrentRole('owner'); else { setSecurityTarget('owner'); setPinInput(''); setLockErrorMessage(''); } } else if (role === 'inventory') { if (authorizedInventory) setCurrentRole('inventory'); else { setSecurityTarget('inventory'); setPinInput(''); setLockErrorMessage(''); } } else { setCurrentRole(role); } }; // --- MULTI-TERMINAL CART MANAGERS --- const getDeviceCart = (role) => { if (role === 'kiosk') return kioskCart; if (role === 'waiter') return waiterCart; if (role === 'cashier') return cashierCart; if (role === 'qr_ordering') return qrCart; return []; }; const getDeviceCartSetter = (role) => { if (role === 'kiosk') return setKioskCart; if (role === 'waiter') return setWaiterCart; if (role === 'cashier') return setCashierCart; if (role === 'qr_ordering') return setQrCart; return () => {}; }; const handleAddCartItemWithModifiers = (product, role) => { const cart = getDeviceCart(role); const setCart = getDeviceCartSetter(role); const cartKey = `${product.id}-${Date.now()}`; const newCartItem = { cartKey, product, quantity: 1, modifiers: [] }; setCart([...cart, newCartItem]); // Open modifiers selection box setActiveModifierItem({ cartKey, role, modifiers: [] }); setTempModifiers([]); setShowModifierModal(true); }; const handleApplyModifiers = () => { if (!activeModifierItem) return; const setCart = getDeviceCartSetter(activeModifierItem.role); setCart(prev => prev.map(item => { if (item.cartKey === activeModifierItem.cartKey) { return { ...item, modifiers: tempModifiers }; } return item; })); setShowModifierModal(false); setActiveModifierItem(null); showNotification("Preparation modifiers applied successfully!"); }; const handleUpdateCartQuantity = (cartKey, delta, role) => { const cart = getDeviceCart(role); const setCart = getDeviceCartSetter(role); const updated = cart.map(item => { if (item.cartKey === cartKey) { const nextQty = item.quantity + delta; return nextQty > 0 ? { ...item, quantity: nextQty } : null; } return item; }).filter(Boolean); setCart(updated); }; const handleRemoveItemFromCart = (cartKey, role) => { const setCart = getDeviceCartSetter(role); setCart(prev => prev.filter(item => item.cartKey !== cartKey)); }; // Safe Math Aggregates const calculateAggregateBill = (cart) => { if (!cart || cart.length === 0) { return { subtotal: 0, tax: 0, serviceCharge: 0, grandTotal: 0, roundOff: 0 }; } const subtotal = cart.reduce((sum, item) => sum + (item.product.price * item.quantity), 0); const tax = Math.round((subtotal * 0.05) * 100) / 100; const serviceCharge = Math.round((subtotal * 0.025) * 100) / 100; const rawTotal = subtotal + tax + serviceCharge; const grandTotal = Math.round(rawTotal); const roundOff = Math.round((grandTotal - rawTotal) * 100) / 100; return { subtotal, tax, serviceCharge, grandTotal, roundOff }; }; const kioskTotals = calculateAggregateBill(kioskCart); const waiterTotals = calculateAggregateBill(waiterCart); const cashierTotals = calculateAggregateBill(cashierCart); const qrTotals = calculateAggregateBill(qrCart); const handleExecuteCheckout = (role, paymentMethod, type, tableNum = 'N/A', name = 'Walk-In Guest', explicitlyUnpaid = false) => { const cart = getDeviceCart(role); const setCart = getDeviceCartSetter(role); if (cart.length === 0) return; const totals = calculateAggregateBill(cart); // Decrement local inventory stock const updatedProducts = products.map(p => { const match = cart.find(c => c.product.id === p.id); if (match) { const newOnHand = Math.max(0, p.stockOnHand - match.quantity); return { ...p, stockOnHand: newOnHand, availableForSale: Math.max(0, newOnHand - p.committedStock) }; } return p; }); const tokenNo = orders.length > 0 ? Math.max(...orders.map(o => o.tokenNo)) + 1 : 101; const timestamp = new Date().toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true }); const newKOT = { id: `ord-${Date.now()}`, tokenNo, items: cart.map(item => ({ name: item.product.name, quantity: item.quantity, price: item.product.price, modifiers: item.modifiers || [] })), grandTotal: totals.grandTotal, customerName: name, orderType: type, tableNo: tableNum, status: explicitlyUnpaid ? 'Pending Payment' : 'Pending', timestamp, station: cart.some(c => c.product.category === 'Pizzas') ? 'Main Kitchen' : 'Beverage Bar', paid: !explicitlyUnpaid, createdAt: Date.now() }; const updatedOrders = [...orders, newKOT]; // Update Loyalty points if matched with a registered customer const updatedCustomers = customers.map(cust => { if (cust.name === name) { return { ...cust, loyaltyPoints: cust.loyaltyPoints + Math.round(totals.grandTotal / 10) }; } return cust; }); setProducts(updatedProducts); setOrders(updatedOrders); setCustomers(updatedCustomers); saveStateToStorage(updatedProducts, updatedOrders, updatedCustomers); if (role === 'kiosk') { setKioskLastOrder(newKOT); setKioskMode('finished'); setKioskCart([]); } else if (role === 'qr_ordering') { setQrOrderPlaced(true); setQrCart([]); } else { // If we are settling a recalled order at Biller desk, mark the original pending order as settled/completed if (role === 'cashier' && recalledOrderId) { setOrders(prev => prev.map(o => o.id === recalledOrderId ? { ...o, status: 'Pending', paid: true } : o)); setRecalledOrderId(null); } setActiveKOTPrint(newKOT); setShowPrintModal(true); setCart([]); } showNotification(`Token #${tokenNo} submitted successfully!`); }; // Smart Recall Order Handler const handleSmartRecallOrder = (order) => { // 1. Convert order items to cashier cart schema const loadedCart = order.items.map(item => { const matchedProduct = products.find(p => p.name === item.name) || products[0]; return { cartKey: `${matchedProduct.id}-${Date.now()}-${Math.random()}`, product: matchedProduct, quantity: item.quantity, modifiers: item.modifiers || [] }; }); setCashierCart(loadedCart); setBillingOrderType(order.orderType); setRecalledOrderId(order.id); // 2. Auto-bind table configuration if table service if (order.tableNo && order.tableNo !== 'N/A') { setWaiterTable(order.tableNo); } // 3. Smart Search & Bind Loyalty Profile by Name or Contact Phone const matchedCustomer = customers.find(c => c.name.toLowerCase().includes(order.customerName.toLowerCase()) || (order.customerPhone && c.phone.includes(order.customerPhone)) || c.phone.includes(order.customerName) ); if (matchedCustomer) { setSelectedCustomer(matchedCustomer); showNotification(`Order Recalled & Linked to Loyalty Account: ${matchedCustomer.name}`); } else { setSelectedCustomer(customers[0]); // Fallback to Default Guest Account showNotification(`Order Recalled. Guest account auto-assigned.`); } }; // Cashier Settle Pending Kiosk Orders const handleSettleUnpaidKioskOrder = (orderId) => { const updated = orders.map(o => { if (o.id === orderId) { return { ...o, status: 'Pending', paid: true }; } return o; }); setOrders(updated); setSelectedUnpaidKioskOrder(null); saveStateToStorage(products, updated, customers); showNotification("Kiosk order paid successfully! Routed to Kitchen Display."); }; const handleRegisterCustomerSubmit = (e) => { e.preventDefault(); if (!newCustName || !newCustPhone) { showNotification("Name and Phone are mandatory.", "error"); return; } const isDuplicate = customers.some(c => c.phone === newCustPhone); if (isDuplicate) { showNotification("A loyalty account with this phone number already exists.", "error"); return; } const newProfile = { id: `c-${Date.now()}`, name: newCustName, phone: newCustPhone, email: newCustEmail || "N/A", outstandingBalance: 0.00, loyaltyPoints: 50 // Signup welcome points }; const updatedCustomers = [...customers, newProfile]; setCustomers(updatedCustomers); setSelectedCustomer(newProfile); // Auto-bind as the selected billing customer saveStateToStorage(products, orders, updatedCustomers); // Reset form states setNewCustName(''); setNewCustPhone(''); setNewCustEmail(''); setShowRegisterCustomerModal(false); showNotification(`Registered loyalty account: ${newProfile.name}!`); }; // KDS State Transition Handlers with Recalled Safety Cache const handleKdsCompleteTicket = (orderId) => { const orderToMark = orders.find(o => o.id === orderId); if (orderToMark) { setRecentlyCompletedOrder(orderToMark); } handleUpdateOrderStatus(orderId, 'Completed'); showNotification("KDS Ticket Completed."); }; const handleKdsRecallCompletedTicket = () => { if (!recentlyCompletedOrder) { showNotification("No recently completed order to recall.", "error"); return; } handleUpdateOrderStatus(recentlyCompletedOrder.id, 'Ready'); setRecentlyCompletedOrder(null); showNotification("Re-opened recently completed order!"); }; // Add Item (Inventory Dashboard) const handleAddCatalogItem = (e) => { e.preventDefault(); const fd = new FormData(e.target); const newProduct = { id: `p-${Date.now()}`, name: fd.get('name') || 'Fresh Item', category: fd.get('category') || 'Hot Coffee', price: parseFloat(fd.get('price')) || 100, costPrice: parseFloat(fd.get('costPrice')) || 30, tax: fd.get('tax') || '5%', sku: fd.get('sku') || 'SKU-NEW', image: fd.get('image') || '☕', stockOnHand: parseInt(fd.get('stock')) || 50, committedStock: 0, availableForSale: parseInt(fd.get('stock')) || 50, openingStock: parseInt(fd.get('stock')) || 50, unit: 'pcs', manufacturer: 'La Greenzaa Farms', reorderPoint: 10 }; const updatedProducts = [newProduct, ...products]; setProducts(updatedProducts); saveStateToStorage(updatedProducts, orders, customers); e.target.reset(); showNotification("Product saved successfully to master database."); }; const handleConfirmRemoveProduct = (id) => { setConfirmDeleteId(id); }; const executeDeleteProduct = () => { if (!confirmDeleteId) return; const updatedProducts = products.filter(p => p.id !== confirmDeleteId); setProducts(updatedProducts); saveStateToStorage(updatedProducts, orders, customers); setConfirmDeleteId(null); showNotification("Product deleted from catalog."); }; return (
{/* ========================================================= */} {/* SYSTEM HEADER AND SCREEN SELECTOR */} {/* ========================================================= */}
La Greenzaa - Terminal Simulator Developed by Umang Developers
{/* Global Notifications Alert Widget */} {systemAlert && (
{systemAlert.text}
)}
{/* ========================================================= */} {/* SCREEN CONTAINER */} {/* ========================================================= */}
{/* ========================================================= */} {/* ROLE 1: SELF SERVICE KIOSK SCREEN */} {/* ========================================================= */} {currentRole === 'kiosk' && (
{/* WELCOME VIEW */} {kioskMode === 'welcome' && (

Welcome to La Greenzaa

Restaurant & Cafe

Skip the cashier queue! Customize, select your dining table and mode, and place orders directly below.

)} {/* CHOOSE DINING MODE */} {kioskMode === 'select-dining-mode' && (

Select Your Dining Preference

Would you like to dine inside or package a parcel takeaway?

)} {/* SELECT DINE-IN TABLE SCREEN */} {kioskMode === 'select-table' && (

Select Your Dining Table Number

Please select an available dining table from the map layout below.

{[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].map(num => ( ))}
)} {/* KIOSK CATALOG VIEW */} {kioskMode === 'catalog' && (
{/* Touch menu lists */}
Mode Selected {kioskDiningMode} {kioskDiningMode === 'Dine-In Self-Service' && `(${kioskTable})`}
{/* Horiz category slider */}
{CATEGORIES.map(cat => ( ))}
{products.filter(p => activeCategory === 'All Items' || p.category === activeCategory).map(prod => (
handleAddCartItemWithModifiers(prod, 'kiosk')} className="bg-slate-950 border border-slate-850 hover:border-emerald-700 rounded-2xl p-4 flex flex-col justify-between cursor-pointer transition-all active:scale-95 group" >
{prod.image}

{prod.name}

{prod.sku}
Price: {currencySymbol}{prod.price}
))}
{/* Right Side Kiosk Cart */}
Order summary
Method: {kioskDiningMode}
{kioskDiningMode === 'Dine-In Self-Service' && (
Table: {kioskTable}
)}
{kioskCart.map(item => (
{item.product.name} {currencySymbol}{item.product.price} each
{item.quantity}
{item.modifiers?.length > 0 && (
{item.modifiers.map((mod, i) => ( {mod} ))}
)}
))}
{/* Settlement */}
Total Due: {currencySymbol}{kioskTotals.grandTotal}
)} {/* ORDER SUBMITTED TICKET GENERATION SCREEN */} {kioskMode === 'finished' && kioskLastOrder && (

Order Logged Successfully!

TOKEN {kioskLastOrder.tokenNo}
Dining Style: {kioskLastOrder.orderType}
{kioskLastOrder.tableNo !== 'N/A' && (
Allocated Table: {kioskLastOrder.tableNo}
)}
Total Invoice: {currencySymbol}{kioskLastOrder.grandTotal}
{/* Action prompts */}
{kioskLastOrder.paid ? (

🟢 Paid Successfully: Your order has routed directly to the kitchen display boards. Please watch the large TV Signage Wall Display. Once your token sounds, pick up your plate.

) : (

⚠️ Action Required (Settle at Biller): Please take your printed token ticket to the Biller Cashier Terminal. Once you pay, your order will route to the kitchen displays and television signage queue.

)}
)}
)} {/* ========================================================= */} {/* ROLE 2: TABLE QR SELF-ORDERING SIMULATOR */} {/* ========================================================= */} {currentRole === 'qr_ordering' && (
Table QR Scan Simulator Live ordering from private mobile device
Select Scanned Table QR:
{!qrOrderPlaced ? (
{CATEGORIES.map(cat => ( ))}
{products.filter(p => activeCategory === 'All Items' || p.category === activeCategory).map(prod => (
handleAddCartItemWithModifiers(prod, 'qr_ordering')} className="bg-slate-950 border border-slate-855 hover:border-emerald-700 rounded-2xl p-4 flex flex-col justify-between cursor-pointer transition-all active:scale-95 group" >
{prod.image}

{prod.name}

Price: {currencySymbol}{prod.price}
))}
Live Table Cart Orders sync instantly to kitchen display and television monitors
{qrCart.map(item => (
{item.product.name} {currencySymbol}{item.product.price} each
{item.quantity}
{item.modifiers?.length > 0 && (
{item.modifiers.map((mod, i) => ( {mod} ))}
)}
))}
Subtotal: {currencySymbol}{qrTotals.subtotal}
) : (

QR Order Placed successfully!

Your order has been routed instantly to the kitchen KDS. Please monitor the signage wall display for status updates.

)}
)} {/* ========================================================= */} {/* ROLE 3: TABLE-SIDE WAITER TABLET */} {/* ========================================================= */} {currentRole === 'waiter' && (
{/* Catalog (8 columns) */}

Waiter Hand-held Tablet

Allocate orders, select dining table mappings, and manage custom modifiers.

Select Active Table:
{/* Grid of items */}
{products.map(prod => (
handleAddCartItemWithModifiers(prod, 'waiter')} className="bg-slate-950 border border-slate-855 hover:border-emerald-700 rounded-2xl p-4 flex flex-col justify-between cursor-pointer transition-all active:scale-95 group" >
{prod.image}

{prod.name}

{prod.sku}
Price: {currencySymbol}{prod.price}
))}
{/* Right columns (4 columns) */}
Table order details
{waiterTable}
setWaiterGuestName(e.target.value)} />
{waiterCart.map(item => (
{item.product.name} {currencySymbol}{item.product.price} each
{item.quantity}
{item.modifiers?.length > 0 && (
{item.modifiers.map((mod, i) => ( {mod} ))}
)}
))}
Guest Total: {currencySymbol}{waiterTotals.subtotal}
)} {/* ========================================================= */} {/* ROLE 4: POS CASHIER TERMINAL (BILLER DESK) */} {/* ========================================================= */} {currentRole === 'biller' && (
{/* Left Column POS list (8 columns) */}
{/* SMART RECALL QUEUE PANEL */}
Smart Pending Order Recaller Fetch, modify, and assign loyalty accounts to any pending Kiosk or QR bill without re-adding items
setOrderRecallFilter(e.target.value)} />
{orders.filter(o => { const matchesUnpaid = o.status === 'Pending Payment' || !o.paid; const matchesQuery = o.tokenNo.toString().includes(orderRecallFilter) || o.customerName.toLowerCase().includes(orderRecallFilter.toLowerCase()) || o.tableNo.toLowerCase().includes(orderRecallFilter.toLowerCase()); return matchesUnpaid && matchesQuery; }).map(o => (
handleSmartRecallOrder(o)} className={`p-3 rounded-xl border cursor-pointer min-w-[230px] flex flex-col justify-between transition-all ${ recalledOrderId === o.id ? 'bg-emerald-950/40 border-emerald-500 shadow-md ring-1 ring-emerald-500/30' : 'bg-slate-900 border-slate-855 hover:border-slate-700' }`} >
Token #{o.tokenNo} {o.tableNo !== 'N/A' ? `Dining: ${o.tableNo}` : o.orderType}
{o.items.length} Items
Guest: {o.customerName} {currencySymbol}{o.grandTotal}
))} {orders.filter(o => o.status === 'Pending Payment' || !o.paid).length === 0 && ( No active unpaid or recalled tickets pending in the local pipeline... )}
{/* Standard POS catalog search and Customer bind */}
setSearchQuery(e.target.value)} />
{/* Select Loyalty Customer & Add Customer Button */}
Link Loyalty Account: {/* Option to Register/Add Customer Profile */}
{/* POS Category Tabs */}
{CATEGORIES.map(cat => ( ))}
{/* Grid of items */}
{products.filter(p => { const matchesCategory = cashierSelectedCategory === 'All Items' || p.category === cashierSelectedCategory; const matchesSearch = p.name.toLowerCase().includes(cashierSearchQuery.toLowerCase()); return matchesCategory && matchesSearch; }).map(prod => (
handleAddCartItemWithModifiers(prod, 'cashier')} className="bg-slate-950 border border-slate-855 hover:border-emerald-700 rounded-2xl p-3 flex flex-col justify-between cursor-pointer transition-all active:scale-95" >
{prod.image}

{prod.name}

{prod.sku}
Price: {currencySymbol}{prod.price}
))}
{/* Right Billing Desk columns (4 columns) */}
{/* Customer ledger tracking */}
{selectedCustomer.name} {selectedCustomer.phone}
Loyalty Points Balance: {selectedCustomer.loyaltyPoints} PTS
{/* Items loaded */}
{cashierCart.map(item => (
{item.product.name} {currencySymbol}{item.product.price} each
{item.quantity}
{currencySymbol}{(item.product.price * item.quantity).toFixed(2)}
{item.modifiers?.length > 0 && (
{item.modifiers.map((mod, i) => ( {mod} ))}
)}
))}
{/* Calculations Summary */}
Subtotal: {currencySymbol}{cashierTotals.subtotal.toFixed(2)}
Tax (5% GST Included): {currencySymbol}{cashierTotals.tax.toFixed(2)}
Round Off: {currencySymbol}{cashierTotals.roundOff.toFixed(2)}
Total Due: {currencySymbol}{cashierTotals.grandTotal.toFixed(2)}
{/* Checkout triggers */}
)} {/* ========================================================= */} {/* ROLE 5: KITCHEN DISPLAY MONITOR (KDS) - PROFESSIONAL UPGRADE */} {/* ========================================================= */} {currentRole === 'kds' && (
{/* Upgrade Dashboard Header */}

Advanced KDS Command Board Pro Upgrade

Preparation tickets categorized by station, monitored with real-time elapsed timers.

{/* Station Filter & Recall controls */}
{['All Stations', 'Beverage Bar', 'Main Kitchen'].map(station => ( ))}
{recentlyCompletedOrder && ( )}
{/* KDS Active Tickets Grid */}
{orders.filter(o => { const isNotCompleted = o.status !== 'Completed' && o.status !== 'Pending Payment'; const matchesStation = kdsStationFilter === 'All Stations' || o.station === kdsStationFilter; return isNotCompleted && matchesStation; }).map(o => { const elapsedSeconds = o.createdAt ? Math.floor((Date.now() - o.createdAt) / 1000) : 0; const isDelayed = elapsedSeconds > 300; // Trigger delay state after 5 mins return (
{/* Header with real-time timers */}
TOKEN #{o.tokenNo} {o.tableNo !== 'N/A' ? o.tableNo : o.orderType}
{/* Real time timer ticker */}
{getElapsedTimeText(o.createdAt)}
{/* Ticket list with interactive crossed-off checkboxes */}
{o.items.map((it, idx) => (
{it.name} {it.quantity}x
{it.modifiers?.length > 0 && (
{it.modifiers.map((mod, i) => ( {mod} ))}
)}
))}
{o.status === 'Pending' && ( )} {o.status === 'Cooking' && ( )} {o.status === 'Ready' && (
⌛ Pending Server Pickup
)}
); })} {orders.filter(o => { const isNotCompleted = o.status !== 'Completed' && o.status !== 'Pending Payment'; const matchesStation = kdsStationFilter === 'All Stations' || o.station === kdsStationFilter; return isNotCompleted && matchesStation; }).length === 0 && (

Kitchen prep board is fully cleared!

)}
)} {/* ========================================================= */} {/* ROLE 5: TV DISPLAY SIGNAGE WALL MONITOR */} {/* ========================================================= */} {currentRole === 'status' && (
Live Dining Hall Screen

Guest pickup & Waiter dispatch monitor

{/* Left Column: Customer self pickup parcel status */}

Self-Service Pickup Status

Pickup your order when your Token turns green
{/* Preparing list */}
Preparing ⏳
{orders.filter(o => o.status !== 'Completed' && (o.orderType.includes('Self-Service') || o.orderType.includes('Takeaway')) && (o.status === 'Pending' || o.status === 'Cooking')).map(o => (
Token {o.tokenNo}
))}
{/* Ready list */}
Ready for Pickup 📦
{orders.filter(o => o.status !== 'Completed' && (o.orderType.includes('Self-Service') || o.orderType.includes('Takeaway')) && o.status === 'Ready').map(o => (
Token {o.tokenNo}
))}
{/* Right Column: Waiter table serve alerts */}

Dining Tables Dispatch

Waiters: Dispatch plates to tables as soon as they sound
{orders.filter(o => o.status !== 'Completed' && o.orderType.includes('Table Service') && o.status === 'Ready').map(o => (
{o.tableNo} READY TO SERVE
{o.items.map((it, idx) => (
- {it.name} ({it.quantity}x)
))}
))} {orders.filter(o => o.status !== 'Completed' && o.orderType.includes('Table Service') && o.status === 'Ready').length === 0 && (

No active dining table dispatch calls

)}
)} {/* ========================================================= */} {/* ROLE 6: SECURE AUTHORIZED OWNER BACKOFFICE */} {/* ========================================================= */} {currentRole === 'owner' && authorizedOwner && (
Enterprise Owner Backoffice Dashboard

{BRAND_SETTINGS.businessName} Analytics and Loyalty Hub

{/* Data downloaders */}
{/* Simulated executive metrics */}
Gross Sales Value ₹4,45,790.00 ✓ Profit margin: 76.5%
Active Orders Pipeline {orders.filter(o => o.status !== 'Completed').length} Orders ↗ Live Transit Routing
Top Selling Category Hot Coffee ☕ Best hour: 4 PM - 7 PM
Loyalty Accounts {customers.length} Accounts ✓ GST Invoices Settled
{/* Split layout: Customers ledger (Left) vs insights (Right) */}
Customer Loyalty Ledger Centralized database
{customers.map(c => ( ))}
Customer Name Phone Loyalty Points O/S Balance
{c.name} {c.phone} {c.loyaltyPoints} PTS {currencySymbol}{c.outstandingBalance.toFixed(2)}
{/* Insights Column */}

Business Health Insights

Category Optimization

Hot Coffee and Smoothies constitute 78% of your total sales. Consider running loyalty combos on low-margin baked goods during morning slots.

Peak Performance Hours

Footfall peak occurs at 4:30 PM. Ensuring self-service kiosks and Table QR order scanners are fully optimized reduces front counter bottleneck by 40%.

)} {/* ========================================================= */} {/* ROLE 7: SECURE AUTHORIZED INVENTORY PANEL */} {/* ========================================================= */} {currentRole === 'inventory' && authorizedInventory && (
{/* Left Stock Matrix & Catalog (8 columns) */}

La Greenzaa Inventory Management Panel

Update recipes catalog, track opening vs. hand stocks, and adjust warehouse values.

{/* Master stock compiler */}
Accounting vs. Physical Stock distribution Select any recipe item below to inspect detailed matrices or print barcodes
{products.map(p => ( setSelectedInventoryItem(p)} className={`hover:bg-slate-900/40 cursor-pointer ${ selectedInventoryItem?.id === p.id ? 'bg-slate-900' : '' }`} > ))}
Item details SKU Opening Stock Committed Available Barcode Action
{p.image} {p.name} {p.sku} {p.openingStock}.00 {p.committedStock}.00 {p.availableForSale}.00
{/* Selected Item Stock details */} {selectedInventoryItem && (
Stock Matrix: {selectedInventoryItem.name} Base Unit: {selectedInventoryItem.unit}
Opening Stock {selectedInventoryItem.openingStock}.00
Stock On Hand {selectedInventoryItem.stockOnHand}.00
Committed Stock {selectedInventoryItem.committedStock}.00
Available For Sale {selectedInventoryItem.availableForSale}.00
)}
{/* Right configuration panel (4 columns) */}
{/* Add Item form */}

Add New Recipe

{/* Barcode Preview widget */}
Printing Barcode Preview {selectedInventoryItem ? (
{selectedInventoryItem.name} Price: {currencySymbol}{selectedInventoryItem.price}
{[1, 2, 1, 3, 2, 1.5, 3, 1, 2, 1, 3, 2, 1.5].map((w, i) => (
))}
{selectedInventoryItem.sku}
) : (
Please select an item to preview barcode template.
)}
)} {/* ========================================================= */} {/* PIN CODE KEYPAD LOCK OVERLAY */} {/* ========================================================= */} {securityTarget && (

Access PIN Required

Owner Portal Code: 8888 | Inventory Code: 9999

{/* Keypad entry visual feedback */}
{[0, 1, 2, 3].map((idx) => (
idx ? 'bg-indigo-500 shadow-lg shadow-indigo-500/50 scale-110' : 'bg-slate-950' }`} /> ))}
{lockErrorMessage && ( {lockErrorMessage} )} {/* Keypad Matrix Grid */}
{[1, 2, 3, 4, 5, 6, 7, 8, 9].map(num => ( ))}
)}
{/* ========================================================= */} {/* MODAL: CUSTOM INGREDIENTS/PREPARATION MODIFIERS */} {/* ========================================================= */} {showModifierModal && activeModifierItem && (
Preparation Custom Modifiers

Select dynamic modifiers to send alongside KOT ticket data structures:

{['Keep Vegan', 'No Onion No Garlic', 'Extra Hot', 'Less Sugar', 'Keep Sugar-Free', 'Extra Cheese'].map(mod => { const active = tempModifiers.includes(mod); return ( ); })}
)} {/* ========================================================= */} {/* MODAL: CUSTOM CUSTOMER REGISTRATION DIALOG (BILLER PORTAL) */} {/* ========================================================= */} {showRegisterCustomerModal && (

Register Loyalty Member

setNewCustName(e.target.value)} />
setNewCustPhone(e.target.value)} />
setNewCustEmail(e.target.value)} />
)} {/* ========================================================= */} {/* MODAL: CUSTOM INLINE PRODUCT DELETE CONFIRMATION */} {/* ========================================================= */} {confirmDeleteId && (

Permanently Delete Product?

This action cannot be undone. This recipe will be deleted from the local database master catalog.

)} {/* ========================================================= */} {/* MODAL: SINGLE PRODUCT BARCODE LABEL PRINT SIMULATOR */} {/* ========================================================= */} {showBarcodePrintModal && selectedBarcodeItem && (
Barcode Decal Printer
{selectedBarcodeItem.name} Price: {currencySymbol}{selectedBarcodeItem.price}
{[1, 3, 1, 2, 4, 1.5, 3, 2.5, 1, 2, 1.5, 3, 1, 2, 4, 1.5, 3, 2.5, 1, 2].map((w, i) => (
))}
{selectedBarcodeItem.sku}
)} {/* ========================================================= */} {/* POPUP MODAL: KOT THERMAL PRINTER SIMULATOR */} {/* ========================================================= */} {showPrintModal && activeKOTPrint && (
Dynamic KOT Saved Natively

{BRAND_SETTINGS.businessName} KOT

Token Ticket #{activeKOTPrint.tokenNo}
Date: May 22, 2026 Time: {activeKOTPrint.timestamp}
Order Mode: {activeKOTPrint.orderType} Terminal: REG-A01
{activeKOTPrint.tableNo !== 'N/A' && (
Dining Table: {activeKOTPrint.tableNo}
)}
Customer Name: {activeKOTPrint.customerName}
{activeKOTPrint.items.map((it, idx) => ( ))}
Qty Recipe Detail
{it.quantity}x
{it.name}
{it.modifiers?.length > 0 && (
* MOD: {it.modifiers.join(', ')}
)}
* KOT Issued Automatically to Prep Stations *
Developed by Umang Developers
)}
); } // --- APP WITH BOUNDED CRASH RECOVERY --- export default function App() { return ( ); }