import React, { useState, useEffect, useMemo } from 'react'; import { initializeApp } from 'firebase/app'; import { getFirestore, collection, addDoc, onSnapshot, doc, updateDoc, serverTimestamp, query, where } from 'firebase/firestore'; import { getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged } from 'firebase/auth'; import { ShoppingBag, Utensils, Clock, CheckCircle2, ChevronRight, Trash2, Plus, Minus, Store, X, PackageCheck, Truck, Flame, UserCheck } from 'lucide-react'; // --- Firebase Configuration --- const firebaseConfig = JSON.parse(__firebase_config); const app = initializeApp(firebaseConfig); const auth = getAuth(app); const db = getFirestore(app); const appId = typeof __app_id !== 'undefined' ? __app_id : 'kfc-clone-app'; // --- Sample Data: KFC Menu --- const MENU_DATA = [ { id: 'b1', category: 'Buckets', name: '10 pc. Family Bucket', price: 29.99, image: 'https://images.unsplash.com/photo-1626082927389-6cd097cdc6ec?auto=format&fit=crop&w=300&q=80', description: '10 pieces of our Original Recipe chicken, 2 large sides, and 4 biscuits.' }, { id: 'b2', category: 'Buckets', name: '8 pc. Chicken & Tenders Box', price: 24.99, image: 'https://images.unsplash.com/photo-1513185041617-8ab03f83d6c5?auto=format&fit=crop&w=300&q=80', description: '4 pieces of chicken and 4 Extra Crispy Tenders.' }, { id: 's1', category: 'Sandwiches', name: 'KFC Chicken Sandwich', price: 5.49, image: 'https://images.unsplash.com/photo-1606755962773-d324e0a13086?auto=format&fit=crop&w=300&q=80', description: 'Double-breaded, premium chicken breast fillet with pickles and mayo.' }, { id: 's2', category: 'Sandwiches', name: 'Spicy Chicken Sandwich', price: 5.49, image: 'https://images.unsplash.com/photo-1521305916504-4a1121188589?auto=format&fit=crop&w=300&q=80', description: 'Our signature spicy sauce adds the perfect kick.' }, { id: 't1', category: 'Tenders', name: '5 pc. Tenders Combo', price: 10.99, image: 'https://images.unsplash.com/photo-1562967914-608f82629710?auto=format&fit=crop&w=300&q=80', description: '5 Extra Crispy Tenders, side, biscuit, and a medium drink.' }, { id: 'd1', category: 'Sides', name: 'Secret Recipe Fries', price: 3.29, image: 'https://images.unsplash.com/photo-1573080496219-bb080dd4f877?auto=format&fit=crop&w=300&q=80', description: 'Seasoned with a secret blend of herbs and spices.' } ]; const CATEGORIES = ['All', 'Buckets', 'Sandwiches', 'Tenders', 'Sides']; export default function App() { const [user, setUser] = useState(null); const [view, setView] = useState('customer'); // 'customer' or 'kitchen' const [cart, setCart] = useState([]); const [orders, setOrders] = useState([]); const [activeCategory, setActiveCategory] = useState('All'); const [isOrdering, setIsOrdering] = useState(false); const [orderSuccess, setOrderSuccess] = useState(false); // 1. Auth Logic useEffect(() => { const initAuth = async () => { try { if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) { await signInWithCustomToken(auth, __initial_auth_token); } else { await signInAnonymously(auth); } } catch (err) { console.error("Auth error:", err); } }; initAuth(); const unsubscribe = onAuthStateChanged(auth, setUser); return () => unsubscribe(); }, []); // 2. Data Logic (Kitchen Orders) useEffect(() => { if (!user) return; const ordersRef = collection(db, 'artifacts', appId, 'public', 'data', 'orders'); // We listen to all orders for the kitchen view, but can filter in memory or locally for the customer const unsubscribe = onSnapshot(ordersRef, (snapshot) => { const orderData = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); setOrders(orderData.sort((a, b) => (b.createdAt?.seconds || 0) - (a.createdAt?.seconds || 0))); }, (error) => console.error("Firestore error:", error) ); return () => unsubscribe(); }, [user]); // --- Customer Actions --- const addToCart = (item) => { setCart(prev => { const existing = prev.find(i => i.id === item.id); if (existing) { return prev.map(i => i.id === item.id ? { ...i, qty: i.qty + 1 } : i); } return [...prev, { ...item, qty: 1 }]; }); }; const updateQty = (id, delta) => { setCart(prev => prev.map(item => { if (item.id === id) { const newQty = Math.max(0, item.qty + delta); return { ...item, qty: newQty }; } return item; }).filter(item => item.qty > 0)); }; const placeOrder = async () => { if (cart.length === 0 || !user) return; setIsOrdering(true); try { const orderPayload = { userId: user.uid, items: cart, total: cart.reduce((sum, i) => sum + (i.price * i.qty), 0), status: 'pending', // pending -> preparing -> ready -> received createdAt: serverTimestamp(), orderNumber: Math.floor(1000 + Math.random() * 9000) }; await addDoc(collection(db, 'artifacts', appId, 'public', 'data', 'orders'), orderPayload); setCart([]); setOrderSuccess(true); setTimeout(() => setOrderSuccess(false), 5000); } catch (err) { console.error("Order failed:", err); } finally { setIsOrdering(false); } }; // --- Status Helpers --- const updateOrderStatus = async (orderId, newStatus) => { try { const orderRef = doc(db, 'artifacts', appId, 'public', 'data', 'orders', orderId); await updateDoc(orderRef, { status: newStatus }); } catch (err) { console.error("Update failed:", err); } }; // Filter orders for the current customer that aren't finalized yet const myActiveOrders = useMemo(() => { if (!user) return []; return orders.filter(o => o.userId === user.uid && o.status !== 'received'); }, [orders, user]); const filteredMenu = activeCategory === 'All' ? MENU_DATA : MENU_DATA.filter(item => item.category === activeCategory); const cartTotal = cart.reduce((sum, item) => sum + (item.price * item.qty), 0); // Helper for status styling const getStatusInfo = (status) => { switch (status) { case 'pending': return { label: 'Placed', icon: PackageCheck, color: 'text-amber-500', bg: 'bg-amber-50', step: 1 }; case 'preparing': return { label: 'Preparing', icon: Flame, color: 'text-blue-500', bg: 'bg-blue-50', step: 2 }; case 'ready': return { label: 'Ready for Pickup', icon: Truck, color: 'text-green-500', bg: 'bg-green-50', step: 3 }; default: return { label: 'Unknown', icon: Clock, color: 'text-gray-500', bg: 'bg-gray-50', step: 0 }; } }; return (
{/* Navigation Header */}
{view === 'customer' ? (
{/* Customer Tracker - Only shows if there are active orders */} {myActiveOrders.length > 0 && (

Track My Order

{myActiveOrders.map(order => { const status = getStatusInfo(order.status); const StatusIcon = status.icon; return (
Order ID

#{order.orderNumber}

{status.label}
{/* Progress Tracker Bar */}
{[1, 2, 3].map((s) => (
= s ? 'border-red-600 bg-red-600' : 'border-gray-200'}`}>
))}
{order.items.length} items • ${order.total.toFixed(2)}
{order.status === 'ready' && ( )}
); })}
)}
{/* Menu Section */}
{orderSuccess && (

Order placed! Track it at the top of the page.

)} {/* Category Filter */}
{CATEGORIES.map(cat => ( ))}
{filteredMenu.map(item => (
{item.name}
${item.price.toFixed(2)}

{item.name}

{item.description}

))}
{/* Cart Summary */}

My Bucket

{cart.reduce((s, i) => s + i.qty, 0)} items
{cart.length === 0 ? (

Your bucket is empty

) : ( cart.map(item => (

{item.name}

${(item.price * item.qty).toFixed(2)}

{item.qty}
)) )}
{cart.length > 0 && (
Total ${cartTotal.toFixed(2)}
)}
) : ( /* Kitchen Display System (KDS) */

Kitchen Display

Manage incoming orders

Pending
{orders.filter(o => o.status === 'pending').length}
Preparing
{orders.filter(o => o.status === 'preparing').length}
{orders.filter(o => o.status !== 'received').map(order => (
Order

#{order.orderNumber}

{order.createdAt ? new Date(order.createdAt.seconds * 1000).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) : '...'}
{order.items.map((item, idx) => (
{item.qty}
{item.name}
))}
{order.status === 'pending' && ( )} {order.status === 'preparing' && ( )} {order.status === 'ready' && (
WAITING FOR CUSTOMER
)}
))} {orders.filter(o => o.status !== 'received').length === 0 && (

Kitchen is clear!

)}
)}
{/* Mobile Footer Cart Hint */} {view === 'customer' && cart.length > 0 && (
)}
); }