diff --git "a/frontend/src/App.jsx" "b/frontend/src/App.jsx" --- "a/frontend/src/App.jsx" +++ "b/frontend/src/App.jsx" @@ -1,2266 +1,29 @@ -import React, { useState, useEffect, useRef, useCallback } from 'react'; -import { motion, AnimatePresence } from 'framer-motion'; -import * as API from './api.js'; -import { - Shield, X, CreditCard, Wallet, Smartphone, Activity, Settings, - MapPin, ChevronDown, Search, MessageSquare, Award, - Zap, ShoppingBasket, ShoppingCart, User, Check, Plus, - RotateCcw, Info, CheckCircle, Star, Sparkles, Flame, CalendarDays, - ShieldCheck, HelpCircle, TrendingUp, AlertTriangle, Play -} from 'lucide-react'; -import { AreaChart, Area, XAxis, YAxis, Tooltip, ResponsiveContainer } from 'recharts'; -import confetti from 'canvas-confetti'; -import './App.css'; - -// Import Modular Components -import AuthPortal from './components/AuthPortal.jsx'; -import DiscoveryHub from './components/DiscoveryHub.jsx'; -import RestaurantDetail from './components/RestaurantDetail.jsx'; -import CartCheckout from './components/CartCheckout.jsx'; -import RealTimeTracking from './components/RealTimeTracking.jsx'; -import AICommerceAgent from './components/AICommerceAgent.jsx'; -import OpsControlPanel from './components/OpsControlPanel.jsx'; -import LockScreen from './components/LockScreen.jsx'; -import LoyaltyAnalytics from './components/LoyaltyAnalytics.jsx'; - -// Import New Admin & Support Components -import MerchantStockAdmin from './components/MerchantStockAdmin.jsx'; -import FleetLogisticsAdmin from './components/FleetLogisticsAdmin.jsx'; -import FinancialOpsAdmin from './components/FinancialOpsAdmin.jsx'; -import GrowthAnalyticsAdmin from './components/GrowthAnalyticsAdmin.jsx'; - -// Import HyperFlow 4.0 Module Views -import DemandOracleView from './components/DemandOracleView.jsx'; -import ETATruthView from './components/ETATruthView.jsx'; -import RefundOracleView from './components/RefundOracleView.jsx'; -import DineoutSniperView from './components/DineoutSniperView.jsx'; -import DispatchMapView from './components/DispatchMapView.jsx'; - -import RefundStatus from './components/RefundStatus.jsx'; -import HelpSupport from './components/HelpSupport.jsx'; -import ChatbotHelp from './components/ChatbotHelp.jsx'; -import FestivalThemeManager from './components/FestivalThemeManager.jsx'; - -// Real coordinates in Bhubaneswar (Patia / Prasanti Vihar area) -const HUB_COORDINATES = { - Bhubaneswar: { - center: [20.3533, 85.8333], - route: [ - [20.3533, 85.8333], // Swiggy Instamart Warehouse (Patia) - [20.3562, 85.8315], // Prasanti Vihar road - [20.3585, 85.8288], // Near Lp 60 - [20.3601, 85.8272] // Gaurav Home - ] - } -}; - -const getInterpolatedPosition = (route, progress) => { - if (!route || route.length === 0) return null; - if (route.length === 1) return route[0]; - const totalSegments = route.length - 1; - const progressPercent = progress / 100; - const segmentIndex = Math.min( - Math.floor(progressPercent * totalSegments), - totalSegments - 1 - ); - const start = route[segmentIndex]; - const end = route[segmentIndex + 1]; - const segmentProgress = (progressPercent * totalSegments) - segmentIndex; - const lat = start[0] + (end[0] - start[0]) * segmentProgress; - const lng = start[1] + (end[1] - start[1]) * segmentProgress; - return [lat, lng]; -}; - -function LeafletMap({ center, routePoints, riderPos, theme, zoom = 14 }) { - const mapRef = useRef(null); - const mapInstanceRef = useRef(null); - const routeLayerRef = useRef(null); - const riderMarkerRef = useRef(null); - const storeMarkerRef = useRef(null); - const customerMarkersRef = useRef([]); - - useEffect(() => { - if (!mapRef.current || !window.L) return; - - const map = window.L.map(mapRef.current, { - zoomControl: false, - attributionControl: false - }).setView(center, zoom); - - mapInstanceRef.current = map; - - const darkTiles = 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png'; - const lightTiles = 'https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png'; - - window.L.tileLayer(theme === 'dark' ? darkTiles : lightTiles, { - maxZoom: 19 - }).addTo(map); - - return () => { - map.remove(); - mapInstanceRef.current = null; - }; - }, []); - - useEffect(() => { - const map = mapInstanceRef.current; - if (!map || !window.L) return; - - map.eachLayer((layer) => { - if (layer instanceof window.L.TileLayer) { - map.removeLayer(layer); - } - }); - - const darkTiles = 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png'; - const lightTiles = 'https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png'; - - window.L.tileLayer(theme === 'dark' ? darkTiles : lightTiles, { - maxZoom: 19 - }).addTo(map); - }, [theme]); - - useEffect(() => { - const map = mapInstanceRef.current; - if (map) { - map.setView(center, zoom); - } - }, [center, zoom]); - - useEffect(() => { - const map = mapInstanceRef.current; - if (!map || !window.L) return; - - if (routeLayerRef.current) { - map.removeLayer(routeLayerRef.current); - } - - if (routePoints && routePoints.length > 0) { - routeLayerRef.current = window.L.polyline(routePoints, { - color: '#6C63FF', - weight: 5, - dashArray: '8, 8', - opacity: 0.95 - }).addTo(map); - } - - if (storeMarkerRef.current) map.removeLayer(storeMarkerRef.current); - if (riderMarkerRef.current) map.removeLayer(riderMarkerRef.current); - customerMarkersRef.current.forEach(m => map.removeLayer(m)); - customerMarkersRef.current = []; - - const createCircleIcon = (color, size, pulse = false) => { - return window.L.divIcon({ - className: 'custom-map-pin', - html: `
`, - iconSize: [size, size], - iconAnchor: [size/2, size/2] - }); - }; - - if (routePoints && routePoints.length > 0) { - storeMarkerRef.current = window.L.marker(routePoints[0], { - icon: createCircleIcon('#6C63FF', 14) - }).addTo(map); - - const lastPoint = routePoints[routePoints.length - 1]; - const marker = window.L.marker(lastPoint, { - icon: createCircleIcon('#00D4AA', 14) - }).addTo(map); - customerMarkersRef.current.push(marker); - } - - if (riderPos) { - riderMarkerRef.current = window.L.marker(riderPos, { - icon: createCircleIcon('#FF4757', 18, true) - }).addTo(map); - } - - }, [routePoints, riderPos]); - - return
; -} - -function CategoryIcon({ name, className }) { - if (name === "Biryani") { - return ( - - - - - - - - ); - } - if (name === "Pizzas") { - return ( - - - - - - - - ); - } - if (name === "North Indian") { - return ( - - - - - - - ); - } - if (name === "Healthy") { - return ( - - - - - ); - } - if (name === "Groceries") { - return ( - - - - - ); - } - return null; -} - -const promoBanners = [ - { title: "Diwali Special: Up to 50% Off", desc: "Celebrate with royal Biryani from Behrouz & more partners", color: "from-[#FFB347] to-[#FF4757]", badge: "Festive" }, - { title: "9-Min Groceries Delivery", desc: "Get fresh milk, vegetables, and essentials instantly", color: "from-[#6C63FF] to-[#A078FF]", badge: "Quick" }, - { title: "Dineout Slot Bookings Open", desc: "Book dining slots at Mayfair Lagoon & premium buffets", color: "from-[#00D4AA] to-[#6C63FF]", badge: "Dineout" } -]; - -const categories = [ - { name: "Biryani" }, - { name: "Pizzas" }, - { name: "North Indian" }, - { name: "Healthy" }, - { name: "Groceries" } -]; +import React from 'react'; +import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'; +import Sidebar from './components/Sidebar.jsx'; +import AIAgent from './pages/AIAgent.jsx'; +import DarkStoreIntel from './pages/DarkStoreIntel.jsx'; +import RouteIntelligence from './pages/RouteIntelligence.jsx'; +import MLGuard from './pages/MLGuard.jsx'; +import Analytics from './pages/Analytics.jsx'; +import './index.css'; export default function App() { - const [isLoggedIn, setIsLoggedIn] = useState(() => !!localStorage.getItem('swiggy_access_token')); - const [activeTab, setActiveTab] = useState('home'); - const [appView, setAppView] = useState('consumer'); - const [isSimulatorMode, setIsSimulatorMode] = useState(window.innerWidth >= 1024); - const [isMobileDevice, setIsMobileDevice] = useState(window.innerWidth < 1024); - const [donateClimate, setDonateClimate] = useState(true); - const [donateFoodSafety, setDonateFoodSafety] = useState(true); - const [showSplash, setShowSplash] = useState(false); - const [showLockScreen, setShowLockScreen] = useState(false); - - useEffect(() => { - const handleResize = () => { - const isMobile = window.innerWidth < 1024; - setIsMobileDevice(isMobile); - if (isMobile) { - setIsSimulatorMode(true); - } - }; - window.addEventListener('resize', handleResize); - // run initial check - handleResize(); - return () => window.removeEventListener('resize', handleResize); - }, []); - - useEffect(() => { - if (showSplash) { - const timer = setTimeout(() => { - setShowSplash(false); - }, 2200); // 2.2 seconds splash animation - return () => clearTimeout(timer); - } - }, [showSplash]); - - // Swiggy, Zomato, Blinkit Operations & SOP states - const [adminSubTab, setAdminSubTab] = useState('system'); // 'system', 'restaurant', 'picking', 'logistics' - const [restaurantOrders, setRestaurantOrders] = useState([ - { id: "O-8374", name: "Anjali Patnaik", items: "1x Dum Gosht Biryani", elapsed: 0, status: "PENDING", limit: 45, price: 349 }, - { id: "O-2938", name: "Siddharth Sen", items: "2x Butter Chicken, 1x Paneer Tikka", elapsed: 0, status: "PENDING", limit: 45, price: 770 }, - ]); - const [pickingList, setPickingList] = useState([ - { id: "g_milk", name: "Amul Taaza Milk (1L)", qty: 2, location: "Aisle 2, A1", status: "PENDING" }, - { id: "g_tomatoes", name: "Fresh Tomatoes (500g)", qty: 1, location: "Aisle 5, C3", status: "PENDING" }, - { id: "g_bananas", name: "Organic Bananas (1 doz)", qty: 1, location: "Aisle 1, B2", status: "PENDING" } - ]); - const [pickingSLA, setPickingSLA] = useState(0); - const [pickingActive, setPickingActive] = useState(true); - const [riderList, setRiderList] = useState([ - { id: "R-01", name: "Sourav M.", status: "IDLE", location: "Patia Hub", batchedOrders: [] }, - { id: "R-02", name: "Amit K.", status: "DELIVERING", location: "Prasanti Vihar Rd", batchedOrders: ["O-8374"] }, - { id: "R-03", name: "Ranjan D.", status: "DELIVERING", location: "Lp 60 Lane", batchedOrders: ["O-2938"] } - ]); - const [rainIncentive, setRainIncentive] = useState(false); - - // Operational Simulation Timers - useEffect(() => { - const interval = setInterval(() => { - // 1. Restaurant SLA order timer - setRestaurantOrders(prev => prev.map(order => { - if (order.status === "PENDING") { - const nextElapsed = order.elapsed + 1; - if (nextElapsed >= order.limit) { - return { ...order, elapsed: order.limit, status: "TIMEOUT (Lapsed)" }; - } - return { ...order, elapsed: nextElapsed }; - } - return order; - })); - - // 2. Picking SLA timer - setPickingSLA(prev => { - if (pickingActive) return prev + 1; - return prev; - }); - }, 1000); - return () => clearInterval(interval); - }, [pickingActive]); - - const savedAddresses = [ - { id: "187465656", tag: "Home", name: "Gaurav Nayak", detail: "Plot Lp 60, Prasanti Vihar, Patia, Bhubaneswar, 751024" }, - { id: "d7n8j7j5p2h33j28em90", tag: "Work", name: "Gaurav Nayak", detail: "In front of Swiggy Instamart Warehouse, Patia, Bhubaneswar" }, - { id: "252492248", tag: "Other", name: "Gaurav Nayak", detail: "Lp 60, Prasanti Vihar, Patia, Bhubaneswar" } - ]; - const [selectedAddress, setSelectedAddress] = useState(savedAddresses[0]); - const [addressDropdownOpen, setAddressDropdownOpen] = useState(false); - - // Cart & Orders State - const [cart, setCart] = useState([]); - const [customizingItem, setCustomizingItem] = useState(null); - const [selectedBeverage, setSelectedBeverage] = useState('raita'); // 'raita' or 'pepsi' - const [selectedSweet, setSelectedSweet] = useState('jamun'); // 'jamun', 'meetha', or 'none' - const [deliveryMode, setDeliveryMode] = useState('ev'); // 'ev' or 'normal' - const [activeOrder, setActiveOrder] = useState(null); - const [riderProgress, setRiderProgress] = useState(0); - const [restaurantPageOpen, setRestaurantPageOpen] = useState(false); - const [selectedRestaurant, setSelectedRestaurant] = useState(null); - - const handleSelectRestaurant = (rest) => { - setSelectedRestaurant(rest); - setRestaurantPageOpen(true); - if (!rest.menu || rest.menu.length === 0) { - API.fetchRestaurantMenu(rest.id).then(menuData => { - if (menuData && Array.isArray(menuData) && menuData.length > 0) { - setRestaurants(prev => prev.map(r => r.id === rest.id ? { ...r, menu: menuData } : r)); - setSelectedRestaurant(prev => prev && prev.id === rest.id ? { ...prev, menu: menuData } : prev); - } - }); - } - }; - - // Search state - const [searchQuery, setSearchQuery] = useState(""); - const [vegOnly, setVegOnly] = useState(false); - const [selectedCuisine, setSelectedCuisine] = useState(null); - - // AI Agent Chat States - const [chatOpen, setChatOpen] = useState(false); - const [chatMessages, setChatMessages] = useState([ - { sender: 'agent', text: 'Hey Gaurav! I can query restaurants and groceries using Swiggy tools. Tell me your dietary goals or cravings.', time: '9:15pm', tools: [] } - ]); - const [chatInput, setChatInput] = useState(""); - const [isAgentThinking, setIsAgentThinking] = useState(false); - const [agentThinkingTools, setAgentThinkingTools] = useState([]); - - // Telemetry & Anomaly parameters - const [censoringRate, setCensoringRate] = useState(0.40); - const [forecastOutput, setForecastOutput] = useState({ - censoring_rate: 0.40, - ols_wmape: 0.208, - tobit_wmape: 0.139, - lift_pct: 33.1, - converged: true - }); - const [stormSurge, setStormSurge] = useState(false); - const [driftInjected, setDriftInjected] = useState(false); - const [arbitrageMessage, setArbitrageMessage] = useState(""); - const [rescueOffers, setRescueOffers] = useState([]); - const [rescueTimer, setRescueTimer] = useState(299); - const [securityLogs, setSecurityLogs] = useState([ - { time: "14:10:02", event: "SYSTEM BOOT SEQUENCE INITIATED...", type: "info" }, - { time: "14:10:12", event: "Anti-Arbitrage Guard active on Patia subnets.", type: "success" } - ]); - const [activeGroceryForecast, setActiveGroceryForecast] = useState(null); - - // Payment Gateway States - const [paymentScreenOpen, setPaymentScreenOpen] = useState(false); - const [selectedPaymentMethod, setSelectedPaymentMethod] = useState("cobranded"); - const [paymentProcessing, setPaymentProcessing] = useState(false); - const [paymentSuccess, setPaymentSuccess] = useState(false); - const [checkoutPayload, setCheckoutPayload] = useState(null); - const [backendUrl] = useState(import.meta.env.VITE_BACKEND_URL || "http://localhost:7860"); - const [theme, setTheme] = useState('dark'); - - // Customer Loyalty & Retention Metrics States - const [isPro, setIsPro] = useState(false); // HyperFlow Pro membership - const [streakOrders, setStreakOrders] = useState(1); // Gamified progress - const [lastOrderedItem, setLastOrderedItem] = useState({ - id: "dum_gosht", - name: "Dum Gosht Biryani", - price: 349, - restaurantName: "Behrouz Biryani", - restaurantId: "rest_behrouz", - protein: 36, - calories: 540 - }); - - // Festive theme overrides - const [festivalTheme, setFestivalTheme] = useState('nominal'); // 'nominal', 'diwali', 'holi' - - // Coupons database - const [coupons, setCoupons] = useState([ - { code: "HYPERPRO", pct: 15, minOrder: 300, desc: "15% off above ₹300" }, - { code: "DIWALI50", pct: 50, minOrder: 500, desc: "Festive 50% off above ₹500" }, - { code: "FREEFEES", pct: 100, minOrder: 0, desc: "Zero delivery fees coupon" } - ]); - const [appliedCoupon, setAppliedCoupon] = useState(null); - const [couponCodeInput, setCouponCodeInput] = useState(""); - const [couponMessage, setCouponMessage] = useState(""); - - // Expense Logs database - const [expenseLogs, setExpenseLogs] = useState([ - { id: 1, name: "July 04", amount: 480, calories: 1250 }, - { id: 2, name: "July 05", amount: 620, calories: 1800 }, - { id: 3, name: "July 06", amount: 290, calories: 950 }, - { id: 4, name: "July 07", amount: 840, calories: 2100 }, - { id: 5, name: "July 08", amount: 350, calories: 1100 } - ]); - - // Dineout slots reservation database - const [reservations, setReservations] = useState([ - { id: "res_101", hotel: "Mayfair Lagoon", time: "08:30 PM", party: 2, status: "CONFIRMED" } - ]); - - // Dynamic Databases - const [restaurants, setRestaurants] = useState([ - { - id: "rest_behrouz", - name: "Behrouz Biryani", - cuisine: "Biryani · Mughlai · Royal", - rating: 4.6, - distance: "2.1 km", - time: "28 min", - slaConfidence: 97, - isAIPick: true, - isExclusive: true, - image: "https://lh3.googleusercontent.com/aida-public/AB6AXuB3O6h3kN5v2ZfZDd3Ufds1_PUUHBmlla4WShhsUOwN1BiWVty9aGs9k-ujSiY3HWg0c-a6yUVCpufZJTK3hqLopqOy-INM9HYG-SKcVE0PbA__mUudSLa2FZF4yeu1q6fwxpjVZXn7yNLyelP_KZmven-uKjmR8Q3bG2PkZi64JiSya_N0Zb1Ww0kf3A7LW34llf4b4dpiTff9GbejYkJFooJR4Slc4fs85sLnGz-kZjWnuFABxdtocK8oviRGW5vmkB6XF1IMU4YS", - menu: [ - { id: "dum_gosht", name: "Dum Gosht Biryani", price: 349, rating: 4.6, desc: "Fragrant long-grain basmati rice layered with juicy mutton in royal spices.", protein: 36, cal: 540, veg: false, image: "https://lh3.googleusercontent.com/aida-public/AB6AXuAy8Ulq_axTRp6t2EagRb5G-YtqpRnvPzPmyNLG-1FBJ0_p-83Hb7anlB2ZhXsi9Yd0x4n4HVmWhRYJ4r1J0aeYhAKyBpAHs5R59gryk1trq626wW1LuUFZ7SkM8OvhMdS78RXzvNqpn-E03C047MfVamHP-NIetglvLA2A5zzJjsUUJ8KlWdV_E4DdUow8sK7YValAPmnwch_EcyAii9s8yhA-yi925HvzzqKBSoWyYDzGpNFU46e2dbF68cDx_CA1jI2gcAKBGs_E" }, - { id: "lazeez_chicken", name: "Lazeez Bhuna Murgh Biryani", price: 299, rating: 4.5, desc: "Tender boneless chicken in bhuna spices layered with basmati rice.", protein: 32, cal: 480, veg: false, image: "https://lh3.googleusercontent.com/aida-public/AB6AXuBVH7_iiDjEwAqM-iOH8jm3r4ljZMINGVU_Xp5Q-c5wjp04ir3wyacHOLYmjmdPdsAEKmN7NFvNQ8ccPIwOAUEqVu7ESWWZFV7ECSWX7JzlbDWyCtYJ_7mti2MWNy3Yuj77gJG8cjX2qVom1OGcFA8kzAFxQ4u3CBk-mzNORIV01WqDHbcX9ae4xKUwXCM69aXnh0vKIHvWcTm7xzkbIx4a_pAK1gBNf1lGPPzRLuDKikphdzej965g0gpkdAKQ1V-5hDx9OoV1vQMF" }, - { id: "mint_raita", name: "Mint Raita", price: 49, rating: 4.2, desc: "Refreshing raita flavored with fresh mint leaves.", protein: 2, cal: 60, veg: true, image: "https://lh3.googleusercontent.com/aida-public/AB6AXuA9dB7F5xSnF4KMn9vZmYR-rdDJJynymGxYucwoE-YBitPw0VKGSu-DN14kA90BSzp-2uy6VqlvfPFGUv1w1bAkAncDACJEjmjyIs5U_edIxKkwyJXxKBdiWMNunXofnk0gpGuMhOYRmiAlpBLt1eDqi27iQu4sKk2m2BOZdHLrGxGFXuHSxNxRfZrvdjjDlDh9Qzm9Bq8gJA1kCDLJqJ4Wt4tvK3bGLCdxh0ENy_AR1ED6oHIrCU53WfftTybXUz_QCYlouZZvj1fU" } - ] - }, - { - id: "rest_carbon_grill", - name: "Carbon Grill", - cuisine: "Burgers · Wings · Sides", - rating: 4.3, - distance: "1.4 km", - time: "22 min", - slaConfidence: 94, - isAIPick: false, - isExclusive: false, - image: "https://lh3.googleusercontent.com/aida-public/AB6AXuD9C62CkwFO1Ta65rOPGt_zkQb3NWBfpIVfhSCWsS173P7Hw1t8O2CFnA1Swhsh03BFAJeCU4v8zMcs2FtgfS9UKrkQ-pgIxmQV0atKwEY1VvIrOO2nqjJirHB5LtlEy7v2E23zmpz5QUROCmGsEwpUTOxc6-W7bqEnwZTpjlEj84W0_wRNkm3oiChRsbQBbdUsj6iQ4IQ8MjgCXDjvXHjIGyb2EehurUmG2rcFE5E_2NQqMXhnC7sZPl5JUl0b-89s8s1A5HghkpjV", - menu: [ - { id: "truffle_burger", name: "Truffle Cheese Burger", price: 280, rating: 4.5, desc: "Gourmet double-patty burger with Swiss cheese and black truffle aioli.", protein: 34, cal: 620, veg: false, image: "https://lh3.googleusercontent.com/aida-public/AB6AXuD9C62CkwFO1Ta65rOPGt_zkQb3NWBfpIVfhSCWsS173P7Hw1t8O2CFnA1Swhsh03BFAJeCU4v8zMcs2FtgfS9UKrkQ-pgIxmQV0atKwEY1VvIrOO2nqjJirHB5LtlEy7v2E23zmpz5QUROCmGsEwpUTOxc6-W7bqEnwZTpjlEj84W0_wRNkm3oiChRsbQBbdUsj6iQ4IQ8MjgCXDjvXHjIGyb2EehurUmG2rcFE5E_2NQqMXhnC7sZPl5JUl0b-89s8s1A5HghkpjV" }, - { id: "peri_fries", name: "Spicy Peri Peri Fries", price: 149, rating: 4.3, desc: "Crispy golden skin-on fries tossed in house peri-peri spice dust.", protein: 5, cal: 320, veg: true, image: "https://lh3.googleusercontent.com/aida-public/AB6AXuD9C62CkwFO1Ta65rOPGt_zkQb3NWBfpIVfhSCWsS173P7Hw1t8O2CFnA1Swhsh03BFAJeCU4v8zMcs2FtgfS9UKrkQ-pgIxmQV0atKwEY1VvIrOO2nqjJirHB5LtlEy7v2E23zmpz5QUROCmGsEwpUTOxc6-W7bqEnwZTpjlEj84W0_wRNkm3oiChRsbQBbdUsj6iQ4IQ8MjgCXDjvXHjIGyb2EehurUmG2rcFE5E_2NQqMXhnC7sZPl5JUl0b-89s8s1A5HghkpjV" } - ] - }, - { - id: "rest_yoko_ono", - name: "Yoko Ono Sushi", - cuisine: "Sushi · Asian · Japanese", - rating: 4.4, - distance: "3.2 km", - time: "18 min", - slaConfidence: 98, - isAIPick: false, - isExclusive: true, - image: "https://lh3.googleusercontent.com/aida-public/AB6AXuCBY63vuIkeBp6l5cHYDUYAUxyfZjekeIUDrgoaWXdYWfRsIItON9yVcNgasVY5EVJ_z9UCEYE7ifS6es_em8GXuQSZjL4elMAOcYKY-mFqvK7XoIYiCdoO9fXcs76s27BFjIlZ-jibt94sXMKAMiW-HDhL8Fx6YgFDMjXCKJuqgQvL6f2QokApfLDSvnpgf5uRCpVCyjlevWvENzKb2pD1gJvWBrOj_kU8HsHYg8siO1GP2yGFdEgOS79jFlelYdFjbEs_cIizY-X6", - menu: [ - { id: "salmon_nigiri", name: "Salmon Nigiri (2pcs)", price: 320, rating: 4.7, desc: "Slices of premium fresh Atlantic salmon laid over seasoned sushi rice.", protein: 14, cal: 180, veg: false, image: "https://lh3.googleusercontent.com/aida-public/AB6AXuCBY63vuIkeBp6l5cHYDUYAUxyfZjekeIUDrgoaWXdYWfRsIItON9yVcNgasVY5EVJ_z9UCEYE7ifS6es_em8GXuQSZjL4elMAOcYKY-mFqvK7XoIYiCdoO9fXcs76s27BFjIlZ-jibt94sXMKAMiW-HDhL8Fx6YgFDMjXCKJuqgQvL6f2QokApfLDSvnpgf5uRCpVCyjlevWvENzKb2pD1gJvWBrOj_kU8HsHYg8siO1GP2yGFdEgOS79jFlelYdFjbEs_cIizY-X6" }, - { id: "tuna_maki", name: "Tuna Maki Roll (6pcs)", price: 280, rating: 4.5, desc: "Yellowfin tuna wrapped in nori sheet with sushi rice.", protein: 18, cal: 220, veg: false, image: "https://lh3.googleusercontent.com/aida-public/AB6AXuCBY63vuIkeBp6l5cHYDUYAUxyfZjekeIUDrgoaWXdYWfRsIItON9yVcNgasVY5EVJ_z9UCEYE7ifS6es_em8GXuQSZjL4elMAOcYKY-mFqvK7XoIYiCdoO9fXcs76s27BFjIlZ-jibt94sXMKAMiW-HDhL8Fx6YgFDMjXCKJuqgQvL6f2QokApfLDSvnpgf5uRCpVCyjlevWvENzKb2pD1gJvWBrOj_kU8HsHYg8siO1GP2yGFdEgOS79jFlelYdFjbEs_cIizY-X6" } - ] - } - ]); - - const [groceries, setGroceries] = useState([ - { id: "g_milk", name: "Amul Taaza Milk (1L)", brand: "Amul", price: 56, weight: "1L", image: "https://images.unsplash.com/photo-1563636619-e9143da7973b?w=200&auto=format&fit=crop&q=60", stock: 0, latent_demand: 48, restock: 55, replacementName: "GoodLife Tetra Pack Milk (1L)" }, - { id: "g_tomatoes", name: "Fresh Tomatoes (500g)", brand: "Organic Farms", price: 32, weight: "500g", image: "https://images.unsplash.com/photo-1595855759920-86582396756a?w=200&auto=format&fit=crop&q=60", stock: 3, latent_demand: 24, restock: 30 }, - { id: "g_bananas", name: "Organic Bananas (1 doz)", brand: "Fresh Produce", price: 60, weight: "1 Dozen", image: "https://images.unsplash.com/photo-1571771894821-ce9b6c11b08e?w=200&auto=format&fit=crop&q=60", stock: 18, latent_demand: 82, restock: 90 } - ]); - - const [disputesQueue, setDisputesQueue] = useState([ - { id: "disp_1", customer: "Gaurav Nayak", merchantId: "rest_behrouz", type: "Cold Delivery", text: "Mutton Biryani was cold and dry on arrival.", items: "1x Dum Gosht Biryani", status: "PENDING", refundAmt: 349 }, - { id: "disp_2", customer: "Anjali Patnaik", merchantId: "rest_yoko_ono", type: "Missing Items", text: "Did not receive the salmon nigiri pieces.", items: "1x Salmon Nigiri (2pcs)", status: "PENDING", refundAmt: 320 } - ]); - - // Dineout Hotels Database - const mockHotels = [ - { id: "hot_mayfair", name: "Mayfair Lagoon", cuisine: "Multi-Cuisine · Premium Buffet", rating: 4.8, distance: "3.0 km", costForTwo: 2500, image: "https://images.unsplash.com/photo-1566073771259-6a8506099945?w=300&auto=format&fit=crop&q=60", slots: ["07:30 PM", "08:00 PM", "09:00 PM", "09:30 PM"] }, - { id: "hot_swosti", name: "Swosti Grand Hotels", cuisine: "North Indian · Bar & Grill", rating: 4.5, distance: "1.8 km", costForTwo: 1800, image: "https://images.unsplash.com/photo-1551882547-ff40c63fe5fa?w=300&auto=format&fit=crop&q=60", slots: ["07:00 PM", "08:30 PM", "09:00 PM"] }, - { id: "hot_taj", name: "Taj Vivanta", cuisine: "Global Gourmet · Fine Dine", rating: 4.9, distance: "4.5 km", costForTwo: 4000, image: "https://images.unsplash.com/photo-1542314831-068cd1dbfeeb?w=300&auto=format&fit=crop&q=60", slots: ["08:00 PM", "09:30 PM"] } - ]; - - // Forms states for Admin additions - const [newRestName, setNewRestName] = useState(""); - const [newRestCuisine, setNewRestCuisine] = useState(""); - const [newRestImage, setNewRestImage] = useState(""); - const [newRestSLA, setNewRestSLA] = useState(25); - const [newRestExclusive, setNewRestExclusive] = useState(false); - const [newCouponCode, setNewCouponCode] = useState(""); - const [newCouponPct, setNewCouponPct] = useState(20); - const [newCouponMin, setNewCouponMin] = useState(300); - - // Sync theme and festival attributes - useEffect(() => { - document.body.setAttribute('data-theme', theme); - document.body.setAttribute('data-festival', festivalTheme); - if (theme === 'dark') { - document.documentElement.classList.add('dark'); - } else { - document.documentElement.classList.remove('dark'); - } - }, [theme, festivalTheme]); - - // Animated rider track simulation loop - useEffect(() => { - let interval; - if (activeOrder) { - interval = setInterval(() => { - setRiderProgress(prev => { - if (prev >= 100) { - setActiveOrder(prevOrder => ({ ...prevOrder, status: "Delivered!" })); - const totalSpend = activeOrder.items.reduce((sum, item) => sum + (item.price * item.quantity), 0); - const totalCals = activeOrder.items.reduce((sum, item) => sum + (item.calories || 0) * item.quantity, 0); - - // Increment streaks - setStreakOrders(prevStreak => prevStreak + 1); - - setExpenseLogs(prevLogs => [ - ...prevLogs, - { id: Date.now(), name: "Today", amount: totalSpend, calories: totalCals } - ]); - clearInterval(interval); - return 100; - } - return prev + 1; - }); - }, 500); - } - return () => clearInterval(interval); - }, [activeOrder]); - - // ─── OAuth Redirect Callback Handler ─────────────────────────────────────── - useEffect(() => { - const params = new URLSearchParams(window.location.search); - const code = params.get('code'); - const state = params.get('state'); - - if (code && state) { - const savedState = localStorage.getItem('swiggy_oauth_state'); - if (state !== savedState) { - console.warn("[OAuth] CSRF state mismatch!"); - } - - // Clean up state - localStorage.removeItem('swiggy_oauth_state'); - - // Exchange code for token - API.exchangeCode(code, state).then(data => { - if (data && data.access_token) { - localStorage.setItem('swiggy_access_token', data.access_token); - setIsLoggedIn(true); - setAppView('hub'); - } else { - alert("Swiggy connection failed: " + (data?.error_description || "Unknown error")); - } - window.history.replaceState({}, document.title, window.location.pathname); - }).catch(err => { - console.error("[OAuth] Exchange error:", err); - window.history.replaceState({}, document.title, window.location.pathname); - }); - } - }, []); - - // ─── Backend Integration — on-mount data sync ───────────────────────────── - useEffect(() => { - // 1. Hydrate restaurants from backend - API.fetchRestaurants().then(data => { - if (data && Array.isArray(data) && data.length > 0) { - // Merge backend list with local menus (backend doesn't store menus yet) - setRestaurants(prev => { - const merged = [...prev]; - data.forEach(beRest => { - const existing = merged.find(r => r.id === beRest.id); - if (!existing) merged.push({ ...beRest, menu: [] }); - else Object.assign(existing, { ...beRest, menu: existing.menu }); - }); - return merged; - }); - } - }); - - // 2. Hydrate coupons from backend - API.fetchCoupons().then(data => { - if (data && Array.isArray(data) && data.length > 0) { - setCoupons(data); - } - }); - - // 3. Hydrate dineout reservations from backend - API.fetchDineoutReservations().then(data => { - if (data && Array.isArray(data) && data.length > 0) { - setReservations(data); - } - }); - - // 4. Hydrate expense logs from backend - API.fetchExpenseLogs().then(data => { - if (data && Array.isArray(data) && data.length > 0) { - setExpenseLogs(data.map(e => ({ id: e.id, name: e.date || e.name || 'Day', amount: e.amount, calories: e.calories }))); - } - }); - - // 5. Hydrate festival theme from backend - API.fetchFestivalSettings().then(data => { - if (data?.festival_theme) setFestivalTheme(data.festival_theme); - }); - }, []); - - // ─── Backend Integration — live WebSocket metrics ──────────────────────── - const [liveMetrics, setLiveMetrics] = useState(null); - useEffect(() => { - const ws = API.connectLiveMetrics(data => { - setLiveMetrics(data); - }); - return () => ws.close(); - }, []); - - // ─── Backend Integration — ML robustness polling (every 15s) ──────────── - const [mlRobustness, setMlRobustness] = useState(null); - useEffect(() => { - const poll = () => { - API.fetchRobustness().then(data => { - if (data) setMlRobustness(data); - }); - }; - poll(); - const iv = setInterval(poll, 15000); - return () => clearInterval(iv); - }, []); - - // ─── Backend Integration — availability metrics ────────────────────────── - const [availabilityMetrics, setAvailabilityMetrics] = useState(null); - useEffect(() => { - API.fetchAvailabilityMetrics('store_01').then(data => { - if (data) setAvailabilityMetrics(data); - }); - }, []); - - // ─── Backend Integration — bump rate metrics ───────────────────────────── - const [bumpRateMetrics, setBumpRateMetrics] = useState(null); - useEffect(() => { - API.fetchBumpRate().then(data => { - if (data) setBumpRateMetrics(data); - }); - }, []); - - // ─── Backend Integration — store profitability ─────────────────────────── - const [profitabilityData, setProfitabilityData] = useState({}); - useEffect(() => { - ['store_01', 'store_02', 'store_03'].forEach(storeId => { - API.fetchProfitability(storeId).then(data => { - if (data) setProfitabilityData(prev => ({ ...prev, [storeId]: data })); - }); - }); - }, []); - - - - // Dynamic Loyalty Tier Calculations based on spent levels - const getTotalSpent = () => expenseLogs.reduce((sum, log) => sum + log.amount, 0); - - const getLoyaltyTier = () => { - const total = getTotalSpent(); - if (total >= 10000) return { name: "VIP Platinum Elite", color: "from-[#6C63FF] via-[#A078FF] to-[#00D4AA]", limit: 10000, cashback: 10, bg: "glow-primary" }; - if (total >= 5000) return { name: "Gold Executive", color: "from-[#FFB347] to-[#FF4757]", limit: 10000, next: "VIP Platinum Elite", cashback: 5, bg: "glow-gold" }; - return { name: "Silver Explorer", color: "from-[#A0A0B8] to-[#606075]", limit: 5000, next: "Gold Executive", cashback: 3, bg: "" }; - }; - - const currentTier = getLoyaltyTier(); - - // Helpers - const getCartSubtotal = () => cart.reduce((sum, item) => sum + (item.price * item.quantity), 0); - - const getPackingFee = () => (cart.length > 0 ? 15 : 0); - - const getGSTAmount = () => Math.round(getCartSubtotal() * 0.05 * 100) / 100; - - const getDonations = () => { - let amount = 0; - if (donateClimate) amount += 2; - if (donateFoodSafety) amount += 2; - return amount; - }; - - const getDeliveryFee = () => { - if (currentTier.name === "VIP Platinum Elite" || isPro) return 0; - if (currentTier.name === "Gold Executive" && getCartSubtotal() >= 300) return 0; - - if (cart.length > 0 && cart[0].restaurantId === 'im_store') return 15; - if (cart.length > 0) { - const rest = restaurants.find(r => r.id === cart[0].restaurantId); - if (rest && rest.isExclusive) return 0; - } - return stormSurge ? 45 : 30; - }; - - const getDiscountAmount = () => { - const subtotal = getCartSubtotal(); - let discount = 0; - if (appliedCoupon && subtotal >= appliedCoupon.minOrder) { - if (appliedCoupon.code !== "FREEFEES") { - discount = Math.round(subtotal * (appliedCoupon.pct / 100)); - } - } - if (isPro || currentTier.name === "VIP Platinum Elite") { - discount += Math.round(subtotal * 0.1); // Extra 10% off - } else if (currentTier.name === "Gold Executive") { - discount += Math.round(subtotal * 0.05); // Extra 5% off - } - return discount; - }; - - const getCartTotal = () => { - const subtotal = getCartSubtotal(); - const packing = getPackingFee(); - const gst = getGSTAmount(); - const delivery = (appliedCoupon?.code === "FREEFEES" || isPro || currentTier.name === "VIP Platinum Elite") ? 0 : getDeliveryFee(); - const donations = getDonations(); - const discount = getDiscountAmount(); - // Return precise 2-decimal rounded grand total - return Math.round((subtotal + packing + gst + delivery + donations - discount) * 100) / 100; - }; - - const handleAddToCart = (item, restName, restId) => { - setCart(prev => { - const existing = prev.find(i => i.id === item.id); - if (existing) { - return prev.map(i => i.id === item.id ? { ...i, quantity: i.quantity + 1 } : i); - } - return [...prev, { ...item, restaurantName: restName, restaurantId: restId, quantity: 1, protein: item.protein || 0, calories: item.calories || item.cal || 0 }]; - }); - }; - - const handleAddOrCustomize = (item, restName, restId) => { - if (item.id === 'dum_gosht') { - setCustomizingItem({ dish: item, restaurantName: restName, restaurantId: restId }); - } else { - handleAddToCart(item, restName, restId); - } - }; - - const updateCartQty = (id, delta) => { - setCart(prev => { - return prev.map(item => { - if (item.id === id) { - const newQty = item.quantity + delta; - return newQty <= 0 ? null : { ...item, quantity: newQty }; - } - return item; - }).filter(Boolean); - }); - }; - - const handlePlaceOrder = () => { - if (cart.length === 0) return; - const payload = { - items: [...cart], - restaurantName: cart[0].restaurantName, - restaurantId: cart[0].restaurantId, - total: getCartTotal() - }; - setCheckoutPayload(payload); - setPaymentScreenOpen(true); - }; - - const handleInstantReorder = () => { - if (!lastOrderedItem) return; - const payload = { - items: [{ ...lastOrderedItem, quantity: 1 }], - restaurantName: lastOrderedItem.restaurantName, - restaurantId: lastOrderedItem.restaurantId, - total: lastOrderedItem.price - }; - setCheckoutPayload(payload); - setPaymentScreenOpen(true); - }; - - const executePaymentSuccess = async (directPayload = null) => { - const payload = directPayload || checkoutPayload; - if (!payload) return; - - let orderId = `HF-${Math.floor(Math.random() * 8999) + 1000}`; - let isRealOrder = false; - const timestamp = new Date().toLocaleTimeString(); - - // Fire Confetti Blast - confetti({ - particleCount: 120, - spread: 70, - origin: { y: 0.6 } - }); - - const isSwiggyAuth = !!localStorage.getItem('swiggy_access_token'); - - if (isSwiggyAuth) { - try { - setSecurityLogs(prev => [ - { time: timestamp, event: `SWIGGY REALTIME: Starting Swiggy Food MCP order placement flow...`, type: 'info' }, - ...prev - ]); - - // 1. Fetch Swiggy address - const addrRes = await API.fetchFoodAddresses(); - const addressId = addrRes?.structuredContent?.addresses?.[0]?.id; - - if (addressId) { - // 2. Format items for cart update - const swiggyItems = payload.items.map(item => ({ - id: item.id, - quantity: item.quantity || 1 - })); - - // 3. Update Swiggy cart - await API.updateFoodCart({ addressId, items: swiggyItems }); - - // 4. Place Swiggy order - const placeRes = await API.placeFoodOrder({ addressId, paymentMethod: "COD" }); - - if (placeRes?.structuredContent?.orderId) { - orderId = placeRes.structuredContent.orderId; - isRealOrder = true; - setSecurityLogs(prev => [ - { time: timestamp, event: `SWIGGY ORDER PLACED: Placed real checkout order ${orderId} via COD.`, type: 'success' }, - ...prev - ]); - } - } - } catch (err) { - console.warn("[Swiggy Order placing failed, falling back to mock reservation]:", err); - setSecurityLogs(prev => [ - { time: timestamp, event: `SWIGGY ORDER ERROR: Realtime order failed. Falling back to local lock manager: ${err.message}`, type: 'error' }, - ...prev - ]); - } - } - - // Lock manager execution for local state validation & mock tracking - if (!isRealOrder) { - for (const item of payload.items) { - let skuId = "g4"; // default mock restaurant item - if (item.id === "g_milk") skuId = "g1"; - else if (item.id === "g_bananas") skuId = "g2"; - else if (item.id === "g_tomatoes") skuId = "g3"; - - try { - const res = await API.reserveInventory({ - order_id: orderId, - store_id: "store_01", - sku_id: skuId, - qty_requested: item.quantity - }); - if (res) { - setSecurityLogs(prev => [ - { time: timestamp, event: `LOCK MANAGER: Reserved ${item.quantity}x ${item.name} (SKU: ${skuId}) via ${res.latency_ms ? `p99 Redis lock (${res.latency_ms}ms)` : 'lock manager'}.`, type: 'success' }, - ...prev - ]); - } - } catch (err) { - setSecurityLogs(prev => [ - { time: timestamp, event: `LOCK CONFLICT: Failed to reserve ${item.name}. Lock acquisition timeout or insufficient stock.`, type: 'error' }, - ...prev - ]); - } - } - } - - setActiveOrder({ - id: orderId, - items: payload.items, - status: isRealOrder ? "Order Confirmed by Swiggy" : "Preparing at kitchen", - restaurantName: payload.restaurantName || "District Merchant", - isRealOrder - }); - - if (payload.items.length > 0) { - setLastOrderedItem({ - id: payload.items[0].id, - name: payload.items[0].name, - price: payload.items[0].price, - restaurantName: payload.restaurantName, - restaurantId: payload.restaurantId, - protein: payload.items[0].protein, - calories: payload.items[0].calories - }); - } - - setCart([]); - setAppliedCoupon(null); - setCheckoutPayload(null); - setActiveTab('orders'); - }; - - const handleApplyCoupon = () => { - const code = couponCodeInput.trim().toUpperCase(); - const matched = coupons.find(c => c.code === code); - if (!matched) { - setCouponMessage("Invalid Coupon Code ❌"); - return; - } - const subtotal = getCartSubtotal(); - if (subtotal < matched.minOrder) { - setCouponMessage(`Min order value must be ₹${matched.minOrder} ⚠️`); - return; - } - setAppliedCoupon(matched); - setCouponMessage(`Coupon ${matched.code} applied successfully! ✓`); - }; - - const triggerCancelOrder = () => { - if (!activeOrder) return; - const itemsLabel = activeOrder.items.map(i => `${i.quantity}x ${i.name}`).join(', '); - const originalPrice = activeOrder.items.reduce((sum, i) => sum + (i.price * i.quantity), 0); - const timeNow = new Date().toLocaleTimeString(); - - setRescueOffers([ - { - order_id: `rescue_${activeOrder.id}`, - restaurant_name: activeOrder.restaurantName || "Quick Kitchen", - items: itemsLabel, - original_price_inr: originalPrice, - rescue_price_inr: Math.round(originalPrice * 0.5), - sensory_quality_index: 94 - } - ]); - - setSecurityLogs(prev => [ - { time: timeNow, event: `CANCEL: Order ${activeOrder.id} aborted by user.`, type: 'info' }, - { time: timeNow, event: `RESCUE QUEUE: Initialized cooling thermal curve (SQI=94/100).`, type: 'info' }, - ...prev - ]); - - setActiveOrder(null); - }; - - const claimRescueOffer = (offer) => { - const timestamp = new Date().toLocaleTimeString(); - setArbitrageMessage("Arbitrage Blocked: CO_LOCATION_PROXIMITY_ALERT, SHARED_IP_SUBNET_ALERT"); - setSecurityLogs(prev => [ - { time: timestamp, event: `ALERT: Blocked self-buyback exploit (Co-Location distance: 11 meters)`, type: 'error' }, - ...prev - ]); - setRescueOffers([]); - }; - - const handleCreateRestaurant = async (e) => { - e.preventDefault(); - if (!newRestName.trim()) return; - const payload = { - name: newRestName, - cuisine: newRestCuisine || "Global Cuisine", - rating: 4.5, - distance: "1.5 km", - time: `${newRestSLA} min`, - slaConfidence: 96, - isAIPick: false, - isExclusive: newRestExclusive, - image: newRestImage.trim() || "https://images.unsplash.com/photo-1504674900247-0877df9cc836?w=300&auto=format&fit=crop&q=60" - }; - // Optimistic update - const localObj = { ...payload, id: `rest_${Date.now()}`, menu: [{ id: `dish_${Date.now()}_1`, name: "Signature Combo Pack", price: 299, rating: 4.5, desc: "A custom signature combo.", protein: 22, cal: 380, veg: true }] }; - setRestaurants(prev => [...prev, localObj]); - // Persist to backend - const result = await API.createRestaurant(payload); - if (result?.restaurant) { - // Replace local placeholder with backend ID - setRestaurants(prev => prev.map(r => r.id === localObj.id ? { ...localObj, ...result.restaurant } : r)); - } - setSecurityLogs(prev => [ - { time: new Date().toLocaleTimeString(), event: `ADMIN: Added merchant "${newRestName}" | Exclusive: ${newRestExclusive ? 'Yes' : 'No'} | Backend: ${result ? '✓ Synced' : '⚠ Local only'}`, type: 'success' }, - ...prev - ]); - setNewRestName(""); - setNewRestCuisine(""); - setNewRestImage(""); - setNewRestExclusive(false); - }; - - const handleCreateCoupon = async (e) => { - e.preventDefault(); - if (!newCouponCode.trim()) return; - const code = newCouponCode.toUpperCase().replace(/\s+/g, ""); - const newCop = { - code, - pct: parseInt(newCouponPct) || 10, - minOrder: parseInt(newCouponMin) || 100, - desc: `${newCouponPct}% off above ₹${newCouponMin}` - }; - // Optimistic update - setCoupons(prev => [...prev, newCop]); - // Persist to backend - const result = await API.createCoupon(newCop); - setSecurityLogs(prev => [ - { time: new Date().toLocaleTimeString(), event: `ADMIN: Created coupon "${code}" (${newCouponPct}% off) | Backend: ${result ? '✓ Synced' : '⚠ Local only'}`, type: 'success' }, - ...prev - ]); - setNewCouponCode(""); - }; - - const handleBookTableSlot = async (hotelName, slotTime) => { - const localRes = { - id: `res_${Math.floor(Math.random() * 89999) + 10000}`, - hotel: hotelName, - time: slotTime, - party: 2, - status: "CONFIRMED" - }; - // Optimistic update - setReservations(prev => [localRes, ...prev]); - // Persist to backend - const result = await API.reserveDineout({ hotel: hotelName, time: slotTime, party: 2 }); - if (result?.reservation) { - setReservations(prev => prev.map(r => r.id === localRes.id ? { ...localRes, ...result.reservation } : r)); - } - confetti({ particleCount: 60, spread: 50 }); - alert(`Table Reserved successfully at ${hotelName} for ${slotTime}! ✓`); - }; - - const handleSwapOOSItem = (itemId, altItemName, altPrice) => { - setGroceries(prev => prev.map(item => { - if (item.id === itemId) { - return { - ...item, - name: altItemName, - price: altPrice, - stock: 12, - brand: "GoodLife", - image: "https://images.unsplash.com/photo-1563636619-e9143da7973b?w=200&auto=format&fit=crop&q=60" - }; - } - return item; - })); - setSecurityLogs(prev => [ - { time: new Date().toLocaleTimeString(), event: `REPLACEMENT: Swapped out-of-stock ${itemId} with alternative "${altItemName}"`, type: 'success' }, - ...prev - ]); - }; - - const handleToggleGroceryStock = (id) => { - setGroceries(prev => prev.map(item => { - if (item.id === id) { - const newStock = item.stock === 0 ? 20 : 0; - setSecurityLogs(prevLogs => [ - { time: new Date().toLocaleTimeString(), event: `ADMIN: SKU ${id} stock toggled to ${newStock === 0 ? 'STOCKOUT (Censored)' : 'IN_STOCK'}`, type: 'info' }, - ...prevLogs - ]); - return { ...item, stock: newStock }; - } - return item; - })); - }; - - const processRefundTriage = (disputeId) => { - const timestamp = new Date().toLocaleTimeString(); - setDisputesQueue(prev => prev.map(disp => { - if (disp.id === disputeId) { - const isBehrouz = disp.merchantId === 'rest_behrouz'; - let decision = "APPROVED (Auto-Refund)"; - let reason = "Approved: High tenant tenure, 0 recent refund requests."; - let fraudProb = 0.08; - - if (isBehrouz) { - decision = "FLAGGED (Manual Triage)"; - reason = "Flagged: Multiple claims from same IP subnet on high-end merchant."; - fraudProb = 0.89; - } - - setSecurityLogs(prevLogs => [ - { time: timestamp, event: `FRAUD GUARD: Dispute ${disputeId} processed. Decision: ${decision}. Score: ${(fraudProb * 100).toFixed(0)}%`, type: fraudProb > 0.5 ? 'error' : 'success' }, - ...prevLogs - ]); - - return { ...disp, status: decision, fraudProb, reason }; - } - return disp; - })); - }; - - const handlePayUpgradeTier = (upgradeAmount, targetTierName) => { - setExpenseLogs(prev => [ - ...prev, - { id: Date.now(), name: "Upgrade", amount: upgradeAmount, calories: 0 } - ]); - - // Blast confetti celebration - confetti({ - particleCount: 150, - spread: 80, - origin: { y: 0.5 } - }); - - setSecurityLogs(prev => [ - { time: new Date().toLocaleTimeString(), event: `LOYALTY TIER: User completed direct pay upgrade to ${targetTierName} card.`, type: 'success' }, - ...prev - ]); - }; - - const sendAgentMessage = async () => { - if (!chatInput.trim()) return; - const userMsg = chatInput.trim(); - setChatInput(""); - - const newMessages = [...chatMessages, { sender: 'user', text: userMsg, time: new Date().toLocaleTimeString() }]; - setChatMessages(newMessages); - setIsAgentThinking(true); - setAgentThinkingTools(['agent_brain_router']); - - try { - const response = await fetch('/api/v1/chat', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - message: userMsg, - history: chatMessages.map(m => ({ - role: m.sender === 'user' ? 'user' : 'model', - text: m.text - })) - }) - }); - - const data = await response.json(); - setIsAgentThinking(false); - setChatMessages(prev => [...prev, { - sender: 'agent', - text: data.reply, - time: new Date().toLocaleTimeString(), - tools: data.tools || [] - }]); - } catch (err) { - console.error("AI Agent Chat error:", err); - setIsAgentThinking(false); - setChatMessages(prev => [...prev, { - sender: 'agent', - text: "Sorry, I had trouble communicating with my backend brain. Please verify that your backend server is running and the Gemini API key is configured.", - time: new Date().toLocaleTimeString(), - tools: [] - }]); - } - }; - - if (showLockScreen) { - return ( - { - setShowLockScreen(false); - setShowSplash(true); - }} - /> - ); - } - - if (showSplash) { - return ( -
setShowSplash(false)} - className="fixed inset-0 bg-[#FF5200] z-[9999] flex flex-col items-center justify-center overflow-hidden cursor-pointer font-sans" - > - {/* Swiggy Logo (Main File) */} -
- {/* Swiggy Map Pin Logo in white */} -
- - - - -
- {/* Swiggy text wordmark in white */} -

- SWIGGY -

-
-
- ); - } - - if (!isLoggedIn) { - return setIsLoggedIn(true)} />; - } - - if (appView === 'demand_oracle') { - return setAppView('consumer')} />; - } - - if (appView === 'eta_truth') { - return setAppView('consumer')} />; - } - - if (appView === 'refund_oracle') { - return setAppView('consumer')} />; - } - - if (appView === 'dineout_sniper') { - return setAppView('consumer')} />; - } - - if (appView === 'dispatch_map') { - return setAppView('consumer')} />; - } - - if (appView === 'admin') { - return setAppView('consumer')} onNavigateView={(view) => setAppView(view)} />; - } - - if (appView === 'merchant_stock_admin') { - return setAppView('admin')} />; - } - - if (appView === 'fleet_logistics_admin') { - return setAppView('admin')} />; - } - - if (appView === 'financial_ops_admin') { - return setAppView('admin')} />; - } - - if (appView === 'growth_analytics_admin') { - return setAppView('admin')} />; - } - - if (appView === 'refund_status') { - return setAppView('admin')} />; - } - - if (appView === 'help_support') { - return setAppView('admin')} onOpenChatbot={() => setAppView('chatbot_help')} />; - } - - if (appView === 'chatbot_help') { - return setAppView('help_support')} />; - } - - if (appView === 'festival_theme_manager') { - return ( - { - setFestivalTheme(newTheme); - }} - onBack={() => setAppView('admin')} - /> - ); - } - - if (appView === 'loyalty') { - return ( - setAppView('consumer')} - onNavigate={(tab) => { - if (tab === 'home') { - setAppView('consumer'); - setActiveTab('home'); - } else if (tab === 'dineout') { - setAppView('consumer'); - setActiveTab('dineout'); - } else if (tab === 'quick') { - setAppView('consumer'); - setActiveTab('quick'); - } else if (tab === 'agent_chat') { - setAppView('consumer'); - setChatOpen(true); - } - }} - cartCount={cart.reduce((acc, item) => acc + (item.quantity || 1), 0)} - /> - ); - } - - if (chatOpen) { - return ( - setChatOpen(false)} - messages={chatMessages} - onSendMessage={sendAgentMessage} - /> - ); - } - - if (activeOrder) { - return ( - setActiveOrder(null)} - riderPos={getInterpolatedPosition(HUB_COORDINATES.Bhubaneswar.route, riderProgress)} - routePoints={HUB_COORDINATES.Bhubaneswar.route} - orderStatus={riderProgress >= 100 ? "Arrived" : riderProgress >= 70 ? "Rider is delivering" : "Rider is picking up food"} - etaMinutes={Math.max(1, Math.round(15 * (1 - riderProgress / 100)))} - onChatClick={() => setChatOpen(true)} - /> - ); - } - - if (paymentScreenOpen) { - return ( - setPaymentScreenOpen(false)} - onUpdateQuantity={updateCartQty} - onPlaceOrder={(payload) => { - const directPayload = { - items: cart, - restaurantName: cart[0]?.restaurantName || 'Instamart Store', - restaurantId: cart[0]?.restaurantId || 'im_store', - total: payload.grandTotal - }; - setCheckoutPayload(directPayload); - setCart([]); - setPaymentScreenOpen(false); - setActiveOrder({ - id: 'ORD-' + (Math.floor(Math.random() * 89999) + 10000), - items: cart, - total: payload.grandTotal, - status: 'Preparing your meal' - }); - setRiderProgress(0); - executePaymentSuccess(directPayload); - }} - coupons={coupons} - /> - ); - } - - if (restaurantPageOpen && selectedRestaurant) { - return ( - setRestaurantPageOpen(false)} - onAddToCart={handleAddToCart} - onCheckout={() => { setRestaurantPageOpen(false); setPaymentScreenOpen(true); }} - cart={cart} - /> - ); - } - - if (appView === 'consumer') { - return ( - setChatOpen(true)} - onOpenCheckout={() => setPaymentScreenOpen(true)} - onOpenOps={() => setAppView('intel')} - onOpenProfile={() => setAppView('loyalty')} - cart={cart} - /> - ); - } - return ( -
- - {/* ─── Premium Glassmorphic Header ─── */} - {!isMobileDevice && ( -
-
-
- HF -
- - HyperFlow 3.0 - -
- - {/* View Switchers */} -
-
- - - -
-
- - {/* User Badging */} -
- {liveMetrics ? ( -
- - API: LIVE - | - ✓ {liveMetrics.reservation_success_rate}% - | - ETA Δ {liveMetrics.eta_bump_rate}% - | - ⚠ {liveMetrics.restock_alerts_count} -
- ) : ( -
- - SWIGGY MCP: ACTIVE -
- )} -
- Gaurav Nayak -
GN
-
-
-
- )} - - - {/* ─── Main Viewport Grid ─── */} -
- - {/* VIEW 1: CONSUMER EXPERIENCE */} - {appView === 'consumer' && ( - setChatOpen(true)} - onOpenCheckout={() => setPaymentScreenOpen(true)} - onOpenOps={() => setAppView('admin')} - cart={cart} - /> - )} - - {/* VIEW 2: OPERATIONS COMMAND DESK (INTEL VIEW) */} - {appView === 'intel' && ( -
-
-
-

Operations & Intel Command Center

-

- Active monitoring of Tobit MLE parameters, spatial route optimization algorithms, and anti-fraud filters. -

-
-
- -
- {/* Box 1: Tobit MLE — live from /api/v1/metrics/availability */} -
-

- - Q1: Tobit MLE Demand Estimator - {availabilityMetrics && ● LIVE} -

-
-
- Censored Rate: - {availabilityMetrics ? `${(availabilityMetrics.censoring_rate * 100).toFixed(0)}%` : `${(censoringRate * 100).toFixed(0)}%`} -
-
- Availability Rate: - {availabilityMetrics ? `${(availabilityMetrics.availability_rate * 100).toFixed(1)}%` : '94.7%'} -
-
- WMAPE Lift: - {availabilityMetrics ? `+${(availabilityMetrics.wmape_lift * 100).toFixed(1)}%` : `+${forecastOutput.lift_pct.toFixed(1)}%`} -
-
- Avg Wastage: - {availabilityMetrics ? `${availabilityMetrics.average_wastage_units} units` : '4.2 units'} -
-
-
- - {/* Box 2: ETA Jitter Smoother — live from /api/v1/metrics/bump-rate */} -
-

- - Q2: ETA Jitter Smoother - {bumpRateMetrics && ● LIVE} -

-
-
- Raw MIMO Bumps: - {bumpRateMetrics?.raw_mimo_bumps ?? 113} -
-
- Gated Bumps: - {bumpRateMetrics?.gated_smoother_bumps ?? 21} -
-
- Suppression: - {bumpRateMetrics ? `${bumpRateMetrics.jitter_suppression_pct}%` : '81.4%'} -
-
- Storm Surge: - - {bumpRateMetrics?.zone_status ?? (stormSurge ? 'ACTIVE' : 'INACTIVE')} - -
-
-
- - {/* Box 3: ML Robustness — live from /api/v1/metrics/robustness */} -
-

- - Q3: ML Robustness (PSI) - {mlRobustness && ● LIVE} -

-
- {mlRobustness ? ( - <> - {Object.entries(mlRobustness.features_drift || {}).map(([feat, m]) => ( -
- {feat.replace('weather_', '').replace('_elapsed_sec', '_time')}: - - PSI {m.psi?.toFixed(3)} - -
- ))} -
- Clipped Today: - {mlRobustness.clipping_guard?.total_clipped_observations_today ?? 0} -
- - - ) : ( - <> - {rescueOffers.length > 0 ? ( -
-

Resale Opportunity Identified:

- -
- ) : ( -
Sybil-Guard: No active resale offers in pool.
- )} - - )} -
-
-
- - - {/* GIS Routing Map and security log terminal */} -
-
-

Spatial Routing (Bhubaneswar Hub)

-
- -
-
- -
-

Live Console Logs

-
- {arbitrageMessage &&
{arbitrageMessage}
} - {securityLogs.map((log, idx) => ( -
- [{log.time}] - {log.event} -
- ))} -
-
-
-
- )} - - {appView === 'admin' && ( -
-
-
-

Operations Parameter Configurator

-

- Inject anomalies, monitor pick deadlines, review merchant portals, and configure logistics surge incentives. -

-
-
- {[ - { id: 'system', name: '⚙️ System' }, - { id: 'restaurant', name: '🍳 Partner Portal' }, - { id: 'picking', name: '📦 Dark Store Pick' }, - { id: 'logistics', name: '🚴 Fleet Dispatch' } - ].map(tab => ( - - ))} -
-
- - {/* CONDITIONAL SUB-TABS RENDERING */} - {adminSubTab === 'system' && ( - <> - {/* Two-Column Top Grid */} -
- - {/* Merchant Restaurant Creator */} -
-
-

- storefront - Merchant Restaurant Creator -

-
-
-
- - setNewRestName(e.target.value)} - className="px-3 py-2 text-xs bg-white/5 border border-white/10 rounded-lg text-white outline-none focus:ring-2 focus:ring-[#FF0077]/50 focus:border-[#FF0077] transition-all" - /> -
-
- - setNewRestCuisine(e.target.value)} - className="px-3 py-2 text-xs bg-white/5 border border-white/10 rounded-lg text-white outline-none focus:ring-2 focus:ring-[#FF0077]/50 focus:border-[#FF0077] transition-all" - /> -
-
- - setNewRestImage(e.target.value)} - className="px-3 py-2 text-xs bg-white/5 border border-white/10 rounded-lg text-white outline-none focus:ring-2 focus:ring-[#FF0077]/50 focus:border-[#FF0077] transition-all font-mono" - /> -
-
- - setNewRestSLA(parseInt(e.target.value) || 20)} - className="px-3 py-2 text-xs bg-white/5 border border-white/10 rounded-lg text-white outline-none focus:ring-2 focus:ring-[#FF0077]/50 focus:border-[#FF0077] transition-all font-mono" - /> -
-
- setNewRestExclusive(!newRestExclusive)} - className="w-4 h-4 rounded bg-white/5 border border-white/10 text-[#FF0077] focus:ring-0 cursor-pointer" - id="exclusivePartner" - /> - -
- -
-
- - {/* Coupon & Offer Builder */} -
-
-

- local_offer - Coupon & Offer Builder -

-
-
-
- - setNewCouponCode(e.target.value.toUpperCase())} - className="px-3 py-2 text-xs bg-white/5 border border-white/10 rounded-lg text-white outline-none focus:ring-2 focus:ring-[#8F00FF]/50 focus:border-[#8F00FF] transition-all font-mono uppercase" - /> -
-
- - setNewCouponPct(parseInt(e.target.value) || 10)} - className="px-3 py-2 text-xs bg-white/5 border border-white/10 rounded-lg text-white outline-none focus:ring-2 focus:ring-[#8F00FF]/50 focus:border-[#8F00FF] transition-all font-mono" - /> -
-
- - setNewCouponMin(parseInt(e.target.value) || 200)} - className="px-3 py-2 text-xs bg-white/5 border border-white/10 rounded-lg text-white outline-none focus:ring-2 focus:ring-[#8F00FF]/50 focus:border-[#8F00FF] transition-all font-mono" - /> -
- -
-
-
- - {/* Three-Column Bottom Configurator Row */} -
- - {/* Column 1: Instamart Stock Controls */} -
-
-

- inventory_2 - Instamart Stock Sync -

-
-
- {groceries.map(item => ( -
-
-
- local_drink -
-
- {item.name} - SKU: SKU-{item.id.toUpperCase()} -
-
- -
- ))} -
-
- - {/* Column 2: System Parameters & Overrides */} -
-
-

- tune - Global Overrides -

-
- -
- -
- {['nominal', 'diwali', 'holi'].map(tName => ( - - ))} -
-
- -
-
-
- thunderstorm - Monsoon Surge Alert -
- -
-

Activates dynamic pricing multiplier +1.5x across delivery fleet.

-
-
- - {/* Column 3: Refund Disputes */} -
-
-

- support_agent - Dispute Triage -

-
-
- {disputesQueue.map(disp => ( -
-
- {disp.id || 'ORD-9921-A'} - 2m ago -
-

"{disp.text}"

- -
- ))} -
-
-
- - )} - - {/* TAB 2: PARTNER PORTAL */} - {adminSubTab === 'restaurant' && ( -
- {/* Left Column: Live SLA Accepting queue */} -
-

- - Incoming Zomato/Swiggy Orders (SOP-01 SLA accepting) -

-
- {restaurantOrders.map(order => ( -
- {order.status === 'PENDING' && ( -
- - {order.limit - order.elapsed}s LEFT -
- )} -
- {order.id} -

{order.name}

- {order.items} - Value: ₹{order.price} -
- - {/* Progress Bar showing elapsed SLA accept limit */} - {order.status === 'PENDING' && ( -
-
-
- )} - -
- {order.status === 'PENDING' ? ( - <> - - - - ) : ( -
- Status: - {order.status} -
- )} -
-
- ))} -
-
- - {/* Right Column: Kitchen state flow tracker */} -
-

Merchant Kitchen SLA SOPs

-
-
- Active Preparation Pipelines -
- {restaurantOrders.filter(o => o.status === 'COOKING').length === 0 ? ( - No items currently cooking. - ) : ( - restaurantOrders.filter(o => o.status === 'COOKING').map(o => ( -
- {o.id} - Preparing -
- -
-
- )) - )} -
-
- -
- Completed Ready-to-Deliver Queue -
- {restaurantOrders.filter(o => o.status === 'READY FOR PICKUP').map(o => ( -
- {o.id} - RIDER ASSIGNED -
- ))} -
-
-
-
-
- )} - - {/* TAB 3: DARK STORE PICKING */} - {adminSubTab === 'picking' && ( -
- {/* Left Column: picking sequence checklist */} -
-
-

- Blinkit Picking Layout & Sequence (SOP-02 Target: 90s) -

-
- Pick Time: - 90 ? 'bg-red-500/10 text-red-500' : 'bg-green-500/10 text-green-500'}`}> - {Math.floor(pickingSLA / 60)}m {pickingSLA % 60}s - -
-
- -
- {pickingList.map(item => ( -
-
-
- {item.location.split(',')[1].trim()} -
-
-

{item.name}

- Location: {item.location} | Qty: {item.qty} -
-
-
- {item.status === 'PENDING' ? ( - - ) : ( - - ✓ VERIFIED - - )} -
-
- ))} -
- - {/* Visual Pathway path grid optimizer */} -
- Optimized Picking Path Sequence: -
- Aisle 1 (B2) - - Aisle 2 (A1) - - Aisle 5 (C3) - - Billing Counter -
-
-
- - {/* Right Column: Picking operations manual override */} -
-

Picking Console SOPs

-
-
- Reset Picking Queue -

Simulate a fresh order arrival inside the Dark Store warehouse.

- -
-
-
-
- )} - - {/* TAB 4: RIDER LOGISTICS */} - {adminSubTab === 'logistics' && ( -
- {/* Left Column: Rider dispatch & route batching */} -
-

- Active Delivery Fleet & Route Batching Resolver -

- -
- {riderList.map(rider => ( -
-
- {rider.name} - {rider.status} -
- Location: {rider.location} - {rider.batchedOrders.length > 0 && ( -
- Batched Runs: - {rider.batchedOrders.map(oId => ( - - {oId} - - ))} -
- )} -
- ))} -
- - {/* Batch routing simulator details */} -
- Logistics Engine SOP-03: Route Batching Rules -

- Assigning two separate orders destined for co-located apartments to a single rider reduces cost per delivery (CPD) by 34% and improves rider payouts during peak surge windows. -

-
-
- - {/* Right Column: Fleet weather modifiers */} -
-

Weather & Surge Modifiers

- -
-
-
- Rain Storm Incentives - Applies +₹20 / order to rider payouts -
- -
- -
- Delivery Fee (Consumer side): - {stormSurge ? '₹45 (Rain Surge)' : '₹30'} -
-
-
-
- )} -
- )} - -
- - {/* ─── SCREEN: Floating AI Agent Chat Drawer ─── */} - {chatOpen && ( -
setChatOpen(false)}> -
e.stopPropagation()}> -
-
- -
-

AI Agent

-
-
- -
- -
- {chatMessages.map((msg, idx) => ( -
-
-

{msg.text}

-
-
- ))} -
- -
-
- setChatInput(e.target.value)} - onKeyDown={(e) => { - if (e.key === 'Enter') sendAgentMessage(); - }} - /> - -
-
- -
-
- )} - - {/* Tobit Forecast Modal */} - {activeGroceryForecast && ( -
setActiveGroceryForecast(null)}> -
e.stopPropagation()}> -

Tobit Latent Demand Model

-
-
- Imputed Latent Demand: - {activeGroceryForecast.latent_demand} units / day -
-
- -
-
- )} - -
+ +
+ +
+ + } /> + } /> + } /> + } /> + } /> + } /> + +
+
+
); }