133 lines
7.1 KiB
TypeScript
133 lines
7.1 KiB
TypeScript
import { formatValue } from '../../lib/format';
|
|
import { Badge } from '../reusable/Badge';
|
|
import { CheckCircle2Icon, Factory, UserIcon } from 'lucide-react';
|
|
|
|
export function OrderCard({ row, fields }: { row: Record<string, any>; fields: any[] }) {
|
|
const orderIdStr = row.order_id;
|
|
|
|
// Extract store lookup object if it exists
|
|
const storeObj = (row.select_store || row.store) as Record<string, unknown> | null;
|
|
const storeVal = formatValue(storeObj?.business_name || '—');
|
|
const routeVal = formatValue(storeObj?.route_name || '—');
|
|
const distributorVal = formatValue(storeObj?.distributor_name || '—');
|
|
|
|
// Extract user/performed_by object
|
|
const userKey = Object.keys(row).find(k => k.includes('user_id') || k.includes('created_by'));
|
|
const userObj = userKey ? row[userKey] as Record<string, unknown> : null;
|
|
const userVal = formatValue(userObj?.name || userObj?.user_name || '—');
|
|
const userEmail = userObj?.email ? String(userObj.email) : '';
|
|
|
|
const dateVal = row.date_of_order ? formatValue(row.date_of_order) : '—';
|
|
|
|
const stateName = String(row.current_state_name || '');
|
|
const isProductive = stateName.toLowerCase().includes('productive') || stateName.toLowerCase().includes('closed');
|
|
const productiveLabel = stateName || 'Pending';
|
|
|
|
// Order Details Grid
|
|
const gridField = fields.find(f => f.data_type === 'grid' || f.field_key === 'order_details');
|
|
const gridValRaw = gridField ? row[gridField.field_key] : row.order_details;
|
|
const gridVal = Array.isArray(gridValRaw) ? gridValRaw : [];
|
|
|
|
return (
|
|
<div className="w-full bg-white dark:bg-slate-900 rounded-2xl shadow-[0_2px_12px_-4px_rgba(0,0,0,0.08)] border border-slate-200/75 dark:border-slate-800 p-0 overflow-hidden transition-all hover:shadow-[0_8px_24px_-8px_rgba(0,0,0,0.12)]">
|
|
|
|
{/* Top Header Section */}
|
|
<div className="p-4 bg-slate-50 dark:bg-slate-800/40 border-b border-slate-100 dark:border-slate-800">
|
|
<div className="flex justify-between items-start mb-4">
|
|
<div className="flex flex-col">
|
|
<span className="text-[10px] font-bold text-slate-400 uppercase tracking-widest mb-0.5">Order ID</span>
|
|
<span className="text-[17px] font-extrabold text-slate-800 dark:text-slate-100 tracking-tight">{orderIdStr}</span>
|
|
</div>
|
|
<Badge tone={isProductive ? 'success' : 'neutral'} className="shadow-sm border-0 font-medium tracking-wide">
|
|
{isProductive && <CheckCircle2Icon size={14} className="text-emerald-500 mr-1" />}
|
|
{productiveLabel}
|
|
</Badge>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-3 gap-4">
|
|
<div className="flex flex-col gap-0.5">
|
|
<span className="text-[10px] font-bold text-slate-400 uppercase tracking-widest">Date</span>
|
|
<span className="text-[13px] font-semibold text-slate-700 dark:text-slate-300">{dateVal}</span>
|
|
</div>
|
|
<div className="flex flex-col gap-0.5 col-span-2">
|
|
<span className="text-[10px] font-bold text-slate-400 uppercase tracking-widest">Store & Route</span>
|
|
<span className="text-[13px] font-semibold text-slate-700 dark:text-slate-300 truncate">
|
|
{storeVal} <span className="text-slate-400 font-normal ml-1">({routeVal})</span>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Middle Section: Distributor & User */}
|
|
<div className="px-4 py-3 bg-slate-50/60 dark:bg-slate-800/20 border-b border-slate-100 dark:border-slate-800 flex items-center justify-between gap-2">
|
|
<div className="flex items-center gap-2.5 min-w-0 flex-1">
|
|
<div className="w-8 h-8 rounded-full bg-indigo-100 dark:bg-indigo-900/40 flex items-center justify-center shrink-0 text-indigo-600 dark:text-indigo-400">
|
|
<Factory size={14} />
|
|
</div>
|
|
<div className="flex flex-col min-w-0">
|
|
<span className="text-[9px] font-bold text-slate-400 uppercase tracking-widest">Distributor</span>
|
|
<span className="text-[12px] font-semibold text-slate-700 dark:text-slate-300 truncate">{distributorVal}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="w-px h-8 bg-slate-200 dark:bg-slate-700 shrink-0 mx-2"></div>
|
|
|
|
<div className="flex items-center gap-2.5 min-w-0 flex-1 justify-end">
|
|
<div className="flex flex-col items-end min-w-0 text-right">
|
|
<span className="text-[9px] font-bold text-slate-400 uppercase tracking-widest">Placed by</span>
|
|
<span className="text-[12px] font-semibold text-slate-700 dark:text-slate-300 truncate">{userVal}</span>
|
|
</div>
|
|
<div className="w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/40 flex items-center justify-center shrink-0 text-blue-600 dark:text-blue-400">
|
|
<UserIcon size={14} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Bottom Section: Order Items */}
|
|
{gridVal.length > 0 && (
|
|
<div className="p-4 bg-white dark:bg-slate-900">
|
|
<div className="flex justify-between items-center mb-3">
|
|
<h3 className="text-[11px] font-bold text-slate-500 dark:text-slate-400 uppercase tracking-widest flex items-center">
|
|
Order Items
|
|
<span className="ml-2 bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-300 px-2 py-0.5 rounded-full text-[10px]">
|
|
{gridVal.length}
|
|
</span>
|
|
</h3>
|
|
</div>
|
|
|
|
<div className="flex flex-col gap-1.5">
|
|
{gridVal.map((item, i) => {
|
|
const productName = formatValue(item.product_name || item.product_category || 'Unknown Product');
|
|
const sku = formatValue(item.sku_code || item.sku || 'N/A');
|
|
const bags = formatValue(item.bags || item.total_bags || item.quantity || 0);
|
|
|
|
return (
|
|
<div key={i} className="flex items-center justify-between gap-4 p-2.5 rounded-xl bg-slate-50/80 dark:bg-slate-800/30 border border-slate-100 dark:border-slate-800/60 transition-colors">
|
|
<div className="flex flex-col gap-1 min-w-0">
|
|
<div className="flex items-center">
|
|
<span className="bg-blue-50 dark:bg-blue-900/30 text-blue-700 dark:text-blue-400 text-[9px] uppercase font-bold tracking-widest px-2 py-0.5 rounded-md">
|
|
{sku}
|
|
</span>
|
|
</div>
|
|
<span className="text-[13px] font-bold text-slate-700 dark:text-slate-200 truncate">
|
|
{productName}
|
|
</span>
|
|
</div>
|
|
<div className="flex flex-col items-end justify-center shrink-0 pl-2">
|
|
<span className="text-[22px] font-black text-slate-800 dark:text-slate-100 leading-none tracking-tighter">
|
|
{bags}
|
|
</span>
|
|
<span className="text-[9px] text-slate-400 font-bold uppercase tracking-widest mt-1">
|
|
bags
|
|
</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|