import React, { useState, useEffect, useMemo, useCallback } from 'react'; import { initializeApp } from 'firebase/app'; import { getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged } from 'firebase/auth'; import { getFirestore, collection, addDoc, onSnapshot, doc, updateDoc, deleteDoc, setDoc, increment, serverTimestamp } from 'firebase/firestore'; import { ShoppingBag, Clock, Trash2, Gift, User, LogOut, ArrowLeft, X, Phone, Lock, Loader2, Landmark, ConciergeBell, ChevronDown, Tag, Activity, Sparkles, MapPin, IdCard, Home, Leaf, Mail, Calendar, CalendarCheck, Waves, LayoutDashboard, Receipt, Plus, TrendingUp, TrendingDown, WifiOff, Trophy, RefreshCcw, Box, Copy, Upload, CheckCircle, Eye, Zap, Play, Check, CreditCard, DollarSign, Ticket } from 'lucide-react'; // --- Safe Firebase Initialization --- let app, auth, db; let initError = null; try { if (typeof __firebase_config !== 'undefined') { const config = JSON.parse(__firebase_config); app = initializeApp(config); auth = getAuth(app); db = getFirestore(app); } else { initError = "Firebase Config Missing"; } } catch (e) { console.error("Firebase Init Error:", e); initError = e.message; } const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; // --- CONFIGURATION --- const DUITNOW_QR_URL = "https://i.ibb.co/p99J4w8/IMG-20260204-143833-346.jpg"; const BUSINESS_BANK_DETAILS = { bankName: "RHB Bank", accountName: "NUR NAJWA NAZMINA BINTI AZMAN", accountNumber: "11306160255276" }; const BACKGROUNDS = { welcome: "https://images.unsplash.com/photo-1610832958506-aa56368176cf?q=80&w=2670&auto=format&fit=crop", physio: "https://images.unsplash.com/photo-1576091160399-112ba8d25d1d?q=80&w=2670&auto=format&fit=crop", massage: "https://images.unsplash.com/photo-1544161515-4ab6ce6db874?q=80&w=2670&auto=format&fit=crop", juice: "https://images.unsplash.com/photo-1621506289937-a8e4df240d0b?q=80&w=2574&auto=format&fit=crop", swimming: "https://images.unsplash.com/photo-1530549387789-4c1017266635?q=80&w=2670&auto=format&fit=crop", sports: "https://images.unsplash.com/photo-1626224583764-84786c71971e?q=80&w=2670&auto=format&fit=crop" }; const SERVICES = [ { id: 'juice', name: 'Fruit Juice', emoji: '๐ŸŠ', color: 'bg-orange-50 text-orange-600', gradient: 'from-orange-400 to-amber-500', description: 'Freshly squeezed goodness', subText: '7am - 6pm (Delivery @ 8pm)' }, { id: 'physio', name: 'Physiotherapy', emoji: '๐Ÿฉบ', color: 'bg-teal-50 text-teal-600', gradient: 'from-teal-500 to-emerald-600', description: 'Professional recovery & rehab' }, { id: 'massage', name: 'Massage Service', emoji: '๐Ÿ’†', color: 'bg-purple-50 text-purple-600', gradient: 'from-purple-500 to-indigo-600', description: 'Relax & rejuvenate' }, { id: 'swimming', name: 'Swimming', emoji: '๐ŸŠ', color: 'bg-blue-50 text-blue-600', gradient: 'from-blue-400 to-cyan-500', description: 'Coaching & Equipment Rental' }, { id: 'sports', name: 'Sports Rental', emoji: '๐Ÿธ', color: 'bg-red-50 text-red-600', gradient: 'from-red-500 to-pink-600', description: 'Rackets & Balls (4 Hours)' }, ]; const JUICE_MENU = [ { id: 'j1', type: 'juice', name: "Fresh Watermelon", emoji: "๐Ÿ‰", color: "bg-red-50 text-red-600" }, { id: 'j2', type: 'juice', name: "Squeezed Orange", emoji: "๐ŸŠ", color: "bg-orange-50 text-orange-600" }, { id: 'j3', type: 'juice', name: "Zesty Lemonade", emoji: "๐Ÿ‹", color: "bg-yellow-50 text-yellow-600" }, { id: 'j4', type: 'juice', name: "Tropical Pineapple", emoji: "๐Ÿ", color: "bg-amber-50 text-amber-600" }, ]; const PHYSIO_MENU = [ { id: 'p1', type: 'physio', name: "Physiotherapy Session", emoji: "๐Ÿฉบ", color: "bg-teal-50 text-teal-600", basePrice: 0 } ]; const MASSAGE_MENU = [ { id: 'm1', type: 'massage', name: "Express Massage (30m)", emoji: "๐Ÿ’†", color: "bg-purple-50 text-purple-600", price: 35.00 }, { id: 'm2', type: 'massage', name: "Full Body (60m)", emoji: "๐Ÿง˜", color: "bg-indigo-50 text-indigo-600", price: 70.00 }, { id: 'm3', type: 'massage', name: "Royal Full Body (120m)", emoji: "๐Ÿ‘‘", color: "bg-amber-50 text-amber-600", price: 130.00 }, ]; const SWIMMING_MENU = [ { id: 's1', type: 'swimming_coaching', name: "Swimming Coaching", emoji: "๐ŸŠโ€โ™‚๏ธ", color: "bg-blue-50 text-blue-600", price: 15.00 }, { id: 's2', type: 'swimming_rental', name: "Swimming Goggles", emoji: "๐Ÿฅฝ", color: "bg-cyan-50 text-cyan-600", price: 3.00, stockKey: 'swim_goggles' }, { id: 's3', type: 'swimming_rental', name: "Kickboard", emoji: "๐Ÿ„โ€โ™‚๏ธ", color: "bg-sky-50 text-sky-600", price: 3.00, stockKey: 'swim_kickboard' }, { id: 's4', type: 'swimming_rental', name: "Swimming Cap", emoji: "๐Ÿงข", color: "bg-indigo-50 text-indigo-600", price: 2.00, stockKey: 'swim_cap' }, { id: 's5', type: 'swimming_rental', name: "Pool Noodles", emoji: "๐Ÿ›Ÿ", color: "bg-yellow-50 text-yellow-600", price: 3.00, stockKey: 'swim_noodles' }, ]; const SPORTS_MENU = [ { id: 'sp1', type: 'sports_rental', name: "Badminton Racket", emoji: "๐Ÿธ", color: "bg-red-50 text-red-600", price: 3.00, bundle: true, stockKey: 'racket_badminton' }, { id: 'sp2', type: 'sports_rental', name: "Squash Racket", emoji: "๐ŸŽพ", color: "bg-orange-50 text-orange-600", price: 3.00, bundle: true, stockKey: 'racket_squash' }, { id: 'sp3', type: 'sports_rental', name: "Tennis Racket", emoji: "๐ŸŽพ", color: "bg-green-50 text-green-600", price: 3.00, bundle: true, stockKey: 'racket_tennis' }, { id: 'sp4', type: 'sports_rental', name: "Squash Ball", emoji: "โšซ", color: "bg-gray-50 text-gray-800", price: 2.00 }, { id: 'sp5', type: 'sports_rental', name: "Tennis Ball", emoji: "๐ŸŽพ", color: "bg-yellow-50 text-yellow-600", price: 2.00 }, { id: 'sp6', type: 'sports_sale', name: "Shuttlecock (Buy)", emoji: "๐Ÿธ", color: "bg-stone-50 text-stone-600", price: 5.00 }, ]; const INITIAL_STOCK = { racket_badminton: 4, racket_squash: 2, racket_tennis: 2, swim_goggles: 4, swim_kickboard: 4, swim_cap: 4, swim_noodles: 4 }; // --- Main App Component --- export default function App() { const [user, setUser] = useState(null); const [viewMode, setViewMode] = useState('welcome'); const [selectedServiceId, setSelectedServiceId] = useState(null); const [isOffline, setIsOffline] = useState(false); const [cart, setCart] = useState([]); const [orders, setOrders] = useState([]); const [expenses, setExpenses] = useState([]); const [inventory, setInventory] = useState(INITIAL_STOCK); const [activeVoucher, setActiveVoucher] = useState(null); const [isLoading, setIsLoading] = useState(false); // Dashboard & Auth const [staffTab, setStaffTab] = useState('orders'); const [staffFilterService, setStaffFilterService] = useState('all'); const [staffPassword, setStaffPassword] = useState(''); const [staffAuthError, setStaffAuthError] = useState(''); // Forms for Expenses const [expenseName, setExpenseName] = useState(''); const [expenseCost, setExpenseCost] = useState(''); const [expenseCategory, setExpenseCategory] = useState('stock'); // UI State const [isCartExpanded, setIsCartExpanded] = useState(false); const [customizingItem, setCustomizingItem] = useState(null); // Customization State const [sugarLevel, setSugarLevel] = useState('No Sugar'); const [cupSize, setCupSize] = useState('Medium'); const [physioRate, setPhysioRate] = useState('public'); const [massageArea, setMassageArea] = useState('Head & Shoulder'); const [massageAddOn, setMassageAddOn] = useState(false); const [swimCapType, setSwimCapType] = useState('Silicone'); // Customer Data const [customerName, setCustomerName] = useState(''); const [customerPhone, setCustomerPhone] = useState(''); const [customerEmail, setCustomerEmail] = useState(''); const [customerBlock, setCustomerBlock] = useState(''); const [roomNumber, setRoomNumber] = useState(''); const [matricNo, setMatricNo] = useState(''); const [staffId, setStaffId] = useState(''); const [homeAddress, setHomeAddress] = useState(''); const [massageClientType, setMassageClientType] = useState('student'); // Booking & Payment const [deliveryMode, setDeliveryMode] = useState('lobby'); const [paymentMethod, setPaymentMethod] = useState('cash'); const [voucherInput, setVoucherInput] = useState(''); const [voucherMsg, setVoucherMsg] = useState(''); const [appliedVoucher, setAppliedVoucher] = useState(null); const [discountPercent, setDiscountPercent] = useState(0); // Modals const [showPaymentModal, setShowPaymentModal] = useState(false); const [receiptImage, setReceiptImage] = useState(null); const [viewingReceipt, setViewingReceipt] = useState(null); // Game State const [showGameModal, setShowGameModal] = useState(false); const [gameBoard, setGameBoard] = useState(Array(9).fill(null)); const [gameStatus, setGameStatus] = useState('intro'); const [isPlayerTurn, setIsPlayerTurn] = useState(true); const [trialCustomer, setTrialCustomer] = useState({ name: '', matric: '', choice: 'Watermelon' }); // --- Logic Helpers --- const cartHasMobileService = useMemo(() => cart.some(item => ['physio', 'massage'].includes(item.type)), [cart]); const cartHasCoaching = useMemo(() => cart.some(item => item.type === 'swimming_coaching'), [cart]); const cartHasAppointment = useMemo(() => cartHasMobileService || cartHasCoaching, [cartHasMobileService, cartHasCoaching]); const getEffectiveClientType = () => { if (cart.some(i => i.type === 'physio')) { const item = cart.find(i => i.type === 'physio'); if (item.variant?.includes('Student')) return 'student'; if (item.variant?.includes('Staff')) return 'staff'; return 'public'; } return cart.some(i => i.type === 'massage') ? massageClientType : 'public'; }; const availableDates = useMemo(() => { const dates = []; const today = new Date(); for (let i = 0; i < 7; i++) { const d = new Date(today); d.setDate(today.getDate() + i); dates.push(d); } return dates; }, []); const getSlotsForItem = (dateObj, itemType) => { if (!dateObj) return []; const day = dateObj.getDay(); if (['physio', 'massage'].includes(itemType)) { if (day === 1 || day === 5) return ['22:00']; if (day >= 2 && day <= 4) return ['20:00', '21:00']; if (day === 6) return ['18:00', '19:00', '20:00', '21:00']; } else if (itemType === 'swimming_coaching') { if (day === 1 || day === 5) return ['20:00']; } return []; }; const isSlotBooked = (dateStr, timeStr, currentCartIndex = -1) => { const inOrders = orders.some(o => o.status !== 'cancelled' && o.items?.some(i => i.date === dateStr && i.time === timeStr)); const inCart = cart.some((c, idx) => idx !== currentCartIndex && c.date === dateStr && c.time === timeStr); return inOrders || inCart; }; const setItemSchedule = (index, dateObj, timeStr) => { setCart(prev => prev.map((item, i) => { if (i === index) { return { ...item, dateObj, date: dateObj?.toLocaleDateString() || null, time: timeStr || null }; } return item; })); }; const initiateAdd = (item) => { if (item.stockKey && inventory[item.stockKey] <= 0) { alert("Sorry, this item is currently out of stock!"); return; } setCustomizingItem(item); setSugarLevel('No Sugar'); setCupSize('Medium'); setPhysioRate('public'); setMassageArea('Head & Shoulder'); setMassageAddOn(false); setSwimCapType('Silicone'); }; const getPrice = () => { if (!customizingItem) return 0; if (customizingItem.type === 'juice') { if (cupSize === 'Small') return 5.00; if (cupSize === 'Medium') return 7.00; if (cupSize === 'Large') return 8.00; } if (customizingItem.type === 'physio') { if (physioRate === 'student') return 25.00; if (physioRate === 'staff') return 45.00; return 80.00; } if (customizingItem.type === 'massage') { return (customizingItem.price + (massageAddOn ? 6.00 : 0)); } return customizingItem.price || 0; }; const generateVariantString = () => { if (!customizingItem) return "Standard"; if (customizingItem.type === 'juice') { return `${cupSize}, ${sugarLevel}`; } if (customizingItem.type === 'physio') { const labels = { student: 'IIUM Student', staff: 'IIUM Staff', public: 'Public' }; return labels[physioRate] || "Standard"; } if (customizingItem.type === 'massage') { let details = ""; if (customizingItem.id === 'm1') details += `Area: ${massageArea}`; if (massageAddOn) details += `${details ? ', ' : ''}+10mins Add-on`; return details || "Standard"; } if (customizingItem.id === 's4') { return `Type: ${swimCapType}`; } return "Standard"; }; const confirmAddToCart = () => { if (!customizingItem) return; const finalPrice = getPrice(); const variantDetails = generateVariantString(); setCart(prev => [...prev, { id: customizingItem.id, qty: 1, variant: variantDetails, price: finalPrice, type: customizingItem.type, name: customizingItem.name, stockKey: customizingItem.stockKey || null, bundle: customizingItem.bundle || false, date: null, time: null }]); setCustomizingItem(null); }; const handleApplyVoucher = () => { const code = (voucherInput || '').trim().toUpperCase(); if (code.includes('JACKFER')) { setDiscountPercent(0.10); setAppliedVoucher({ code, percent: 10 }); setVoucherMsg('Voucher applied: 10% off โœ…'); } else { setDiscountPercent(0); setAppliedVoucher(null); setVoucherMsg('Invalid voucher code โŒ'); } }; const calculateTotal = () => { const subtotal = cart.reduce((acc, item) => { if (item.bundle) { return acc + (Math.floor(item.qty/2)*5) + ((item.qty%2)*item.price); } return acc + (item.price * item.qty); }, 0); const discountAmount = subtotal * discountPercent; let deliveryFee = (!cartHasAppointment && deliveryMode === 'room') ? 0.50 : 0; return subtotal + deliveryFee - discountAmount; }; const removeFromCart = (index) => { setCart(prev => prev.filter((_, i) => i !== index)); }; const handleCheckout = () => { if (!customerName || !customerPhone || !customerEmail) { alert("Please fill in basic contact details (Name, Phone, Email)."); return; } for (const item of cart) { if (['physio', 'massage', 'swimming_coaching'].includes(item.type)) { if (!item.date || !item.time) { alert(`Please select a date and time for your ${item.name} appointment.`); return; } } } if (paymentMethod === 'qr') { setShowPaymentModal(true); } else { submitOrder(); } }; const submitOrder = async () => { if (!user) return; setIsLoading(true); try { const finalTotal = calculateTotal(); // Clean undefined fields for Firestore const cleanedCart = cart.map(({ dateObj, ...rest }) => ({ ...rest, id: rest.id || null, stockKey: rest.stockKey || null, date: rest.date || null, time: rest.time || null })); const orderData = { items: cleanedCart, subtotal: finalTotal + (finalTotal * discountPercent), discount: finalTotal * discountPercent, total: finalTotal, status: 'pending', timestamp: Date.now(), customerCode: Math.floor(Math.random()*9000)+1000, userId: user.uid, receiptImage: paymentMethod === 'qr' ? receiptImage : null, customerDetails: { name: customerName || 'N/A', phone: customerPhone || 'N/A', email: customerEmail || 'N/A', matricNo: matricNo || 'N/A', staffId: staffId || 'N/A', block: customerBlock || 'N/A', roomNumber: roomNumber || 'N/A', homeAddress: homeAddress || 'N/A', deliveryMode, paymentMethod, bank: paymentMethod === 'qr' ? 'RHB QR' : 'Cash', clientType: cartHasMobileService ? getEffectiveClientType() : 'standard' } }; await addDoc(collection(db, 'artifacts', appId, 'public', 'data', 'orders'), orderData); // Update inventory safely const invRef = doc(db, 'artifacts', appId, 'public', 'data', 'inventory_main', 'stock'); for(let i of cart) { if(i.stockKey) { await updateDoc(invRef, {[i.stockKey]: increment(-i.qty)}); } } // Send Email via EmailJS if (customerEmail && customerEmail !== 'N/A') { fetch('https://api.emailjs.com/api/v1.0/email/send', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ service_id: 'service_3kj1ch1', template_id: 'template_kd13abi', user_id: 'diDwLTYFVg4PBmisN', template_params: { customer_name: customerName, customer_email: customerEmail, total_amount: finalTotal.toFixed(2), voucher_code: `JACKFER${Math.floor(Math.random()*100)}` } }) }).catch(e => console.error("Email API silent fail:", e)); } setActiveVoucher({ code: `JACKFER${Math.floor(Math.random()*100)}`, amount: "10%", email: customerEmail }); setCart([]); setReceiptImage(null); setShowPaymentModal(false); setIsCartExpanded(false); } catch(e) { console.error("Database Error:", e); alert("There was an error submitting your order. Please refresh and try again."); } finally { setIsLoading(false); } }; const handleReceiptUpload = (e) => { const file = e.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = (event) => { const img = new Image(); img.onload = () => { const canvas = document.createElement('canvas'); const MAX_WIDTH = 600; canvas.width = MAX_WIDTH; canvas.height = img.height * (MAX_WIDTH / img.width); canvas.getContext('2d').drawImage(img, 0, 0, canvas.width, canvas.height); setReceiptImage(canvas.toDataURL('image/jpeg', 0.6)); }; img.src = event.target.result; }; reader.readAsDataURL(file); }; const handleStaffLogin = () => { if (staffPassword === 'jackfer2025') { setViewMode('staff'); setStaffPassword(''); setStaffAuthError(''); } else { setStaffAuthError('Invalid Admin Password'); } }; const toggleOrderStatus = async (id, cur) => { await updateDoc(doc(db, 'artifacts', appId, 'public', 'data', 'orders', id), { status: cur === 'pending' ? 'completed' : 'pending' }); }; const addExpense = async () => { if (!user || !expenseName || !expenseCost) return; await addDoc(collection(db, 'artifacts', appId, 'public', 'data', 'expenses'), { item: expenseName, cost: parseFloat(expenseCost), category: expenseCategory, timestamp: Date.now(), userId: user.uid }); setExpenseName(''); setExpenseCost(''); }; const deleteExpense = async (id) => { if(user) await deleteDoc(doc(db, 'artifacts', appId, 'public', 'data', 'expenses', id)); }; // Staff Memo Filters const filteredStaffOrders = useMemo(() => { return orders.filter(o => staffFilterService === 'all' || o.items.some(i => i.type.includes(staffFilterService))); }, [orders, staffFilterService]); const verifyOrders = useMemo(() => { return orders.filter(o => o.customerDetails?.paymentMethod === 'qr' || o.receiptImage); }, [orders]); const financialStats = useMemo(() => { const totalRevenue = orders.filter(o => o.status === 'completed').reduce((acc, o) => acc + o.total, 0); const totalExpenses = expenses.reduce((acc, e) => acc + e.cost, 0); return { totalRevenue, totalExpenses, netProfit: totalRevenue - totalExpenses }; }, [orders, expenses]); // Tic Tac Toe Init const initGame = () => { setGameBoard(Array(9).fill(null)); setGameStatus('playing'); setIsPlayerTurn(true); }; // --- Auth & Listeners --- useEffect(() => { if (!auth) return; const initAuth = async () => { try { if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) { await signInWithCustomToken(auth, __initial_auth_token); } else { await signInAnonymously(auth); } } catch (e) { console.error("Auth:", e); } }; initAuth(); return onAuthStateChanged(auth, setUser); }, []); const AnimatedServiceLogo = () => (
๐ŸŠ
); const handleSelectService = (serviceId) => { setSelectedServiceId(serviceId); setViewMode('customer_menu'); }; if (initError) { return
{initError}
; } return (
{/* WELCOME SCREEN */} {viewMode === 'welcome' && (

Bisnes Jackfer

Premium Wellness & Freshness

)} {/* STAFF AUTH SCREEN */} {viewMode === 'staff_auth' && (

Staff Login

setStaffPassword(e.target.value)} placeholder="Enter Password" className="w-full bg-slate-50 border-2 border-slate-100 p-4 rounded-xl mb-4 text-center font-bold outline-none focus:border-gray-900 transition-all text-gray-900" /> {staffAuthError && (

{staffAuthError}

)}
)} {/* CUSTOMER HUB (Service Selection) */} {viewMode === 'customer_hub' && (

Services

Choose your wellness path

{SERVICES.map((s) => ( ))}
)} {/* SPECIFIC MENU SCREEN */} {viewMode === 'customer_menu' && (

Menu

{/* Notice Banners */} {selectedServiceId === 'juice' && (

Operation Hours: 7:00 AM - 6:00 PM

Note: All orders will be delivered starting from 8:00 PM.

)} {/* Game Banner for Juice */} {selectedServiceId === 'juice' && (
{ setShowGameModal(true); initGame(); }} className="mb-8 bg-gradient-to-r from-orange-400 via-red-500 to-pink-500 rounded-[2rem] p-6 text-white cursor-pointer shadow-lg relative overflow-hidden group hover:scale-[1.02] transition-transform duration-300">
Free Trial

FIGHT FOR JUICE!

Beat the bot in Tic-Tac-Toe to win.

)} {/* Items Grid */}
{(selectedServiceId==='juice'?JUICE_MENU:selectedServiceId==='physio'?PHYSIO_MENU:selectedServiceId==='massage'?MASSAGE_MENU:selectedServiceId==='swimming'?SWIMMING_MENU:SPORTS_MENU).map(item => { const isSoldOut = item.stockKey && (inventory[item.stockKey] || 0) <= 0; return (
{item.emoji}

{item.name}

{item.type === 'juice' ? 'Custom Sugar' : item.type === 'physio' ? 'Student/Staff Rates' : `RM ${item.price?.toFixed(2)}`}

{item.stockKey && (
{isSoldOut ? 'Sold Out' : `Stock: ${inventory[item.stockKey]}`}
)}
)})}
{/* FLOATING CART BAR */} {cart.length > 0 && !isCartExpanded && (
setIsCartExpanded(true)}>
{cart.length}

Checkout Amount

RM {calculateTotal().toFixed(2)}

)}
)} {/* STAFF DASHBOARD */} {viewMode === 'staff' && (

Jackfer Admin

{/* ADMIN ORDERS TAB */} {staffTab === 'orders' && filteredStaffOrders.map(o => (
#{o.customerCode} {o.status}
{o.items?.map((i,x)=>(
{i.qty}x

{i.name}

{i.variant}

{i.date && (

{i.date} @ {i.time}

)}
RM {i.price?.toFixed(2)}
))}

{o.customerDetails?.name}

{o.customerDetails?.phone}

{o.customerDetails?.homeAddress !== 'N/A' && (

{o.customerDetails?.homeAddress}

)}

RM {o.total?.toFixed(2)}

))} {/* ADMIN VERIFY TAB */} {staffTab === 'verify' && verifyOrders.map(order => (

#{order.customerCode} {order.customerDetails.paymentMethod}

{order.customerDetails.name} โ€ข RM {order.total.toFixed(2)}

{order.items?.map((i,x)=>(
{i.qty}x {i.name}
))}
order.receiptImage && setViewingReceipt(order.receiptImage)}> {order.receiptImage ? ( <>
) : (
No Image
)}
))} {/* ADMIN EXPENSES & FINANCE TAB */} {staffTab === 'expenses' && (

Total Revenue

RM {financialStats.totalRevenue.toFixed(2)}

Total Expenses

RM {financialStats.totalExpenses.toFixed(2)}

Net Profit

RM {financialStats.netProfit.toFixed(2)}

Log New Expense

setExpenseName(e.target.value)} className="flex-1 bg-slate-50 border-2 border-slate-100 p-4 rounded-xl text-sm font-bold outline-none focus:border-gray-400 transition-colors" /> setExpenseCost(e.target.value)} className="w-full md:w-32 bg-slate-50 border-2 border-slate-100 p-4 rounded-xl text-sm font-bold outline-none focus:border-gray-400 transition-colors font-mono" />

Recent Transactions

{expenses.length === 0 ? (

No financial records found.

) : expenses.map(e => (
{e.item}
{new Date(e.timestamp).toLocaleDateString()}
RM {e.cost.toFixed(2)}
))}
)}
)} {/* CUSTOMIZATION MODAL */} {customizingItem && (

{customizingItem.name}

{/* JUICE OPTIONS */} {customizingItem.type === 'juice' && ( <>
{['Small','Medium','Large'].map(s=>( ))}
{['Normal','Less','No'].map(s=>( ))}
)} {/* PHYSIO OPTIONS */} {customizingItem.type === 'physio' && (
{[{id:'student',l:'IIUM Student',p:'25'},{id:'staff',l:'IIUM Staff',p:'45'},{id:'public',l:'Public',p:'80'}].map(r=>( ))}
)} {/* MASSAGE OPTIONS */} {customizingItem.type === 'massage' && (
{customizingItem.id==='m1' && (
{['Head & Shoulder','Shoulder & Back','Lower Body'].map(a=>( ))}
)}
)} {/* SWIMMING OPTIONS */} {customizingItem.id === 's4' && (
{['Silicone','Mesh'].map(t=>( ))}
)}
{/* Add To Cart Button */}
)} {/* CHECKOUT CART DRAWER */} {isCartExpanded && (

Checkout

{cart.map((item, i) => { const requiresAppointment = ['physio', 'massage', 'swimming_coaching'].includes(item.type); return (
{item.qty}

{item.name}

{item.variant}

{item.bundle && Bundle Applied}
{/* Per-Item Appointment Picker */} {requiresAppointment && (

Select Booking Date & Time

{availableDates.map((date, dIdx) => { const isSel = item.dateObj && date.toDateString() === item.dateObj.toDateString(); const disabled = getSlotsForItem(date, item.type).length === 0; return ( ); })}
{item.dateObj && (
{getSlotsForItem(item.dateObj, item.type).map(time => { const booked = isSlotBooked(item.dateObj.toLocaleDateString(), time, i); const selected = item.time === time; return ( ); })}
)}
)}
); })}
{/* VOUCHER SECTION */}

Reward Voucher

setVoucherInput(e.target.value)} placeholder="Enter JACKFER..." className="flex-1 p-5 rounded-[1.5rem] border-2 border-lime-200 text-sm font-bold uppercase outline-none focus:ring-4 focus:ring-lime-500/10 transition-all bg-white" />
{voucherMsg &&

0 ? 'text-lime-700' : 'text-red-500'}`}> {voucherMsg}

}
{/* CLIENT DETAILS */}

Client Details

setCustomerName(e.target.value)} className="w-full p-5 rounded-2xl border-2 border-slate-200 font-bold outline-none focus:border-gray-900 transition-all text-gray-900 shadow-sm" />
setCustomerPhone(e.target.value)} className="w-1/2 p-5 rounded-2xl border-2 border-slate-200 font-bold outline-none text-gray-900 shadow-sm font-mono" /> setCustomerEmail(e.target.value)} className="w-1/2 p-5 rounded-2xl border-2 border-slate-200 font-bold outline-none text-gray-900 shadow-sm" />
{cartHasMobileService ? (
{getEffectiveClientType()==='student' && (
setMatricNo(e.target.value)} className="bg-white p-5 rounded-2xl border-2 border-slate-200 text-xs font-black outline-none text-gray-900 shadow-sm" /> setCustomerBlock(e.target.value)} className="bg-white p-5 rounded-2xl border-2 border-slate-200 text-xs font-black outline-none text-gray-900 shadow-sm" /> setRoomNumber(e.target.value)} className="bg-white p-5 rounded-2xl border-2 border-slate-200 text-xs font-black outline-none text-gray-900 shadow-sm" />
)} {getEffectiveClientType()==='staff' && (
setStaffId(e.target.value)} className="w-1/3 bg-white p-5 rounded-2xl border-2 border-slate-200 text-xs font-black outline-none text-gray-900 shadow-sm" /> setHomeAddress(e.target.value)} className="w-2/3 bg-white p-5 rounded-2xl border-2 border-slate-200 text-xs font-black outline-none text-gray-900 shadow-sm" />
)} {getEffectiveClientType()==='public' && (
setMatricNo(e.target.value)} className="w-1/3 bg-white p-5 rounded-2xl border-2 border-slate-200 text-xs font-black outline-none text-gray-900 shadow-sm font-mono" /> setHomeAddress(e.target.value)} className="w-2/3 bg-white p-5 rounded-2xl border-2 border-slate-200 text-xs font-black outline-none text-gray-900 shadow-sm" />
)}
) : cartHasCoaching ? (
Swimming Pool, Sport Complex IIUM Kuantan
) : (
setCustomerBlock(e.target.value)} className="w-1/2 bg-white p-5 rounded-2xl border-2 border-slate-200 text-sm font-bold outline-none text-gray-900 shadow-sm" /> {deliveryMode==='room' && setRoomNumber(e.target.value)} className="w-1/2 bg-white p-5 rounded-2xl border-2 border-slate-200 text-sm font-bold outline-none text-gray-900 shadow-sm" />}
)}
{/* PAYMENT METHOD */}

Payment Options

{/* CHECKOUT BUTTON */}
)} {/* QR MODAL */} {showPaymentModal && (

DuitNow Payment

Bank ServiceRHB BANK

Acc Number11306160255276

Total to PayRM {calculateTotal().toFixed(2)}

)} {/* GAME MODAL */} {showGameModal && (

Fight!

{gameStatus === 'won' ? (

You Won!

Claim your reward now!

setTrialCustomer({...trialCustomer,name:e.target.value})} /> setTrialCustomer({...trialCustomer,matric:e.target.value})} />
{['Watermelon','Orange','Lemon'].map(f=>( ))}
) : ( <>
{gameBoard.map((c, i) => ( ))}

{gameStatus==='playing'? (isPlayerTurn?"Your Turn (X)":"Bot Turn") : (gameStatus==='lost'?"Defeat!":"Draw!")}

{gameStatus!=='playing' && } )}
)} {/* VIEW RECEIPT (ADMIN) */} {viewingReceipt && (
setViewingReceipt(null)}>
Click to Close
)} {/* ORDER CONFIRMATION */} {activeVoucher && (

Success!

Your order is on the way! Your discount voucher has been emailed.

Next Order Code {activeVoucher.code}
)}
); }