import React, { useMemo, useState } from 'react'; import { useFiestaCustomerOrders } from '../services/fiestaQueries'; import { num as fnum, str as fstr, type Row } from '../services/fiestaApi'; import { Phone, MapPin, Mail, Receipt, X, Calendar, ShoppingBag, Wallet, TrendingUp, IndianRupee } from 'lucide-react'; import OrderDetailsModal from './OrderDetailsModal'; import './CustomerDetailPanel.css'; interface CustomerDetailPanelProps { customer: Row; onClose?: () => void; } function initialsFor(name: string): string { const parts = name.trim().split(/\s+/).filter(Boolean); if (parts.length === 0) return '?'; if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase(); return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase(); } function getStatusClass(status: string): string { switch (status.toLowerCase()) { case 'created': return 'cdp-status-blue'; case 'pending': return 'cdp-status-amber'; case 'delivered': return 'cdp-status-green'; case 'cancelled': return 'cdp-status-red'; default: return 'cdp-status-blue'; } } export default function CustomerDetailPanel({ customer, onClose }: CustomerDetailPanelProps) { const customerId = fnum(customer.customerid) || fstr(customer.contactno) || 0; const { data: orders, isLoading } = useFiestaCustomerOrders({ customerid: customerId, pagesize: 100 }); const [selectedModalOrder, setSelectedModalOrder] = useState(null); const { totalOrders, totalSpend, highestBill, avgOrderValue, groupedOrders } = useMemo(() => { if (!orders || orders.length === 0) { return { totalOrders: 0, totalSpend: 0, highestBill: 0, avgOrderValue: 0, groupedOrders: [] }; } let highest = 0; let spend = 0; const groups = new Map(); for (const order of orders) { const total = fnum(order.totalamount) || fnum(order.payableamount) || 0; spend += total; if (total > highest) highest = total; const orderDateStr = fstr(order.createddate) || fstr(order.orderdate) || ''; const date = orderDateStr ? new Date(orderDateStr) : new Date(); const monthYear = date.toLocaleString('default', { month: 'long', year: 'numeric' }); if (!groups.has(monthYear)) groups.set(monthYear, []); groups.get(monthYear)!.push(order); } return { totalOrders: orders.length, totalSpend: spend, highestBill: highest, avgOrderValue: spend / orders.length, groupedOrders: Array.from(groups.entries()), }; }, [orders]); const name = fstr(customer.customername) || fstr(customer.name) || 'Unknown Customer'; const phone = fstr(customer.contactno) || fstr(customer.phone) || ''; const email = fstr(customer.email) || ''; const address = fstr(customer.address) || fstr(customer.deliveryaddress) || ''; const formatDate = (dateStr: string) => { if (!dateStr) return 'Date unknown'; const d = new Date(dateStr); return new Intl.DateTimeFormat('en-IN', { day: 'numeric', month: 'short', hour: 'numeric', minute: '2-digit', hour12: true, }).format(d); }; return (
{/* Pinned Top Area (Header + Contact + Metrics) */}
{onClose && ( )}
{initialsFor(name)}
{name} ID {customerId}
{phone && ( {phone} )} {email && ( {email} )} {address && (
{address}
)}
0 ? 'positive' : 'zero'}`}>
Lifetime Value ₹{totalSpend.toLocaleString('en-IN')}
{totalOrders} Orders
₹{highestBill.toLocaleString('en-IN')} Highest Bill
₹{avgOrderValue.toLocaleString('en-IN', { maximumFractionDigits: 0 })} Avg Value
{/* Scrollable Order History Area */}
{isLoading ? (
Loading order history...
) : groupedOrders.length > 0 ? (
{groupedOrders.map(([monthYear, monthOrders], idx) => (
{monthYear}
{monthOrders.map((order, orderIdx) => { const orderDate = fstr(order.createddate) || fstr(order.orderdate) || ''; const orderId = fstr(order.orderid) || String(fnum(order.orderheaderid)); const total = fnum(order.totalamount) || fnum(order.payableamount) || 0; const statusStr = fstr(order.orderstatus) || 'CREATED'; const statusBadgeClass = getStatusClass(statusStr); return (
setSelectedModalOrder(order)} >
{orderId}
{formatDate(orderDate)}
₹{total.toLocaleString('en-IN')}
{statusStr}
); })}
))}
) : (
No past orders found
)}
{selectedModalOrder && ( setSelectedModalOrder(null)} /> )}
); }