/** * @license * SPDX-License-Identifier: Apache-2.0 */ import React, { useState, useEffect } from 'react'; import { ShoppingBag, Truck, CheckCircle2, Clock, UserCheck, MapPin, TrendingUp, Plus, ChevronRight, Package, ArrowRight, AlertCircle, Clock4, Search, Check, Calendar, X } from 'lucide-react'; import { CustomerOrder } from '../types'; import { useFiestaDeliveries, useFiestaDeliverySummary, useFiestaRiders, } from '../services/fiestaQueries'; import { FIESTA_TENANT_ID, num as fnum, str as fstr, ymd } from '../services/fiestaApi'; import { deliveryRowToOrder } from '../services/fiestaMappers'; interface OrdersDeliveriesViewProps { searchQuery?: string; isCoimbatoreView?: boolean; locationid?: number; } interface DeliveryExecutive { id: string; name: string; phone: string; status: 'Active Duty' | 'Idle' | 'Offline'; rating: number; completedToday: number; currentZone: string; avatar: string; } const RIDER_AVATARS = [ 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?auto=format&fit=crop&w=150&q=80', 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=150&q=80', 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=150&q=80', ]; function riderRowToExecutive(row: Record, idx: number): DeliveryExecutive { return { id: `DE-${fstr(row.userid) || idx}`, name: fstr(row.fullname) || `${fstr(row.firstname)} ${fstr(row.lastname)}`.trim() || 'Rider', phone: fstr(row.contactno) || '—', status: fstr(row.starttime) ? 'Active Duty' : 'Idle', rating: 4.7, completedToday: fnum(row.completed) || fnum(row.deliverycount), currentZone: fstr(row.city) || fstr(row.vehiclename) || fstr(row.vehicleno) || 'Coimbatore', avatar: RIDER_AVATARS[idx % RIDER_AVATARS.length], }; } export default function OrdersDeliveriesView({ searchQuery = '', isCoimbatoreView = false, locationid }: OrdersDeliveriesViewProps) { // ── Live deliveries / fleet (Fiesta) ────────────────────────────────────── // Order feed + dispatch controls run off the live deliveries board; the KPI // strip uses the delivery summary; the fleet panel uses the active riders. // A date-range filter lets the user view orders/deliveries day-wise. const today = new Date(); const monthStart = new Date(today.getFullYear(), today.getMonth(), 1); const [fromdate, setFromdate] = useState(ymd(monthStart)); const [todate, setTodate] = useState(ymd(today)); // Quick-range presets (computed off the current day; no Date.now in render path). const dayOffset = (n: number) => { const d = new Date(); d.setDate(d.getDate() - n); return ymd(d); }; const presets: Array<{ key: string; label: string; from: string; to: string }> = [ { key: 'today', label: 'Today', from: ymd(today), to: ymd(today) }, { key: 'yesterday', label: 'Yesterday', from: dayOffset(1), to: dayOffset(1) }, { key: '7d', label: 'Last 7 Days', from: dayOffset(6), to: ymd(today) }, { key: '30d', label: 'Last 30 Days', from: dayOffset(29), to: ymd(today) }, { key: 'month', label: 'This Month', from: ymd(monthStart), to: ymd(today) }, ]; const activePreset = presets.find((p) => p.from === fromdate && p.to === todate)?.key ?? 'custom'; const deliveriesQ = useFiestaDeliveries({ tenantid: FIESTA_TENANT_ID, fromdate, todate }); const summaryQ = useFiestaDeliverySummary({ tenantid: FIESTA_TENANT_ID, fromdate, todate }); const ridersQ = useFiestaRiders({ tenantid: FIESTA_TENANT_ID }); const [orders, setOrders] = useState([]); const [executives, setExecutives] = useState([]); const [selectedOrder, setSelectedOrder] = useState(null); const [filterStatus, setFilterStatus] = useState('ALL'); const [localSearch, setLocalSearch] = useState(''); // Seed local state once live data arrives so existing dispatch/create handlers // continue to mutate in-session. useEffect(() => { if (deliveriesQ.data) { const mapped = deliveriesQ.data.map(deliveryRowToOrder); setOrders(mapped); // Keep the current selection only if it's still in the new range; otherwise // fall back to the first order so the detail panel stays in sync. setSelectedOrder((prev) => (prev && mapped.some((o) => o.id === prev.id)) ? prev : mapped[0] ?? null, ); } }, [deliveriesQ.data]); useEffect(() => { if (ridersQ.data) setExecutives(ridersQ.data.map(riderRowToExecutive)); }, [ridersQ.data]); const summary = summaryQ.data; // Local filtered list of orders const storeOrders = locationid ? orders.filter(o => o.locationid === locationid) : orders; const filteredOrdersList = storeOrders.filter(o => { const term = (localSearch || searchQuery).toLowerCase(); const matchesSearch = o.id.toLowerCase().includes(term) || o.customerName.toLowerCase().includes(term) || o.address.toLowerCase().includes(term); const matchesFilter = filterStatus === 'ALL' || o.status === filterStatus; return matchesSearch && matchesFilter; }); // Calculate dynamic stats for metrics cards based on filtered storeOrders const totalDeliveriesCount = storeOrders.length; const pendingFulfillmentCount = storeOrders.filter(o => o.status === 'PROCESSING' || o.status === 'CONFIRMED').length; const activeDispatchCount = storeOrders.filter(o => o.status === 'OUT_FOR_DELIVERY').length; const completedDeliveriesCount = storeOrders.filter(o => o.status === 'DELIVERED').length; const MOCK_NAMES = ['Aravind Swamy', 'Karthik Raja', 'Priya Mani', 'Meera Jasmine', 'Sanjay Dutt', 'Divya Spandana', 'Vijay Sethupathi', 'Nayan Thara']; const MOCK_STREETS = ['Avarampalayam Rd', 'DB Road', 'Cross Cut Road', 'Avinashi Road', 'Trichy Road', 'NSR Road', 'Sathy Road', 'Marudhamalai Road']; const MOCK_ITEMS = [ { name: 'Tata Salt Premium Iodized 1kg', price: 28 }, { name: 'Gold Winner Sunflower Oil 1L', price: 145 }, { name: 'Britannia Marie Gold Biscuit 250g', price: 35 }, { name: 'MTR Sambar Powder 200g', price: 85 }, { name: 'Aavin Salted Butter 500g', price: 260 }, { name: 'Ponni Boiled Rice 5kg', price: 380 }, { name: 'Fresh Ooty Carrots 500g', price: 45 }, { name: 'Nescafe Classic Coffee 100g', price: 185 }, ]; const handleCreateMockOrder = () => { const randomName = MOCK_NAMES[Math.floor(Math.random() * MOCK_NAMES.length)]; const randomStreet = MOCK_STREETS[Math.floor(Math.random() * MOCK_STREETS.length)]; const numItems = Math.floor(Math.random() * 3) + 1; // 1 to 3 items const selectedItems = []; let amount = 0; for (let k = 0; k < numItems; k++) { const it = MOCK_ITEMS[Math.floor(Math.random() * MOCK_ITEMS.length)]; const qty = Math.floor(Math.random() * 2) + 1; selectedItems.push({ name: it.name, quantity: qty, price: it.price }); amount += it.price * qty; } const newId = `ORD-${Math.floor(100000 + Math.random() * 900000)}`; const newOrder: CustomerOrder = { id: newId, customerName: randomName, phone: `9${Math.floor(100000000 + Math.random() * 900000000)}`, address: `${Math.floor(10 + Math.random() * 190)}, ${randomStreet}, Coimbatore`, items: selectedItems, amount, time: new Date().toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' }), status: 'PROCESSING', assignedRider: 'Pending Assignment', hub: locationid ? `Outlet Node #${locationid}` : 'Coimbatore Hub', locationid: locationid ?? 1097, }; setOrders(prev => [newOrder, ...prev]); setSelectedOrder(newOrder); }; const handleUpdateStatus = (newStatus: CustomerOrder['status']) => { if (!selectedOrder) return; setOrders(prev => prev.map(o => { if (o.id === selectedOrder.id) { const updated = { ...o, status: newStatus }; setSelectedOrder(updated); return updated; } return o; })); }; const handleAssignRider = (riderName: string) => { if (!selectedOrder) return; setOrders(prev => prev.map(o => { if (o.id === selectedOrder.id) { const updated = { ...o, assignedRider: riderName, status: o.status === 'PROCESSING' ? 'CONFIRMED' : o.status }; setSelectedOrder(updated); return updated; } return o; })); }; return (
{/* View Header with Statistics Overview */}

Orders & Delivery Operations

Real-time tracking of app orders, dispatch queues, and active delivery partners across Coimbatore regional sub-hubs.

{deliveriesQ.isLoading ? ( Loading live deliveries… ) : deliveriesQ.isError ? ( Live data unavailable ) : ( Live · {orders.length} deliveries · {executives.length} riders )}
{/* Top Level Delivery Performance Indicators */}

Deliveries in Range

{totalDeliveriesCount.toLocaleString('en-IN')} total

{fromdate === todate ? fromdate : `${fromdate} → ${todate}`}

Pending Fulfilment

{pendingFulfillmentCount + activeDispatchCount} active

Awaiting dispatch / in transit

Successful Deliveries

{completedDeliveriesCount} done

{locationid ? 'At this location' : 'Across all locations'}

Active Delivery Fleet

{executives.filter(e => e.status !== 'Offline').length} partners

{executives.length} riders registered

{/* Day-wise date filter — drives the live deliveries + summary queries */}
View {presets.map((p) => ( ))}
setFromdate(e.target.value)} className="border border-[#e2e8f0] rounded-lg px-2 py-1.5 text-zinc-700 font-medium outline-none focus:ring-1 focus:ring-[#581c87] cursor-pointer" />
setTodate(e.target.value)} className="border border-[#e2e8f0] rounded-lg px-2 py-1.5 text-zinc-700 font-medium outline-none focus:ring-1 focus:ring-[#581c87] cursor-pointer" />
{/* Main interactive segment splits */}
{/* Left List of Customer App Orders */}

Customer Orders Feed ({filteredOrdersList.length})

Interactive list of customer purchases made via client app

{/* Local Search Input */}
setLocalSearch(e.target.value)} className="w-full pl-8 pr-4 py-1.5 border border-[#e2e8f0] rounded-lg text-[11px] outline-none bg-white focus:ring-1 focus:ring-[#581c87] transition-all" />
{/* Filter Status buttons */}
{['ALL', 'PROCESSING', 'CONFIRMED', 'OUT_FOR_DELIVERY', 'DELIVERED'].map((st) => ( ))}
{/* Order item rows */}
{filteredOrdersList.length === 0 ? (
No orders matching status filter found. Try another query or place a mock delivery item.
) : ( filteredOrdersList.map(order => (
setSelectedOrder(order)} className={`p-md flex items-center justify-between hover:bg-zinc-50 border-l-4 transition-all cursor-pointer ${ selectedOrder?.id === order.id ? 'bg-[#faf5ff]/50 border-[#581c87]' : 'border-transparent' }`} >
{order.customerName} • {order.time}

{order.address}

{order.hub} {order.itemCount ?? order.items.length} Items

₹{order.amount.toLocaleString()}

{order.status.replace(/_/g, ' ')}
)) )}
{/* Delivery Executives Fleet Section */}
Coimbatore Delivery Executive Fleet status
{executives.map((ex) => (
{ex.name}

{ex.name}

Zone: {ex.currentZone} • Rated ★{ex.rating}

{ex.status}

Completed: {ex.completedToday}

))}
{selectedOrder ? (
Order Details: {selectedOrder.id} {/* Customer summary */}
Customer Name {selectedOrder.customerName}
Contact info {selectedOrder.phone}
Delivery Address

{selectedOrder.address}

{/* Category items description list */}
Ordered Grocery basket Items:
{selectedOrder.items.length === 0 && (
{selectedOrder.itemCount ?? 0} line item(s) Detail lines not loaded on board view
)} {selectedOrder.items.map((item, idx) => (

{item.name}

Qty: {item.quantity} x ₹{item.price}

₹{(item.price * Number(item.quantity))}
))}
Grand Total Invoice ₹{selectedOrder.amount.toLocaleString()}
{/* Interactive Status advancement controls */}
OPERATIONAL CONTROL {selectedOrder.status === 'PROCESSING' && ( )} {selectedOrder.status === 'CONFIRMED' && ( )} {selectedOrder.status === 'OUT_FOR_DELIVERY' && ( )} {selectedOrder.status === 'DELIVERED' && (
Order Completed Successfully
)}
{/* Active Rider Assignment (only if not delivered) */} {selectedOrder.status !== 'DELIVERED' && (
ASSIGN DELIVERY EXECUTIVE Fleet Roster
{executives.length === 0 ? (

No riders currently available.

) : ( executives.map(ex => { const isAssigned = selectedOrder.assignedRider === ex.name; return ( ); }) )}
)} {/* Simulated GPS map tracking path */} {selectedOrder.status === 'OUT_FOR_DELIVERY' && (
LIVE GPS ROUTE TRACKER
{/* Grid background lines */}
{/* Route path line */} {/* Hub Marker */} {/* Destination Marker */}