/** * @license * SPDX-License-Identifier: Apache-2.0 */ import React, { useState, useEffect } from 'react'; import { ShoppingBag, Truck, CheckCircle2, Clock, UserCheck, MapPin, TrendingUp, ChevronRight, Package, ArrowRight, AlertCircle, Clock4, Search, Check, Calendar, X } from 'lucide-react'; import { CustomerOrder } from '../types'; import { useFiestaDeliveries, useFiestaDeliverySummary, useFiestaRiders, useFiestaOrderDetails, } from '../services/fiestaQueries'; import { FIESTA_TENANT_ID, num as fnum, str as fstr, ymd } from '../services/fiestaApi'; import { deliveryRowToOrder } from '../services/fiestaMappers'; import AwaitingApi from './AwaitingApi'; interface OrdersDeliveriesViewProps { searchQuery?: string; isCoimbatoreView?: boolean; locationid?: number; } interface DeliveryExecutive { id: string; name: string; phone: string; status: 'Active Duty' | 'Idle' | 'Offline'; 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', 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; // Live line-item details for the currently selected order. The deliveries board // only carries an itemCount; the actual basket lines come from this endpoint. const orderDetailsQ = useFiestaOrderDetails(selectedOrder?.id ?? null); const orderItems = (orderDetailsQ.data ?? []).map((row) => { const quantity = fnum(row.quantity) || fnum(row.qty); const price = fnum(row.price) || fnum(row.unitprice); const lineTotal = fnum(row.amount) || price * quantity; return { name: fstr(row.productname) || fstr(row.itemname) || 'Item', quantity, price, lineTotal, }; }); 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 — flex-fills the column so the feed matches the Order Details card height */}
{filteredOrdersList.length === 0 ? (
No orders matching status filter found. Try another query or adjust the date range.
) : ( 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, ' ')}
)) )}
{/* Right column — Order Details, shown parallel to the orders feed */}
{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:
{orderDetailsQ.isLoading && (
Loading order line items…
)} {!orderDetailsQ.isLoading && orderItems.length === 0 && (
{selectedOrder.itemCount ?? 0} line item(s) Detail lines not loaded on board view
)} {orderItems.map((item, idx) => (

{item.name}

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

₹{item.lineTotal}
))}
Grand Total Invoice ₹{selectedOrder.amount.toLocaleString()}
{/* Live GPS route tracker — no rider-telemetry/GPS API yet */} {selectedOrder.status === 'OUT_FOR_DELIVERY' && (
LIVE GPS ROUTE TRACKER
)} {/* Delivery tracking visual roadmap layout */}
Live Dispatch Timeline Tracker
Order Received ({selectedOrder.time})

Placed via customer app cart checkout successfully.

Assortment Packaged & Bagged

Verified fresh produce items in-stock levels.

Out for Delivery

Dispatched with executive partner on bike route.

Handover Verified

Delivered directly to door step location.

) : (
Select any customer order from the feed to view its details.
)}
); }