Files
daily_merchant_web/src/components/StoreDetailView.tsx

1550 lines
87 KiB
TypeScript

/**
* @license
* SPDX-License-Identifier: Apache-2.0
*/
import React, { useState, useEffect } from 'react';
import {
ArrowLeft,
Calendar,
TrendingUp,
Layers,
Users,
Phone,
MapPin,
AlertTriangle,
Clock,
Activity,
CheckCircle2,
Package,
Search,
ShoppingCart,
Send,
Download,
X,
Battery,
ShieldCheck,
Globe,
UploadCloud,
FileText,
Mail,
UserCheck,
CreditCard,
History,
Building,
Award,
ShoppingBag
} from 'lucide-react';
import {
useFiestaStockStatement,
useFiestaTenantCustomers,
FIESTA_TENANT_ID
} from '../services/fiestaQueries';
import { str as fstr } from '../services/fiestaApi';
import {
initialInventory,
initialCustomerOrders,
operationalAlerts
} from '../data';
import ragulStoreCover from '../assets/images/store_front_view_1780299351800.png';
import OrdersDeliveriesView from './OrdersDeliveriesView';
interface StoreDetailViewProps {
store: {
locationid?: number;
name: string;
zone: string;
deliveries: number;
sales: string;
orders?: number;
staff: string;
color: string;
status: string;
};
onBack: () => void;
}
// ── Master Global Catalogue Items ──
const GLOBAL_CATALOGUE_ITEMS = [
{ sku: 'SALT-TATA-1KG', name: 'Tata Salt Premium Iodized 1kg', category: 'Staples / Salt', price: 28, image: 'https://images.unsplash.com/photo-1626132647523-66f5bf380027?auto=format&fit=crop&w=150&q=80' },
{ sku: 'SUN-OIL-1LIT', name: 'Gold Winner Sunflower Oil 1L', category: 'Groceries / Oils', price: 145, image: 'https://images.unsplash.com/photo-1474979266404-7eaacbcd87c5?auto=format&fit=crop&w=150&q=80' },
{ sku: 'BISCUIT-MAR-GD', name: 'Britannia Marie Gold Biscuit 250g', category: 'Snacks / Biscuits', price: 35, image: 'https://images.unsplash.com/photo-1558961363-fa8fdf82db35?auto=format&fit=crop&w=150&q=80' },
{ sku: 'SPICE-SAMBAR-MTR', name: 'MTR Sambar Powder 200g', category: 'Groceries / Spices', price: 85, image: 'https://images.unsplash.com/photo-1596040033229-a9821ebd058d?auto=format&fit=crop&w=150&q=80' },
{ sku: 'AAVIN-BUTTER-500', name: 'Aavin Salted Butter 500g', category: 'Dairy / Butter', price: 260, image: 'https://images.unsplash.com/photo-1589985270826-4b7bb135bc9d?auto=format&fit=crop&w=150&q=80' }
];
// Fallback cover images
const DETAIL_STORE_COVERS = [
'https://images.unsplash.com/photo-1542838132-92c53300491e?auto=format&fit=crop&w=800&q=80',
'https://images.unsplash.com/photo-1578916171728-46686eac8d58?auto=format&fit=crop&w=800&q=80',
'https://images.unsplash.com/photo-1604719312566-8912e9227c6a?auto=format&fit=crop&w=800&q=80',
'https://images.unsplash.com/photo-1534723452862-4c874018d66d?auto=format&fit=crop&w=800&q=80',
'https://images.unsplash.com/photo-1582408929130-98a2c2640b8a?auto=format&fit=crop&w=800&q=80',
'https://images.unsplash.com/photo-1516594798947-e65505dbb29d?auto=format&fit=crop&w=800&q=80',
'https://images.unsplash.com/photo-1601599561263-60a4e4e083cd?auto=format&fit=crop&w=800&q=80',
'https://images.unsplash.com/photo-1441986300917-64674bd600d8?auto=format&fit=crop&w=800&q=80',
'https://images.unsplash.com/photo-1528698827591-e19ccd7bc23d?auto=format&fit=crop&w=800&q=80',
'https://images.unsplash.com/photo-1536697246787-1f7ae568d89a?auto=format&fit=crop&w=800&q=80',
'https://images.unsplash.com/photo-1506617498306-bd97b3663b65?auto=format&fit=crop&w=800&q=80',
'https://images.unsplash.com/photo-1579621970563-ebec7560ff3e?auto=format&fit=crop&w=800&q=80'
];
export default function StoreDetailView({ store, onBack }: StoreDetailViewProps) {
const [activeTab, setActiveTab] = useState<'overview' | 'inventory' | 'customers' | 'orders'>('overview');
const isRagul = store.name.toLowerCase().includes('ragul');
const getStoreCover = () => {
if (isRagul) return ragulStoreCover;
let hash = 0;
for (let j = 0; j < store.name.length; j++) {
hash = store.name.charCodeAt(j) + ((hash << 5) - hash);
}
const idx = Math.abs(hash) % DETAIL_STORE_COVERS.length;
return DETAIL_STORE_COVERS[idx];
};
const storeCoverImage = getStoreCover();
const [stockSearch, setStockSearch] = useState('');
const [customerSearch, setCustomerSearch] = useState('');
const [hoveredChartIndex, setHoveredChartIndex] = useState<number | null>(null);
// ── Toast Notification state ──────────────────────────────────────────────
const [toast, setToast] = useState<{ show: boolean; message: string; type: 'success' | 'info' | 'warning' }>({
show: false,
message: '',
type: 'success'
});
const showToast = (message: string, type: 'success' | 'info' | 'warning' = 'success') => {
setToast({ show: true, message, type });
setTimeout(() => {
setToast(prev => ({ ...prev, show: false }));
}, 4000);
};
// ── Replenishment Modal state ──────────────────────────────────────────────
const [replenishModal, setReplenishModal] = useState<{ show: boolean; item: any | null }>({
show: false,
item: null
});
const [replenishQty, setReplenishQty] = useState(100);
// ── Catalogue Local State & Modals ────────────────────────────────────────
const [localInventory, setLocalInventory] = useState<any[]>([]);
const [showImportModal, setShowImportModal] = useState(false);
const [importState, setImportState] = useState<'idle' | 'reading' | 'parsing' | 'saving' | 'done'>('idle');
const [showGlobalModal, setShowGlobalModal] = useState(false);
const [selectedGlobalSkus, setSelectedGlobalSkus] = useState<string[]>([]);
// ── Customer CRM Profile Drawer state ──────────────────────────────────────
const [selectedCustomer, setSelectedCustomer] = useState<any | null>(null);
// ── API Queries with live locationid ───────────────────────────────────────
const locationid = store.locationid || 1097;
const stockQ = useFiestaStockStatement({
tenantid: FIESTA_TENANT_ID,
locationid,
pagesize: 100
});
const customersQ = useFiestaTenantCustomers({
tenantid: FIESTA_TENANT_ID,
locationid,
pagesize: 100
});
// ── Seed / Fallback calculation helpers ────────────────────────────────────
const parseOrdersCount = (salesStr: string): number => {
const num = parseInt(salesStr.replace(/[^0-9]/g, ''), 10);
return isNaN(num) ? 45 : num;
};
const baseOrders = parseOrdersCount(store.sales);
const revenueToday = baseOrders > 100 ? Math.round(baseOrders * 320) : 48200;
// ── Interval slots with heights for chart representation ──────────────────
const intervalSlots = [
{ time: '06:00 AM - 10:00 AM', label: 'Morning Rush', orders: Math.round(store.deliveries * 0.35) || 14, sales: `${Math.round(revenueToday * 0.3).toLocaleString('en-IN')}`, height: '70%', status: 'PEAK' },
{ time: '10:00 AM - 02:00 PM', label: 'Mid-day Deliveries', orders: Math.round(store.deliveries * 0.25) || 10, sales: `${Math.round(revenueToday * 0.25).toLocaleString('en-IN')}`, height: '50%', status: 'NORMAL' },
{ time: '02:00 PM - 06:00 PM', label: 'Afternoon Dispatch', orders: Math.round(store.deliveries * 0.15) || 6, sales: `${Math.round(revenueToday * 0.15).toLocaleString('en-IN')}`, height: '30%', status: 'LOW' },
{ time: '06:00 PM - 10:00 PM', label: 'Evening Surge', orders: Math.round(store.deliveries * 0.2) || 8, sales: `${Math.round(revenueToday * 0.25).toLocaleString('en-IN')}`, height: '45%', status: 'HIGH' },
{ time: '10:00 PM - 06:00 AM', label: 'Night Prep', orders: Math.round(store.deliveries * 0.05) || 2, sales: `${Math.round(revenueToday * 0.05).toLocaleString('en-IN')}`, height: '15%', status: 'LOW' }
];
const activeSlotIndex = hoveredChartIndex !== null ? hoveredChartIndex : 0;
const activeSlot = intervalSlots[activeSlotIndex];
// Past 7 Days Log
const pastDaysLog = [
{ day: 'Wednesday (Today)', orders: store.deliveries || 40, sales: `${revenueToday.toLocaleString('en-IN')}`, rate: '98.2%', change: '+4.5%' },
{ day: 'Tuesday', orders: Math.round(store.deliveries * 0.9) || 36, sales: `${Math.round(revenueToday * 0.88).toLocaleString('en-IN')}`, rate: '100%', change: '+1.2%' },
{ day: 'Monday', orders: Math.round(store.deliveries * 0.85) || 34, sales: `${Math.round(revenueToday * 0.82).toLocaleString('en-IN')}`, rate: '96.8%', change: '-2.1%' },
{ day: 'Sunday', orders: Math.round(store.deliveries * 1.2) || 48, sales: `${Math.round(revenueToday * 1.15).toLocaleString('en-IN')}`, rate: '94.5%', change: '+12.4%' },
{ day: 'Saturday', orders: Math.round(store.deliveries * 1.15) || 46, sales: `${Math.round(revenueToday * 1.12).toLocaleString('en-IN')}`, rate: '99.1%', change: '+8.6%' },
{ day: 'Friday', orders: Math.round(store.deliveries * 0.95) || 38, sales: `${Math.round(revenueToday * 0.92).toLocaleString('en-IN')}`, rate: '97.4%', change: '+2.0%' },
{ day: 'Thursday', orders: Math.round(store.deliveries * 0.9) || 36, sales: `${Math.round(revenueToday * 0.89).toLocaleString('en-IN')}`, rate: '100%', change: '+0.5%' }
];
// Inventory mapping (derived + live merges)
const getMergedInventory = () => {
const rawStock = stockQ.data ?? [];
const resolveMetadata = (name: string) => {
const nameLower = name.toLowerCase();
let price = 60;
let image = 'https://images.unsplash.com/photo-1542838132-92c53300491e?auto=format&fit=crop&w=150&q=80';
if (nameLower.includes('rice')) {
price = 1400;
image = 'https://images.unsplash.com/photo-1586201375761-83865001e31c?auto=format&fit=crop&w=150&q=80';
} else if (nameLower.includes('oil')) {
price = 340;
image = 'https://images.unsplash.com/photo-1474979266404-7eaacbcd87c5?auto=format&fit=crop&w=150&q=80';
} else if (nameLower.includes('coffee')) {
price = 195;
image = 'https://images.unsplash.com/photo-1514432324607-a09d9b4aefdd?auto=format&fit=crop&w=150&q=80';
} else if (nameLower.includes('carrot')) {
price = 60;
image = 'https://images.unsplash.com/photo-1598170845058-32b9d6a5da37?auto=format&fit=crop&w=150&q=80';
} else if (nameLower.includes('ghee')) {
price = 320;
image = 'https://images.unsplash.com/photo-1589985270826-4b7bb135bc9d?auto=format&fit=crop&w=150&q=80';
} else if (nameLower.includes('butter')) {
price = 260;
image = 'https://images.unsplash.com/photo-1589985270826-4b7bb135bc9d?auto=format&fit=crop&w=150&q=80';
} else if (nameLower.includes('salt')) {
price = 28;
image = 'https://images.unsplash.com/photo-1626132647523-66f5bf380027?auto=format&fit=crop&w=150&q=80';
} else if (nameLower.includes('atta') || nameLower.includes('flour')) {
price = 440;
image = 'https://images.unsplash.com/photo-1574316071802-0d684efa7bf5?auto=format&fit=crop&w=150&q=80';
}
return { price, image };
};
if (rawStock.length > 0) {
return rawStock.map((item: any) => {
const name = fstr(item.productname) || fstr(item.name) || 'Product Item';
const meta = resolveMetadata(name);
return {
sku: fstr(item.sku) || fstr(item.productsku) || 'SKU-UNKNOWN',
name,
category: fstr(item.subcategoryname) || fstr(item.categoryname) || 'Groceries / Staples',
stockLevel: Number(item.physicalstock) || Number(item.stock) || 0,
maxCapacity: Number(item.maxcapacity) || 500,
status: (Number(item.physicalstock) || 0) < 50 ? 'Critical' : (Number(item.physicalstock) || 0) < 150 ? 'Low Stock' : 'Optimal',
price: meta.price,
image: meta.image
};
});
}
// High fidelity fallback seeded catalog if live API results are empty
return [
{ sku: 'RICE-PN-50', name: 'Premium Ponni Rice Bag 25kg', category: 'Staples / Rice', stockLevel: Math.round(baseOrders * 1.2) || 450, maxCapacity: 1000, status: 'Optimal', price: 1400, image: 'https://images.unsplash.com/photo-1586201375761-83865001e31c?auto=format&fit=crop&w=150&q=80' },
{ sku: 'ATTA-ASH-10', name: 'Aashirvaad Chakki Atta 10kg', category: 'Staples / Flour', stockLevel: 12, maxCapacity: 120, status: 'Critical', price: 440, image: 'https://images.unsplash.com/photo-1574316071802-0d684efa7bf5?auto=format&fit=crop&w=150&q=80' },
{ sku: 'OIL-IDH-05', name: 'Idhayam Sesame Oil Can 5L', category: 'Groceries / Oils', stockLevel: 32, maxCapacity: 150, status: 'Low Stock', price: 340, image: 'https://images.unsplash.com/photo-1474979266404-7eaacbcd87c5?auto=format&fit=crop&w=150&q=80' },
{ sku: 'COF-NAR-01', name: 'Narasus Filter Coffee 1kg Pack', category: 'Beverages / Coffee', stockLevel: Math.round(baseOrders * 0.5) || 120, maxCapacity: 300, status: 'Optimal', price: 195, image: 'https://images.unsplash.com/photo-1514432324607-a09d9b4aefdd?auto=format&fit=crop&w=150&q=80' },
{ sku: 'MILK-AAV-50', name: 'Aavin Premium Pouch Milk 500ml', category: 'Dairy / Milk', stockLevel: 18, maxCapacity: 200, status: 'Critical', price: 28, image: 'https://images.unsplash.com/photo-1542838132-92c53300491e?auto=format&fit=crop&w=150&q=80' },
{ sku: 'OOTY-CARROT-1KG', name: 'Ooty Fresh Quality Carrots 1kg', category: 'Fresh Produce / Veg', stockLevel: 45, maxCapacity: 100, status: 'Low Stock', price: 60, image: 'https://images.unsplash.com/photo-1598170845058-32b9d6a5da37?auto=format&fit=crop&w=150&q=80' },
{ sku: 'TURMERIC-200G', name: 'Organic Turmeric Powder 200g', category: 'Groceries / Spices', stockLevel: 280, maxCapacity: 300, status: 'Optimal', price: 90, image: 'https://images.unsplash.com/photo-1596040033229-a9821ebd058d?auto=format&fit=crop&w=150&q=80' },
{ sku: 'GHEE-500ML', name: 'Pure Cow Ghee 500ml', category: 'Dairy / Ghee', stockLevel: 75, maxCapacity: 250, status: 'Low Stock', price: 320, image: 'https://images.unsplash.com/photo-1589985270826-4b7bb135bc9d?auto=format&fit=crop&w=150&q=80' }
];
};
// Sync loaded stock to state
useEffect(() => {
setLocalInventory(getMergedInventory());
}, [stockQ.data, store.locationid]);
const inventoryList = localInventory.filter(item =>
item.name.toLowerCase().includes(stockSearch.toLowerCase()) ||
item.sku.toLowerCase().includes(stockSearch.toLowerCase()) ||
item.category.toLowerCase().includes(stockSearch.toLowerCase())
);
// Customer Directory mapping (derived + live merges)
const getMergedCustomers = () => {
const rawCustomers = customersQ.data ?? [];
if (rawCustomers.length > 0) {
return rawCustomers.map((c: any) => ({
name: fstr(c.fullname) || `${fstr(c.firstname)} ${fstr(c.lastname)}`.trim() || 'Customer',
phone: fstr(c.contactno) || '—',
address: fstr(c.address) || 'Coimbatore',
ordersCount: Number(c.orderscount) || Math.floor(Math.random() * 8) + 1,
totalSpent: `${(Number(c.totalspent) || Math.floor(Math.random() * 4000) + 500).toLocaleString('en-IN')}`,
lastOrder: '2 Days ago'
}));
}
// High fidelity fallback customer base
return [
{ name: 'Meenakshi Sundaram', phone: '+91 94432 18942', address: 'Plot 4, Lakshmipuram Ext, RS Puram, Coimbatore - 641002', ordersCount: 42, totalSpent: '₹34,820.00', lastOrder: 'Today, 14:24 PM' },
{ name: 'Senthil Kumar VSD', phone: '+91 98421 00234', address: 'Flat 2C, Whispering Palms, Avinashi Road, Peelamedu - 641004', ordersCount: 28, totalSpent: '₹22,910.00', lastOrder: 'Yesterday, 14:10 PM' },
{ name: 'Kavitha Ramaswamy', phone: '+91 90035 88921', address: 'No 15, Cross Cut Road, Gandhipuram, Coimbatore - 641012', ordersCount: 19, totalSpent: '₹14,240.00', lastOrder: '2 Days ago' },
{ name: 'Dr. Anand Selvapandian', phone: '+91 97890 22104', address: 'Villa 12, Sobha Elanza, Sathy Road, Saravanampatti - 641035', ordersCount: 12, totalSpent: '₹9,800.00', lastOrder: '3 Days ago' },
{ name: 'Rajesh Subramaniam', phone: '+91 94421 88902', address: '45, West Club Road, Race Course, Coimbatore - 641018', ordersCount: 64, totalSpent: '₹84,900.00', lastOrder: 'Today, 10:15 AM' },
{ name: 'Priya Krishnan', phone: '+91 90432 11094', address: '8C, Royal Arcade, Trichy Road, Singanallur - 641005', ordersCount: 7, totalSpent: '₹4,120.00', lastOrder: '1 Week ago' }
];
};
const customersList = getMergedCustomers().filter(c =>
c.name.toLowerCase().includes(customerSearch.toLowerCase()) ||
c.phone.includes(customerSearch) ||
c.address.toLowerCase().includes(customerSearch.toLowerCase())
);
// Store Alerts specific to the store
const storeAlerts = operationalAlerts.filter(alert =>
alert.title.toLowerCase().includes(store.name.split(' ')[0].toLowerCase()) ||
alert.details.toLowerCase().includes(store.name.split(' ')[0].toLowerCase())
);
// ── Riders fleet data list ────────────────────────────────────────────────
const activeRiders = [
{ name: 'Karthikeyan Radhakrishnan', initial: 'KR', status: 'Delivering', orders: 3, battery: 92, lastPing: '2m ago' },
{ name: 'Arun Kumar Chinnasamy', initial: 'AC', status: 'Delivering', orders: 2, battery: 48, lastPing: '10m ago' },
{ name: 'Suresh Balasubramaniam', initial: 'SB', status: 'Idle', orders: 0, battery: 84, lastPing: 'Just now' },
{ name: 'Manoj Kumar Gowda', initial: 'MG', status: 'Delivering', orders: 1, battery: 14, lastPing: '1m ago' }
];
// Actions simulation handles
const handleReplenishSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (!replenishModal.item) return;
setLocalInventory(prev => prev.map(item => {
if (item.sku === replenishModal.item.sku) {
const newStock = Math.min(item.stockLevel + replenishQty, item.maxCapacity);
return {
...item,
stockLevel: newStock,
status: newStock < 50 ? 'Critical' : newStock < 150 ? 'Low Stock' : 'Optimal'
};
}
return item;
}));
showToast(`Replenishment batch ticket generated for ${replenishQty} units of ${replenishModal.item.name}.`, 'success');
setReplenishModal({ show: false, item: null });
};
// CSV Import simulation trigger
const handleStartCsvImport = () => {
setImportState('reading');
setTimeout(() => {
setImportState('parsing');
setTimeout(() => {
setImportState('saving');
setTimeout(() => {
const newItems = [
{ sku: 'NOODLE-MAG-12', name: 'Maggi 2-Min Masala Noodles 280g', category: 'Snacks / Noodles', stockLevel: 80, maxCapacity: 250, status: 'Optimal', price: 45, image: 'https://images.unsplash.com/photo-1569718212165-3a8278d5f624?auto=format&fit=crop&w=150&q=80' },
{ sku: 'DET-SURF-1KG', name: 'Surf Excel Easy Wash Detergent 1kg', category: 'Household / Detergent', stockLevel: 14, maxCapacity: 100, status: 'Critical', price: 165, image: 'https://images.unsplash.com/photo-1542838132-92c53300491e?auto=format&fit=crop&w=150&q=80' },
{ sku: 'SALT-TATA-1KG', name: 'Tata Salt Premium Iodized 1kg', category: 'Staples / Salt', stockLevel: 180, maxCapacity: 300, status: 'Optimal', price: 28, image: 'https://images.unsplash.com/photo-1626132647523-66f5bf380027?auto=format&fit=crop&w=150&q=80' }
];
// Add to localInventory state preventing duplicates
setLocalInventory(prev => {
const filtered = prev.filter(item => !newItems.some(ni => ni.sku === item.sku));
return [...filtered, ...newItems];
});
setImportState('done');
showToast(`CSV Inventory manifest sync complete. 3 items added to local stocks.`, 'success');
}, 800);
}, 700);
}, 700);
};
// Add items from Global Catalog
const handleAddGlobalCatalogue = () => {
if (selectedGlobalSkus.length === 0) {
showToast('Kindly select at least one catalogue item.', 'warning');
return;
}
const itemsToAdd = GLOBAL_CATALOGUE_ITEMS.filter(item => selectedGlobalSkus.includes(item.sku)).map(item => ({
...item,
stockLevel: Math.floor(Math.random() * 80) + 20,
maxCapacity: 200,
status: 'Optimal'
}));
setLocalInventory(prev => {
const filtered = prev.filter(item => !itemsToAdd.some(ni => ni.sku === item.sku));
return [...filtered, ...itemsToAdd];
});
showToast(`${itemsToAdd.length} products synced from Master Global Catalogue successfully!`, 'success');
setSelectedGlobalSkus([]);
setShowGlobalModal(false);
};
const handleExportLedger = () => {
showToast(`Generating secure PDF ledger audit reports for ${store.name}...`, 'info');
setTimeout(() => {
showToast(`Ledger spreadsheet decrypted and downloaded successfully.`, 'success');
}, 2000);
};
const handleStaffBroadcast = () => {
const text = prompt('Type notification message to broadcast to all cashiers and staff at this store:');
if (text) {
showToast(`Broadcast notification dispatched to all active terminals at ${store.name}.`, 'success');
}
};
return (
<div className="space-y-lg animate-in fade-in duration-500 relative font-sans text-zinc-900 pb-xl">
{/* ── Floating Alert Toast UI ── */}
{toast.show && (
<div className="fixed top-24 right-6 z-[300] bg-[#0f172a] text-white border border-[#334155] px-lg py-3 rounded-xl shadow-2xl flex items-center gap-md animate-in slide-in-from-top duration-300">
{toast.type === 'success' && <CheckCircle2 size={16} className="text-emerald-400" />}
{toast.type === 'info' && <Activity size={16} className="text-purple-400" />}
{toast.type === 'warning' && <AlertTriangle size={16} className="text-amber-400" />}
<span className="text-xs font-semibold">{toast.message}</span>
<button onClick={() => setToast(prev => ({ ...prev, show: false }))} className="text-zinc-500 hover:text-zinc-300 cursor-pointer">
<X size={14} />
</button>
</div>
)}
{/* ── Subheader Navigation Bar ── */}
<div className="flex items-center justify-between">
<button
onClick={onBack}
className="flex items-center gap-xs text-xs font-bold text-[#581c87] hover:text-[#4c1d95] bg-purple-50 hover:bg-purple-100/80 px-xl py-2 rounded-lg transition-all shadow-sm border border-purple-100 cursor-pointer"
>
<ArrowLeft size={14} />
<span>Back to Registry</span>
</button>
<div className="flex items-center gap-xs">
<span className="w-2 h-2 rounded-full bg-emerald-500 animate-pulse" />
<span className="text-[10px] font-bold tracking-widest text-emerald-600 uppercase">System Sync Active</span>
</div>
</div>
{/* ── Immersive Analytics Banner (With Store Cover Image & Slate Gradient Overlay) ── */}
<div className="relative overflow-hidden rounded-2xl p-6 md:p-8 text-white shadow-xl border border-purple-500/20 mb-8 animate-in fade-in duration-300">
{/* Cover Image Background */}
<div className="absolute inset-0 z-0">
<img
src={storeCoverImage}
alt={store.name}
className="w-full h-full object-cover object-center"
/>
<div className="absolute inset-0 bg-gradient-to-r from-slate-950 via-slate-900/90 to-purple-950/80" />
</div>
{/* Background decorative glowing circles */}
<div className="absolute top-0 right-0 w-72 h-72 bg-purple-500/10 rounded-full blur-3xl -mr-20 -mt-20 pointer-events-none z-0" />
<div className="absolute bottom-0 left-0 w-56 h-56 bg-slate-500/5 rounded-full blur-2xl -ml-20 -mb-20 pointer-events-none z-0" />
<div className="relative flex flex-col md:flex-row md:items-center justify-between gap-6 z-10">
<div className="space-y-2">
<div className="inline-flex items-center gap-2 px-2.5 py-1 rounded-full bg-purple-500/20 border border-purple-400/30 text-purple-200 text-[10px] font-bold uppercase tracking-widest">
<span className="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse" />
Outlet Node #{locationid} Operations
</div>
<h2 className="font-sans font-bold text-3xl tracking-tight bg-gradient-to-r from-white via-slate-100 to-purple-200 bg-clip-text text-transparent">
{store.name}
</h2>
<div className="flex flex-wrap gap-2 text-xs text-purple-200 mt-1">
<span className="flex items-center gap-1">
<MapPin size={13} className="text-purple-300" /> {store.zone}
</span>
<span className="flex items-center gap-1 ml-4">
<Users size={13} className="text-purple-300" /> Node Lead: <strong>{store.staff}</strong>
</span>
</div>
</div>
</div>
{/* Metrics grid */}
<div className="grid grid-cols-1 sm:grid-cols-4 gap-4 mt-8 pt-6 border-t border-slate-800/80 relative z-10">
<div className="bg-slate-900/40 backdrop-blur-sm rounded-xl p-4 border border-slate-800/80 hover:border-purple-500/30 transition-all group">
<div className="flex justify-between items-start">
<span className="text-[10px] text-slate-400 uppercase tracking-widest font-bold">Node Status</span>
<div className="p-2 rounded-lg bg-emerald-500/10 text-emerald-400 border border-emerald-500/20 group-hover:scale-110 transition-transform">
<Building className="w-4 h-4" />
</div>
</div>
<div className="mt-2">
<h3 className="text-2xl font-extrabold tracking-tight font-mono">{store.status}</h3>
<p className="text-[10px] text-emerald-400 font-semibold mt-1"> Online Operations</p>
</div>
</div>
<div className="bg-slate-900/40 backdrop-blur-sm rounded-xl p-4 border border-slate-800/80 hover:border-purple-500/30 transition-all group">
<div className="flex justify-between items-start">
<span className="text-[10px] text-slate-400 uppercase tracking-widest font-bold">Today's Orders</span>
<div className="p-2 rounded-lg bg-purple-500/10 text-purple-400 border border-purple-500/20 group-hover:scale-110 transition-transform">
<ShoppingCart className="w-4 h-4" />
</div>
</div>
<div className="mt-2">
<h3 className="text-2xl font-extrabold tracking-tight font-mono">{Math.max(store.deliveries, store.orders ?? 0)}</h3>
<p className="text-[10px] text-slate-400 font-semibold mt-1">Incoming Volume</p>
</div>
</div>
<div className="bg-slate-900/40 backdrop-blur-sm rounded-xl p-4 border border-slate-800/80 hover:border-purple-500/30 transition-all group">
<div className="flex justify-between items-start">
<span className="text-[10px] text-slate-400 uppercase tracking-widest font-bold">Today's Dispatches</span>
<div className="p-2 rounded-lg bg-purple-500/10 text-purple-400 border border-purple-500/20 group-hover:scale-110 transition-transform">
<TrendingUp className="w-4 h-4" />
</div>
</div>
<div className="mt-2">
<h3 className="text-2xl font-extrabold tracking-tight font-mono">{store.deliveries}</h3>
<p className="text-[10px] text-slate-400 font-semibold mt-1">Dispatched Deliveries</p>
</div>
</div>
<div className="bg-slate-900/40 backdrop-blur-sm rounded-xl p-4 border border-slate-800/80 hover:border-purple-500/30 transition-all group">
<div className="flex justify-between items-start">
<span className="text-[10px] text-slate-400 uppercase tracking-widest font-bold">Fulfillment Rate</span>
<div className="p-2 rounded-lg bg-indigo-500/10 text-indigo-400 border border-indigo-500/20 group-hover:scale-110 transition-transform">
<Award className="w-4 h-4" />
</div>
</div>
<div className="mt-2">
<h3 className="text-2xl font-extrabold tracking-tight font-mono">
{Math.max(store.deliveries, store.orders ?? 0) > 0
? `${Math.min(100, Math.round((store.deliveries / Math.max(store.deliveries, store.orders ?? 0)) * 100))}%`
: '100%'}
</h3>
<p className="text-[10px] text-indigo-400 font-semibold mt-1">Outlet OTIF Rate</p>
</div>
</div>
</div>
</div>
{/* ── Visual Glass-look Tab Controls ── */}
<div className="flex gap-2 border-b border-[#e2e8f0] pb-[1px] select-none overflow-x-auto">
<button
onClick={() => setActiveTab('overview')}
className={`flex items-center gap-xs px-md pb-sm text-xs font-bold uppercase tracking-wider cursor-pointer border-b-2 transition-all ${
activeTab === 'overview'
? 'border-b-[#581c87] text-[#581c87]'
: 'border-b-transparent text-zinc-400 hover:text-zinc-600'
}`}
>
<Activity size={14} />
<span>Overview & Performance</span>
</button>
<button
onClick={() => setActiveTab('inventory')}
className={`flex items-center gap-xs px-md pb-sm text-xs font-bold uppercase tracking-wider cursor-pointer border-b-2 transition-all ${
activeTab === 'inventory'
? 'border-b-[#581c87] text-[#581c87]'
: 'border-b-transparent text-zinc-400 hover:text-zinc-600'
}`}
>
<Layers size={14} />
<span>Inventory & Catalogue ({inventoryList.length})</span>
{inventoryList.some(item => item.status === 'Critical') && (
<span className="px-1.5 py-0.5 rounded-full bg-rose-500 text-white text-[8px] font-black leading-none animate-pulse">!</span>
)}
</button>
<button
onClick={() => setActiveTab('customers')}
className={`flex items-center gap-xs px-md pb-sm text-xs font-bold uppercase tracking-wider cursor-pointer border-b-2 transition-all ${
activeTab === 'customers'
? 'border-b-[#581c87] text-[#581c87]'
: 'border-b-transparent text-zinc-400 hover:text-zinc-600'
}`}
>
<Users size={14} />
<span>Customer CRM Base ({customersList.length})</span>
</button>
<button
onClick={() => setActiveTab('orders')}
className={`flex items-center gap-xs px-md pb-sm text-xs font-bold uppercase tracking-wider cursor-pointer border-b-2 transition-all ${
activeTab === 'orders'
? 'border-b-[#581c87] text-[#581c87]'
: 'border-b-transparent text-zinc-400 hover:text-zinc-600'
}`}
>
<ShoppingBag size={14} />
<span>Orders & Deliveries</span>
</button>
</div>
{/* ── TAB PAYLOAD AREA ── */}
{activeTab === 'overview' && (
<div className="space-y-lg animate-in fade-in duration-300">
{/* Top Metric Cards */}
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-gutter">
<div className="bg-white border border-[#eceef2] rounded-2xl p-md shadow-sm hover:shadow-md transition-all duration-200 hover:-translate-y-0.5 relative group overflow-hidden">
<div className="w-8 h-8 rounded-xl bg-purple-50 text-[#581c87] flex items-center justify-center mb-sm group-hover:scale-110 transition-transform">
<CheckCircle2 size={16} />
</div>
<span className="text-[10px] font-bold text-zinc-400 uppercase tracking-widest block">OTIF Fulfillment</span>
<p className="text-2xl font-black text-[#0f172a] mt-xs">98.2%</p>
<div className="text-[10px] text-emerald-600 font-bold mt-1 flex items-center gap-xs">
<span> 0.4%</span>
<span className="text-zinc-400 font-medium">vs past week</span>
</div>
</div>
<div className="bg-white border border-[#eceef2] rounded-2xl p-md shadow-sm hover:shadow-md transition-all duration-200 hover:-translate-y-0.5 relative group overflow-hidden">
<div className="w-8 h-8 rounded-xl bg-emerald-50 text-emerald-600 flex items-center justify-center mb-sm group-hover:scale-110 transition-transform">
<TrendingUp size={16} />
</div>
<span className="text-[10px] font-bold text-zinc-400 uppercase tracking-widest block">Est. Revenue</span>
<p className="text-2xl font-black text-[#0f172a] mt-xs">{revenueToday.toLocaleString('en-IN')}</p>
<div className="text-[10px] text-emerald-600 font-bold mt-1 flex items-center gap-xs">
<span> 12.4%</span>
<span className="text-zinc-400 font-medium">growth threshold</span>
</div>
</div>
<div className="bg-white border border-[#eceef2] rounded-2xl p-md shadow-sm hover:shadow-md transition-all duration-200 hover:-translate-y-0.5 relative group overflow-hidden">
<div className="w-8 h-8 rounded-xl bg-sky-50 text-sky-600 flex items-center justify-center mb-sm group-hover:scale-110 transition-transform">
<ShoppingCart size={16} />
</div>
<span className="text-[10px] font-bold text-zinc-400 uppercase tracking-widest block">Total Dispatches</span>
<p className="text-2xl font-black text-[#0f172a] mt-xs">{store.deliveries}</p>
<div className="text-[10px] text-zinc-400 font-bold mt-1">
<span>Daily cap quota: 200</span>
</div>
</div>
<div className="bg-white border border-[#eceef2] rounded-2xl p-md shadow-sm hover:shadow-md transition-all duration-200 hover:-translate-y-0.5 relative group overflow-hidden">
<div className="w-8 h-8 rounded-xl bg-amber-50 text-amber-600 flex items-center justify-center mb-sm group-hover:scale-110 transition-transform">
<Users size={16} />
</div>
<span className="text-[10px] font-bold text-zinc-400 uppercase tracking-widest block">Active Fleet</span>
<p className="text-2xl font-black text-[#0f172a] mt-xs">4 Riders</p>
<div className="text-[10px] text-emerald-600 font-bold mt-1 flex items-center gap-xs">
<span className="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse" />
<span>3 dispatches live</span>
</div>
</div>
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-gutter">
{/* Interactive Timeline Pipeline Flow */}
<div className="lg:col-span-2 bg-white border border-[#eceef2] rounded-2xl p-lg shadow-sm flex flex-col justify-between hover:shadow-md transition-shadow relative">
<div>
<div className="flex justify-between items-start">
<div>
<h3 className="font-sans font-bold text-sm text-[#0f172a] flex items-center gap-xs">
<Clock size={15} className="text-[#581c87]" /> Dispatch Flow Pipeline
</h3>
<p className="text-zinc-450 text-[10px] font-sans mt-0.5">Audit orders & revenue progression by selecting nodes along the daily operational path.</p>
</div>
<span className="text-[9px] font-bold text-purple-600 bg-purple-50 px-2 py-0.5 rounded-lg border border-purple-100 uppercase tracking-wider">Time Flow</span>
</div>
</div>
{/* The Pipeline Line and Nodes */}
<div className="relative py-xl px-lg select-none my-xl">
{/* Flow track base line */}
<div className="w-full bg-[#f1f5f9] h-2 rounded-full relative shadow-inner">
{/* Glowing progress fill line */}
<div
className="absolute top-0 left-0 h-full bg-gradient-to-r from-purple-600 via-indigo-500 to-pink-500 rounded-full transition-all duration-700 shadow-[0_0_8px_rgba(99,102,241,0.5)]"
style={{ width: `${(activeSlotIndex / 4) * 100}%` }}
/>
{/* Operational Nodes */}
<div className="absolute inset-0 flex justify-between items-center overflow-visible">
{intervalSlots.map((slot, index) => {
const isActive = activeSlotIndex === index;
const isHovered = hoveredChartIndex === index;
// Status colors
let dotColor = 'bg-indigo-500';
let ringColor = 'border-indigo-100 hover:border-indigo-300';
let rippleColor = 'bg-indigo-400';
if (slot.status === 'PEAK') {
dotColor = 'bg-rose-500';
ringColor = isActive ? 'border-rose-300 bg-rose-50/50' : 'border-rose-100 hover:border-rose-300';
rippleColor = 'bg-rose-400';
} else if (slot.status === 'HIGH') {
dotColor = 'bg-amber-500';
ringColor = isActive ? 'border-amber-300 bg-amber-50/50' : 'border-amber-100 hover:border-amber-300';
rippleColor = 'bg-amber-400';
} else if (slot.status === 'LOW') {
dotColor = 'bg-emerald-500';
ringColor = isActive ? 'border-emerald-300 bg-emerald-50/50' : 'border-emerald-100 hover:border-emerald-300';
rippleColor = 'bg-emerald-400';
}
return (
<div
key={index}
onMouseEnter={() => setHoveredChartIndex(index)}
onMouseLeave={() => setHoveredChartIndex(null)}
onClick={() => setHoveredChartIndex(index)}
className="relative flex flex-col items-center cursor-pointer group z-10"
>
{/* Time label above node */}
<div className="absolute bottom-8 whitespace-nowrap text-center flex flex-col items-center">
<span className={`text-[10px] font-black tracking-tight transition-colors ${
isActive ? 'text-[#581c87]' : 'text-zinc-400 group-hover:text-zinc-600'
}`}>
{slot.time.split(' - ')[0]}
</span>
</div>
{/* Node Circle */}
<div className={`w-8 h-8 rounded-full border-2 bg-white flex items-center justify-center transition-all duration-300 shadow-sm ${
isActive ? 'scale-125 border-purple-600 shadow-md' : 'border-zinc-200 hover:border-purple-300'
}`}>
{/* Pulse ripples if active */}
{isActive && (
<span className={`absolute inline-flex h-8 w-8 rounded-full ${rippleColor} opacity-25 animate-ping z-0`} />
)}
{/* Inner dot */}
<div className={`w-3.5 h-3.5 rounded-full transition-transform duration-300 ${dotColor} ${
isActive ? 'scale-110' : 'group-hover:scale-110'
}`} />
</div>
{/* Label and dispatches below node */}
<div className="absolute top-10 whitespace-nowrap text-center flex flex-col items-center">
<span className={`text-[10px] font-bold tracking-tight transition-colors ${
isActive ? 'text-[#0f172a]' : 'text-zinc-500 group-hover:text-zinc-700'
}`}>
{slot.label.split(' ')[0]}
</span>
<span className="text-[8px] font-bold text-zinc-400 uppercase tracking-wider mt-[1px]">
{slot.orders} orders
</span>
</div>
</div>
);
})}
</div>
</div>
</div>
{/* Interactive Glassmorphic Stats audit drawer below chart */}
<div className="mt-4 p-md bg-[#faf5ff] border border-[#f3e8ff] rounded-2xl flex flex-col sm:flex-row items-start sm:items-center justify-between gap-md transition-all duration-300 animate-in fade-in duration-200">
<div className="flex items-center gap-md">
<div className={`w-8 h-8 rounded-xl flex items-center justify-center shrink-0 shadow-sm border ${
activeSlot.status === 'PEAK' ? 'bg-rose-50 text-rose-600 border-rose-100' :
activeSlot.status === 'HIGH' ? 'bg-amber-50 text-amber-600 border-amber-100' :
activeSlot.status === 'NORMAL' ? 'bg-sky-50 text-sky-600 border-sky-100' :
'bg-emerald-50 text-emerald-600 border-emerald-100'
}`}>
<Clock size={16} />
</div>
<div>
<span className="text-[10px] font-bold text-zinc-400 uppercase tracking-widest block">Audit Interval</span>
<span className="font-extrabold text-sm text-[#0f172a]">{activeSlot.label}</span>
<span className="text-[10px] text-zinc-500 font-semibold block mt-0.5">{activeSlot.time}</span>
</div>
</div>
<div className="flex flex-wrap items-center gap-md sm:gap-xl select-none text-xs">
<div className="text-right">
<span className="text-[9px] font-bold text-zinc-400 uppercase tracking-widest block">Dispatches</span>
<span className="font-black text-sm text-[#0f172a]">{activeSlot.orders} dispatches</span>
</div>
<div className="text-right border-l border-purple-100 pl-md sm:pl-xl">
<span className="text-[9px] font-bold text-purple-400 uppercase tracking-widest block">Est. Revenue</span>
<span className="font-black text-sm text-[#581c87]">{activeSlot.sales}</span>
</div>
<div className="text-right border-l border-purple-100 pl-md sm:pl-xl">
<span className="text-[9px] font-bold text-zinc-400 uppercase tracking-widest block">Load level</span>
<span className={`px-2 py-0.5 rounded-lg text-[9px] font-black tracking-wider inline-block mt-0.5 ${
activeSlot.status === 'PEAK' ? 'bg-rose-100 text-rose-700' :
activeSlot.status === 'HIGH' ? 'bg-amber-100 text-amber-700' :
activeSlot.status === 'NORMAL' ? 'bg-sky-100 text-sky-700' :
'bg-emerald-100 text-emerald-700'
}`}>
{activeSlot.status}
</span>
</div>
</div>
</div>
</div>
{/* Quick Actions Console */}
<div className="bg-white border border-[#eceef2] rounded-2xl p-md shadow-sm space-y-md flex flex-col justify-between">
<div>
<h3 className="font-sans font-bold text-sm text-[#0f172a] flex items-center gap-xs">
<ShieldCheck size={15} className="text-[#581c87]" /> Node Operations Command
</h3>
<p className="text-zinc-450 text-[10px] font-sans mt-0.5">Automated actions for local outlet hubs.</p>
</div>
<div className="space-y-sm">
<button
onClick={() => setActiveTab('inventory')}
className="w-full flex items-center justify-between p-sm border border-[#e2e8f0] rounded-xl hover:border-purple-300 hover:bg-purple-50/20 text-left text-xs font-semibold text-zinc-700 hover:text-[#581c87] transition cursor-pointer"
>
<span className="flex items-center gap-sm">
<Layers size={14} className="text-[#581c87]" /> Replenish Critical Stock
</span>
<span className="px-1.5 py-0.5 rounded text-[8px] bg-rose-100 text-rose-700 font-black animate-pulse">ALERTS</span>
</button>
<button
onClick={handleExportLedger}
className="w-full flex items-center justify-between p-sm border border-[#e2e8f0] rounded-xl hover:border-purple-300 hover:bg-purple-50/20 text-left text-xs font-semibold text-zinc-700 hover:text-[#581c87] transition cursor-pointer"
>
<span className="flex items-center gap-sm">
<Download size={14} className="text-zinc-500" /> Export Compliance Ledger
</span>
<span className="text-[8px] font-bold text-zinc-400">PDF / CSV</span>
</button>
<button
onClick={handleStaffBroadcast}
className="w-full flex items-center justify-between p-sm border border-[#e2e8f0] rounded-xl hover:border-purple-300 hover:bg-purple-50/20 text-left text-xs font-semibold text-zinc-700 hover:text-[#581c87] transition cursor-pointer"
>
<span className="flex items-center gap-sm">
<Send size={14} className="text-zinc-500" /> Broadcast Terminal SMS
</span>
<span className="text-[8px] font-bold text-[#581c87] uppercase tracking-wider">SMS Blast</span>
</button>
</div>
</div>
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-gutter">
{/* Past 7 days Table */}
<div className="lg:col-span-2 bg-white border border-[#eceef2] rounded-2xl p-md shadow-sm">
<h3 className="font-sans font-bold text-sm text-[#0f172a] mb-md flex items-center gap-xs">
<Calendar size={15} className="text-[#581c87]" /> Past 7 Days Ledger Log
</h3>
<div className="overflow-x-auto text-xs font-sans">
<table className="w-full text-left">
<thead className="bg-[#f8fafc] border-b border-[#e2e8f0] text-zinc-400 text-[10px] uppercase font-bold tracking-wider">
<tr>
<th className="px-md py-sm">Day Period</th>
<th className="px-md py-sm">Dispatches</th>
<th className="px-md py-sm">Revenue Volume</th>
<th className="px-md py-sm text-right">OTIF fulfillment</th>
</tr>
</thead>
<tbody className="divide-y divide-[#f1f5f9] font-medium text-zinc-700">
{pastDaysLog.map((dayLog, index) => (
<tr key={index} className="hover:bg-zinc-50/50 transition">
<td className="px-md py-md font-bold text-[#0f172a]">{dayLog.day}</td>
<td className="px-md py-md text-zinc-650">{dayLog.orders} dispatches</td>
<td className="px-md py-md text-[#581c87] font-black">{dayLog.sales}</td>
<td className="px-md py-md text-right font-mono text-emerald-600 font-bold">{dayLog.rate}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
{/* Live Rider fleet list */}
<div className="bg-white border border-[#eceef2] rounded-2xl p-md shadow-sm flex flex-col justify-between">
<div>
<h3 className="font-sans font-bold text-sm text-[#0f172a] flex items-center gap-xs">
<ShoppingCart size={15} className="text-[#581c87]" /> Active Rider Fleet
</h3>
<p className="text-zinc-405 text-[10px] font-sans mt-0.5">Live status and battery tracking of assigned riders.</p>
</div>
<div className="divide-y divide-[#f1f5f9] text-xs font-sans mt-md">
{activeRiders.map((rider, index) => (
<div key={index} className="py-2 flex justify-between items-center group">
<div className="flex items-center gap-sm min-w-0">
<div className="w-7 h-7 rounded-full bg-purple-50 text-[#581c87] border border-purple-100 font-black text-[10px] flex items-center justify-center shrink-0">
{rider.initial}
</div>
<div className="min-w-0">
<p className="font-bold text-[#0f172a] truncate">{rider.name.split(' ')[0]} {rider.name.split(' ').slice(-1)[0]}</p>
<p className="text-[9px] text-zinc-400 flex items-center gap-1 font-semibold uppercase">
<span className={`w-1.5 h-1.5 rounded-full ${rider.status === 'Idle' ? 'bg-amber-400' : 'bg-emerald-500'}`} />
{rider.status} · {rider.orders} orders
</p>
</div>
</div>
<div className="flex items-center gap-sm text-right shrink-0">
<div className="flex items-center gap-[2px] font-mono text-[10px] text-zinc-400">
<Battery size={13} className={rider.battery < 20 ? 'text-rose-500' : 'text-zinc-400'} />
<span className={rider.battery < 20 ? 'text-rose-600 font-bold' : ''}>{rider.battery}%</span>
</div>
<button
onClick={() => showToast(`SMS alert broadcasted to rider ${rider.name.split(' ')[0]}.`, 'success')}
className="px-2 py-1 border border-zinc-200 rounded-lg hover:border-purple-300 text-[9px] font-bold hover:bg-purple-50/50 hover:text-[#581c87] cursor-pointer transition"
>
Ping
</button>
</div>
</div>
))}
</div>
</div>
</div>
</div>
)}
{activeTab === 'inventory' && (
<div className="space-y-lg animate-in fade-in duration-300">
{/* Inventory search, metrics & catalogue tools */}
<div className="flex flex-col md:flex-row md:items-center justify-between gap-md bg-white border border-[#eceef2] p-md rounded-2xl shadow-sm">
<div className="relative w-full max-w-sm">
<Search size={15} className="absolute left-3 top-1/2 -translate-y-1/2 text-zinc-450" />
<input
type="text"
placeholder="Search local stocks catalogue..."
value={stockSearch}
onChange={(e) => setStockSearch(e.target.value)}
className="w-full pl-9 pr-4 py-2.5 border border-[#e2e8f0] rounded-xl text-xs outline-none bg-[#f8fafc] focus:bg-white focus:ring-1 focus:ring-[#581c87] transition-all"
/>
</div>
{/* Actions for Store Catalogue Management */}
<div className="flex flex-wrap items-center gap-sm text-xs shrink-0 select-none">
<button
onClick={() => { setImportState('idle'); setShowImportModal(true); }}
className="px-3 py-2 bg-purple-50 text-[#581c87] hover:bg-purple-100/80 border border-purple-100 rounded-xl font-bold flex items-center gap-xs cursor-pointer transition shadow-sm"
>
<UploadCloud size={14} />
<span>Import Manual (CSV)</span>
</button>
<button
onClick={() => { setSelectedGlobalSkus([]); setShowGlobalModal(true); }}
className="px-3 py-2 bg-[#0f172a] text-white hover:bg-zinc-800 rounded-xl font-bold flex items-center gap-xs cursor-pointer transition shadow-sm"
>
<Globe size={14} />
<span>Global Catalogue Master</span>
</button>
<span className="h-6 w-[1px] bg-zinc-200 mx-xs hidden md:block" />
<span className="px-3 py-2 bg-rose-50 border border-rose-100 rounded-lg text-rose-700 font-bold">
{inventoryList.filter(item => item.status === 'Critical').length} Critical
</span>
<span className="px-3 py-2 bg-amber-50 border border-amber-100 rounded-lg text-amber-700 font-bold">
{inventoryList.filter(item => item.status === 'Low Stock').length} Low
</span>
</div>
</div>
{/* Stocks statement Table */}
<div className="bg-white border border-[#eceef2] rounded-2xl overflow-hidden shadow-sm">
<div className="p-md border-b border-[#eceef2] bg-[#f8fafc] flex justify-between items-center">
<h4 className="font-sans font-bold text-sm text-[#0f172a]">
Product Stock Levels & Catalog
</h4>
<span className="text-[10px] font-bold text-[#581c87] bg-purple-50 px-2 py-0.5 rounded border border-purple-100 uppercase tracking-wide">Live list</span>
</div>
<div className="overflow-x-auto text-xs font-sans">
<table className="w-full text-left">
<thead className="bg-[#f8fafc] border-b border-[#e2e8f0] text-zinc-450 text-[10px] uppercase font-bold tracking-wider">
<tr>
<th className="px-md py-sm">Product Item</th>
<th className="px-md py-sm">SKU Ref</th>
<th className="px-md py-sm">Category</th>
<th className="px-md py-sm">Est. Price</th>
<th className="px-md py-sm">Capacity Load</th>
<th className="px-md py-sm">Status</th>
<th className="px-md py-sm text-right">Replenish</th>
</tr>
</thead>
<tbody className="divide-y divide-[#f1f5f9] font-medium text-zinc-700">
{inventoryList.length === 0 ? (
<tr>
<td colSpan={7} className="text-center py-10 text-zinc-400 font-medium">
No product stocks found matching the search keyword.
</td>
</tr>
) : (
inventoryList.map((item, index) => {
const capacityPct = Math.round((item.stockLevel / item.maxCapacity) * 100);
// Pretty category badge mapping
const isStaples = item.category.toLowerCase().includes('staple') || item.category.toLowerCase().includes('rice');
const isBeverages = item.category.toLowerCase().includes('bev');
const isProduce = item.category.toLowerCase().includes('produce') || item.category.toLowerCase().includes('fresh') || item.category.toLowerCase().includes('carrot');
const isDairy = item.category.toLowerCase().includes('dairy');
return (
<tr key={index} className="hover:bg-[#f8fafc]/60 transition-colors">
<td className="px-md py-md">
<div className="flex items-center gap-sm">
<img
src={item.image}
alt={item.name}
className="w-10 h-10 object-cover rounded-lg border border-zinc-200 shadow-sm shrink-0"
/>
<span className="font-bold text-[#0f172a]">{item.name}</span>
</div>
</td>
<td className="px-md py-md font-mono text-[10px] text-zinc-400 font-bold uppercase">{item.sku}</td>
<td className="px-md py-md">
<span className={`px-2 py-0.5 rounded text-[8px] font-bold uppercase tracking-wider ${
isStaples ? 'bg-amber-50 text-amber-700 border border-amber-100' :
isBeverages ? 'bg-rose-50 text-rose-700 border border-rose-100' :
isProduce ? 'bg-emerald-50 text-emerald-700 border border-emerald-100' :
isDairy ? 'bg-sky-50 text-sky-700 border border-sky-100' :
'bg-zinc-150 text-zinc-650'
}`}>
{item.category.split(' / ').slice(-1)[0]}
</span>
</td>
<td className="px-md py-md font-bold text-zinc-800">
{item.price.toLocaleString('en-IN')}
</td>
<td className="px-md py-md w-44">
<div className="flex items-center gap-sm">
<span className="w-8 shrink-0 font-mono text-right font-bold text-[10px]">{item.stockLevel} / {item.maxCapacity}</span>
<div className="w-20 bg-[#f1f5f9] h-2 rounded-full overflow-hidden">
<div
className={`h-full ${
item.status === 'Critical' ? 'bg-rose-500 animate-pulse' :
item.status === 'Low Stock' ? 'bg-amber-500' :
'bg-emerald-500'
}`}
style={{ width: `${Math.min(capacityPct, 100)}%` }}
/>
</div>
</div>
</td>
<td className="px-md py-md">
<span className={`px-2 py-0.5 rounded text-[9px] font-bold uppercase tracking-wider ${
item.status === 'Optimal' ? 'bg-emerald-50 text-emerald-700 border border-emerald-100' :
item.status === 'Low Stock' ? 'bg-amber-50 text-amber-700 border border-amber-100' :
'bg-rose-50 text-rose-700 border border-rose-100'
}`}>
{item.status}
</span>
</td>
<td className="px-md py-md text-right">
<button
onClick={() => setReplenishModal({ show: true, item })}
className={`px-3 py-1 rounded-lg text-[10px] font-bold hover:shadow-sm transition cursor-pointer ${
item.status === 'Critical'
? 'bg-rose-500 text-white hover:bg-rose-600'
: 'border border-zinc-200 text-zinc-700 hover:border-[#581c87] hover:text-[#581c87]'
}`}
>
Replenish
</button>
</td>
</tr>
);
})
)}
</tbody>
</table>
</div>
</div>
</div>
)}
{activeTab === 'customers' && (
<div className="space-y-lg animate-in fade-in duration-300">
{/* Customer directory search and metrics */}
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-md bg-white border border-[#eceef2] p-md rounded-2xl shadow-sm">
<div className="relative w-full max-w-sm">
<Search size={15} className="absolute left-3 top-1/2 -translate-y-1/2 text-zinc-400" />
<input
type="text"
placeholder="Search CRM profile roster..."
value={customerSearch}
onChange={(e) => setCustomerSearch(e.target.value)}
className="w-full pl-9 pr-4 py-2.5 border border-[#e2e8f0] rounded-xl text-xs outline-none bg-[#f8fafc] focus:bg-white focus:ring-1 focus:ring-[#581c87] transition-all"
/>
</div>
<div className="flex gap-sm text-xs shrink-0 select-none font-bold">
<span className="px-3 py-1.5 bg-purple-50 text-[#581c87] border border-purple-100 rounded-lg">
Retention Rate: 88.4%
</span>
<span className="px-3 py-1.5 bg-sky-50 text-sky-700 border border-sky-100 rounded-lg">
AOV: 1,580
</span>
<span className="px-3 py-1.5 bg-emerald-50 text-emerald-700 border border-emerald-100 rounded-lg">
CSAT Index: 4.9/5
</span>
</div>
</div>
{/* Customer list directory */}
<div className="bg-white border border-[#eceef2] rounded-2xl overflow-hidden shadow-sm">
<div className="p-md border-b border-[#eceef2] bg-[#f8fafc] flex justify-between items-center">
<h4 className="font-sans font-bold text-sm text-[#0f172a]">
Active Customer Directory
</h4>
<span className="text-[10px] font-bold text-[#581c87] bg-purple-50 px-2 py-0.5 rounded border border-purple-100 uppercase tracking-wide">Customer registry</span>
</div>
<div className="overflow-x-auto text-xs font-sans">
<table className="w-full text-left">
<thead className="bg-[#f8fafc] border-b border-[#e2e8f0] text-zinc-450 text-[10px] uppercase font-bold tracking-wider">
<tr>
<th className="px-md py-sm">Customer Profile</th>
<th className="px-md py-sm">Contact Details</th>
<th className="px-md py-sm">Delivery Address</th>
<th className="px-md py-sm">Total Dispatches</th>
<th className="px-md py-sm">Gross Volume Spent</th>
<th className="px-md py-sm text-right">Audit CRM Actions</th>
</tr>
</thead>
<tbody className="divide-y divide-[#f1f5f9] font-medium text-zinc-700">
{customersList.length === 0 ? (
<tr>
<td colSpan={6} className="text-center py-10 text-zinc-400 font-medium">
No customer accounts found matching search keyword.
</td>
</tr>
) : (
customersList.map((c, idx) => {
const initials = c.name.split(' ').map((n: string) => n[0]).join('');
const gradients = [
'from-purple-500 to-indigo-500 text-white',
'from-rose-500 to-pink-500 text-white',
'from-sky-500 to-indigo-500 text-white',
'from-emerald-500 to-teal-500 text-white',
'from-amber-500 to-orange-500 text-white'
];
const avatarGrad = gradients[idx % gradients.length];
return (
<tr key={idx} className="hover:bg-[#f8fafc]/60 transition-colors">
<td className="px-md py-md">
<div className="flex items-center gap-xs">
<div className={`w-8 h-8 rounded-full bg-gradient-to-br ${avatarGrad} flex items-center justify-center font-black text-[10px] shadow-sm shrink-0`}>
{initials}
</div>
<span className="font-bold text-[#0f172a]">{c.name}</span>
</div>
</td>
<td className="px-md py-md font-mono text-zinc-500 font-semibold">{c.phone}</td>
<td className="px-md py-md max-w-xs truncate text-zinc-500 font-medium" title={c.address}>
{c.address}
</td>
<td className="px-md py-md text-zinc-700 font-bold">{c.ordersCount} orders</td>
<td className="px-md py-md text-[#581c87] font-black">{c.totalSpent}</td>
<td className="px-md py-md text-right space-x-sm shrink-0">
<button
onClick={() => showToast(`Voucher promo code successfully dispatched to ${c.phone}.`, 'success')}
className="px-2.5 py-1 border border-zinc-200 hover:border-purple-300 rounded-lg font-bold text-[10px] text-zinc-650 hover:bg-purple-50/50 hover:text-[#581c87] cursor-pointer transition"
>
Promo SMS
</button>
<button
onClick={() => setSelectedCustomer(c)}
className="px-2.5 py-1 bg-[#0f172a] hover:bg-zinc-800 text-white rounded-lg font-bold text-[10px] cursor-pointer transition shadow-sm"
>
View Profile
</button>
</td>
</tr>
);
})
)}
</tbody>
</table>
</div>
</div>
</div>
)}
{activeTab === 'orders' && (
<OrdersDeliveriesView
searchQuery=""
isCoimbatoreView={false}
locationid={locationid}
/>
)}
{/* ── Replenishment Modal Dialog Overlay ── */}
{replenishModal.show && replenishModal.item && (
<div
className="fixed inset-0 bg-[#0f172a]/40 backdrop-blur-sm z-[200] flex items-center justify-center p-md animate-in fade-in duration-200"
onClick={(e) => { if (e.target === e.currentTarget) setReplenishModal({ show: false, item: null }); }}
>
<div className="bg-white border border-[#e2e8f0] rounded-2xl w-full max-w-[24rem] max-h-[90vh] flex flex-col shadow-2xl overflow-hidden animate-in zoom-in-95 duration-200 text-xs font-sans">
<div className="p-md border-b border-[#e2e8f0] bg-[#f8fafc] flex justify-between items-center shrink-0">
<h4 className="font-bold text-[#0f172a] flex items-center gap-xs">
<ShoppingCart size={15} className="text-[#581c87]" />
Replenish Inventory Stack
</h4>
<button
onClick={() => setReplenishModal({ show: false, item: null })}
className="p-1 hover:bg-zinc-200 rounded-full text-zinc-400 cursor-pointer transition-colors"
>
<X size={16} />
</button>
</div>
<form onSubmit={handleReplenishSubmit} className="flex-1 flex flex-col min-h-0">
<div className="p-md space-y-md overflow-y-auto flex-1">
<div className="p-sm bg-purple-50/50 border border-purple-100 rounded-xl space-y-xs">
<span className="text-[9px] font-black text-purple-600 uppercase tracking-wider">Replenishing Item</span>
<p className="font-bold text-sm text-[#0f172a]">{replenishModal.item.name}</p>
<p className="text-[10px] text-zinc-400 font-bold uppercase tracking-wider">SKU: {replenishModal.item.sku}</p>
</div>
<div className="space-y-sm">
<div className="space-y-1">
<label className="font-bold text-zinc-400 uppercase tracking-widest text-[9px]">Destination Store</label>
<input
type="text"
value={store.name}
className="w-full border border-[#e2e8f0] rounded-xl p-sm bg-[#f8fafc] text-zinc-500 font-semibold outline-none border-dashed"
disabled
/>
</div>
<div className="space-y-1">
<label className="font-bold text-zinc-500 uppercase tracking-widest text-[9px]">Replenish Quantity (Units)</label>
<input
type="number"
value={replenishQty}
onChange={(e) => setReplenishQty(Number(e.target.value))}
className="w-full border border-[#e2e8f0] rounded-xl p-sm bg-[#f8fafc] focus:bg-white outline-none focus:ring-1 focus:ring-[#581c87] font-bold"
min={1}
required
/>
</div>
</div>
</div>
<div className="p-md border-t border-[#f1f5f9] flex justify-end gap-sm bg-[#f8fafc] shrink-0">
<button
type="button"
onClick={() => setReplenishModal({ show: false, item: null })}
className="px-4 py-2 border border-[#e2e8f0] rounded-xl font-semibold text-zinc-500 hover:bg-zinc-50 cursor-pointer"
>
Cancel
</button>
<button
type="submit"
className="px-4 py-2 bg-[#581c87] text-white rounded-xl font-bold hover:bg-purple-800 cursor-pointer shadow-sm"
>
Confirm Batch Dispatch
</button>
</div>
</form>
</div>
</div>
)}
{/* ── Manual CSV Import simulated Modal ── */}
{showImportModal && (
<div
className="fixed inset-0 bg-[#0f172a]/40 backdrop-blur-sm z-[200] flex items-center justify-center p-md animate-in fade-in duration-200"
onClick={(e) => { if (e.target === e.currentTarget && importState !== 'reading' && importState !== 'parsing' && importState !== 'saving') setShowImportModal(false); }}
>
<div className="bg-white border border-[#e2e8f0] rounded-2xl w-full max-w-[26rem] max-h-[90vh] flex flex-col shadow-2xl overflow-hidden animate-in zoom-in-95 duration-200 text-xs font-sans">
<div className="p-md border-b border-[#e2e8f0] bg-[#f8fafc] flex justify-between items-center shrink-0">
<h4 className="font-bold text-[#0f172a] flex items-center gap-xs">
<UploadCloud size={15} className="text-[#581c87]" />
Import Catalogue Manifest
</h4>
<button
onClick={() => setShowImportModal(false)}
disabled={['reading', 'parsing', 'saving'].includes(importState)}
className="p-1 hover:bg-zinc-200 rounded-full text-zinc-400 cursor-pointer transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
>
<X size={16} />
</button>
</div>
<div className="p-md space-y-md overflow-y-auto flex-1">
<p className="text-zinc-500 leading-relaxed font-medium">
Upload or drop your CSV stock ledger files below to commission new items into the <strong>{store.name}</strong> local registry database.
</p>
{importState === 'idle' && (
<div
onClick={handleStartCsvImport}
className="border-2 border-dashed border-[#e2e8f0] hover:border-purple-300 rounded-2xl p-xl text-center cursor-pointer transition-colors bg-[#f8fafc] hover:bg-purple-50/10 space-y-sm group"
>
<UploadCloud size={28} className="mx-auto text-zinc-400 group-hover:text-[#581c87] transition-colors" />
<div>
<p className="font-bold text-[#0f172a]">Click here to import file</p>
<p className="text-[10px] text-zinc-400 font-semibold uppercase tracking-wider mt-0.5">Mock file: coimbatore_manifest_v2.csv</p>
</div>
</div>
)}
{['reading', 'parsing', 'saving'].includes(importState) && (
<div className="border border-[#e2e8f0] rounded-xl p-md bg-[#f8fafc] space-y-md text-center">
<div className="relative w-8 h-8 mx-auto">
<span className="absolute inset-0 rounded-full border-2 border-purple-100" />
<span className="absolute inset-0 rounded-full border-2 border-t-purple-600 animate-spin" />
</div>
<div>
<p className="font-bold text-[#0f172a] uppercase tracking-wide">
{importState === 'reading' && 'Reading uploaded CSV sheets...'}
{importState === 'parsing' && 'Scanning item SKU catalog mapping...'}
{importState === 'saving' && 'Syncing manifest entries with local inventory...'}
</p>
<p className="text-[10px] text-zinc-400 font-semibold mt-1">Kindly keep this window open while processing dispatches.</p>
</div>
</div>
)}
{importState === 'done' && (
<div className="border border-emerald-100 rounded-xl p-md bg-emerald-50/50 space-y-md text-center animate-in zoom-in-95">
<CheckCircle2 size={32} className="mx-auto text-emerald-600" />
<div>
<p className="font-black text-emerald-800 uppercase tracking-wide text-xs">Ledger Imported Successfully</p>
<p className="text-[10px] text-emerald-700 font-bold mt-1">3 new SKU codes commissioned successfully into local registry.</p>
</div>
</div>
)}
</div>
<div className="p-md border-t border-[#f1f5f9] flex justify-end bg-[#f8fafc] shrink-0">
<button
type="button"
onClick={() => setShowImportModal(false)}
disabled={['reading', 'parsing', 'saving'].includes(importState)}
className="px-4 py-2 border border-[#e2e8f0] rounded-xl font-bold text-zinc-650 hover:bg-zinc-50 cursor-pointer disabled:opacity-50"
>
{importState === 'done' ? 'Close Window' : 'Cancel'}
</button>
</div>
</div>
</div>
)}
{/* ── Choose from Global Catalogue Modal ── */}
{showGlobalModal && (
<div
className="fixed inset-0 bg-[#0f172a]/40 backdrop-blur-sm z-[200] flex items-center justify-center p-md animate-in fade-in duration-200"
onClick={(e) => { if (e.target === e.currentTarget) setShowGlobalModal(false); }}
>
<div className="bg-white border border-[#e2e8f0] rounded-2xl w-full max-w-[28rem] max-h-[90vh] flex flex-col shadow-2xl overflow-hidden animate-in zoom-in-95 duration-200 text-xs font-sans">
<div className="p-md border-b border-[#e2e8f0] bg-[#f8fafc] flex justify-between items-center shrink-0">
<h4 className="font-bold text-[#0f172a] flex items-center gap-xs">
<Globe size={15} className="text-[#581c87]" />
Select Products from Master Catalogue
</h4>
<button
onClick={() => setShowGlobalModal(false)}
className="p-1 hover:bg-zinc-200 rounded-full text-zinc-400 cursor-pointer transition-colors"
>
<X size={16} />
</button>
</div>
<div className="p-md space-y-md overflow-y-auto flex-1">
<p className="text-zinc-500 leading-relaxed font-medium">
Choose master items from the national database to stock and commission locally at <strong>{store.name}</strong>.
</p>
<div className="space-y-sm divide-y divide-[#f1f5f9]">
{GLOBAL_CATALOGUE_ITEMS.map((item) => {
const isChecked = selectedGlobalSkus.includes(item.sku);
return (
<div
key={item.sku}
onClick={() => {
setSelectedGlobalSkus(prev =>
isChecked ? prev.filter(s => s !== item.sku) : [...prev, item.sku]
);
}}
className="py-2.5 flex items-center justify-between gap-sm cursor-pointer select-none hover:bg-zinc-50/50 rounded-lg px-1 transition-colors"
>
<div className="flex items-center gap-sm min-w-0">
<input
type="checkbox"
checked={isChecked}
onChange={() => {}} // handled by row click
className="w-4 h-4 rounded text-[#581c87] border-[#e2e8f0] focus:ring-purple-500"
/>
<img
src={item.image}
alt={item.name}
className="w-9 h-9 object-cover rounded-lg border border-zinc-200 shrink-0"
/>
<div className="min-w-0">
<p className="font-bold text-[#0f172a] truncate">{item.name}</p>
<p className="text-[9px] text-zinc-450 font-bold uppercase tracking-wider">{item.category} · SKU: {item.sku}</p>
</div>
</div>
<span className="font-bold text-zinc-800 shrink-0">{item.price}</span>
</div>
);
})}
</div>
</div>
<div className="p-md border-t border-[#f1f5f9] flex justify-end gap-sm bg-[#f8fafc] shrink-0">
<button
type="button"
onClick={() => setShowGlobalModal(false)}
className="px-4 py-2 border border-[#e2e8f0] rounded-xl font-bold text-zinc-500 hover:bg-zinc-50 cursor-pointer"
>
Cancel
</button>
<button
type="button"
onClick={handleAddGlobalCatalogue}
className="px-4 py-2 bg-[#581c87] text-white rounded-xl font-bold hover:bg-purple-800 cursor-pointer shadow-sm"
>
Add Selected to Store
</button>
</div>
</div>
</div>
)}
{/* ── Customer CRM Profile Side Drawer Overlay ── */}
{selectedCustomer && (
<div
className="fixed inset-0 bg-[#0f172a]/40 backdrop-blur-sm z-[200] flex justify-end p-0 animate-in fade-in duration-200"
onClick={(e) => { if (e.target === e.currentTarget) setSelectedCustomer(null); }}
>
<div className="bg-white border-l border-[#e2e8f0] w-full max-w-[28rem] h-full flex flex-col shadow-2xl overflow-hidden animate-in slide-in-from-right duration-300 text-xs font-sans">
{/* Header info */}
<div className="p-lg border-b border-[#e2e8f0] bg-[#f8fafc] flex justify-between items-start shrink-0">
<div className="flex items-center gap-md">
<div className="w-12 h-12 rounded-full bg-gradient-to-br from-purple-600 to-indigo-600 text-white flex items-center justify-center font-black text-sm shadow-md">
{selectedCustomer.name.split(' ').map((n: string) => n[0]).join('')}
</div>
<div>
<h4 className="font-sans font-black text-base text-[#0f172a]">{selectedCustomer.name}</h4>
<span className="inline-flex items-center gap-xs px-2 py-0.5 rounded text-[8px] bg-purple-100 text-purple-700 font-black tracking-wider uppercase mt-1">
<UserCheck size={9} /> High Value Account
</span>
</div>
</div>
<button
onClick={() => setSelectedCustomer(null)}
className="p-1 hover:bg-zinc-200 rounded-full text-zinc-400 cursor-pointer transition-colors"
>
<X size={18} />
</button>
</div>
{/* Profile Drawer Details Container */}
<div className="p-lg overflow-y-auto flex-1 space-y-lg">
{/* Contact info list card */}
<div className="space-y-sm bg-white border border-[#eceef2] rounded-2xl p-md shadow-sm">
<span className="text-[9px] font-black text-purple-600 uppercase tracking-wider block">Profile Registry Details</span>
<div className="space-y-xs text-zinc-650">
<div className="flex items-center gap-sm py-1 border-b border-[#f1f5f9]">
<Phone size={13} className="text-zinc-400 shrink-0" />
<span className="font-mono font-semibold">{selectedCustomer.phone}</span>
</div>
<div className="flex items-center gap-sm py-1 border-b border-[#f1f5f9]">
<Mail size={13} className="text-zinc-400 shrink-0" />
<span>{selectedCustomer.name.toLowerCase().replace(/[^a-z]/g, '')}@gmail.com</span>
</div>
<div className="flex items-start gap-sm py-1">
<MapPin size={13} className="text-zinc-400 shrink-0 mt-0.5" />
<span>{selectedCustomer.address}</span>
</div>
</div>
</div>
{/* Metric grid info overlay */}
<div className="grid grid-cols-3 gap-sm select-none">
<div className="bg-[#faf5ff] border border-[#f3e8ff] p-sm rounded-xl text-center">
<span className="text-[8px] font-black text-purple-400 uppercase tracking-widest block">Dispatches</span>
<span className="font-black text-sm text-[#581c87] mt-xs block">{selectedCustomer.ordersCount} dispatches</span>
</div>
<div className="bg-sky-50/50 border border-sky-100 p-sm rounded-xl text-center">
<span className="text-[8px] font-black text-sky-500 uppercase tracking-widest block">Gross spend</span>
<span className="font-black text-sm text-sky-700 mt-xs block">{selectedCustomer.totalSpent}</span>
</div>
<div className="bg-emerald-50/50 border border-emerald-100 p-sm rounded-xl text-center">
<span className="text-[8px] font-black text-emerald-500 uppercase tracking-widest block">CSAT Score</span>
<span className="font-black text-sm text-emerald-700 mt-xs block">5.0 / 5.0</span>
</div>
</div>
{/* Simulated Customer Order History ledger */}
<div className="space-y-sm">
<h5 className="font-sans font-bold text-xs text-[#0f172a] flex items-center gap-xs">
<History size={14} className="text-[#581c87]" /> Past Interactions & Orders
</h5>
<div className="divide-y divide-[#f1f5f9] select-none text-[11px] font-semibold text-zinc-650">
<div className="py-2.5 flex justify-between items-center">
<div className="space-y-0.5">
<span className="text-[#0f172a]">DM-ORD-2091</span>
<p className="text-[9px] text-zinc-400 font-medium">{selectedCustomer.lastOrder}</p>
</div>
<div className="text-right">
<span className="font-mono text-[#581c87] font-bold">{selectedCustomer.totalSpent}</span>
<span className="px-1.5 py-0.2 bg-emerald-50 text-emerald-600 rounded text-[7px] font-black tracking-wider block mt-0.5 uppercase">Delivered</span>
</div>
</div>
<div className="py-2.5 flex justify-between items-center opacity-70">
<div className="space-y-0.5">
<span className="text-[#0f172a]">DM-ORD-1982</span>
<p className="text-[9px] text-zinc-400 font-medium">1 Month ago</p>
</div>
<div className="text-right">
<span className="font-mono text-zinc-700 font-bold">1,240.00</span>
<span className="px-1.5 py-0.2 bg-emerald-50 text-emerald-600 rounded text-[7px] font-black tracking-wider block mt-0.5 uppercase">Delivered</span>
</div>
</div>
<div className="py-2.5 flex justify-between items-center opacity-60">
<div className="space-y-0.5">
<span className="text-[#0f172a]">DM-ORD-1721</span>
<p className="text-[9px] text-zinc-400 font-medium">2 Months ago</p>
</div>
<div className="text-right">
<span className="font-mono text-zinc-700 font-bold">2,840.00</span>
<span className="px-1.5 py-0.2 bg-emerald-50 text-emerald-600 rounded text-[7px] font-black tracking-wider block mt-0.5 uppercase">Delivered</span>
</div>
</div>
</div>
</div>
</div>
{/* Quick Actions in Side Drawer */}
<div className="p-lg bg-[#f8fafc] border-t border-[#e2e8f0] grid grid-cols-2 gap-sm shrink-0">
<button
onClick={() => {
showToast(`Promo voucher code SMS broadcasted to customer.`, 'success');
setSelectedCustomer(null);
}}
className="w-full py-2.5 bg-[#581c87] hover:bg-purple-800 text-white rounded-xl font-bold text-center cursor-pointer transition shadow-sm"
>
Send Promo SMS
</button>
<button
onClick={() => {
showToast(`Refund credit index check initiated.`, 'info');
setSelectedCustomer(null);
}}
className="w-full py-2.5 border border-[#e2e8f0] bg-white hover:bg-zinc-50 rounded-xl font-bold text-center text-zinc-700 cursor-pointer transition"
>
Issue Store Credit
</button>
</div>
</div>
</div>
)}
</div>
);
}