"use client"; import { useState, useEffect, useCallback } from "react"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Button } from "@/components/ui/button"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Eye, Loader2, CheckCircle2, XCircle, ChevronLeft, ChevronRight, ArrowUpDown, Truck, } from "lucide-react"; import Link from "next/link"; import { clientFetch } from '@/lib/client-utils'; import { toast } from "sonner"; import { Checkbox } from "@/components/ui/checkbox"; interface Order { _id: string; orderId: string; status: string; totalPrice: number; orderDate: Date; telegramUsername?: string; } type SortableColumns = "orderId" | "totalPrice" | "status" | "orderDate"; interface StatusConfig { icon: React.ElementType; color: string; animate?: string; } type OrderStatus = "paid" | "unpaid" | "confirming" | "shipped" | "completed" | "disputed" | "cancelled"; export default function OrderTable() { const [orders, setOrders] = useState([]); const [loading, setLoading] = useState(true); const [statusFilter, setStatusFilter] = useState("all"); const [currentPage, setCurrentPage] = useState(1); const [sortConfig, setSortConfig] = useState<{ column: SortableColumns; direction: "asc" | "desc"; }>({ column: "orderDate", direction: "desc" }); const [selectedOrders, setSelectedOrders] = useState>(new Set()); const ITEMS_PER_PAGE = 10; // Fetch orders with error handling const fetchOrders = useCallback(async () => { try { setLoading(true); const data = await clientFetch("/orders"); setOrders(data.orders || []); } catch (error) { toast.error("Failed to fetch orders"); console.error("Fetch error:", error); } finally { setLoading(false); } }, []); useEffect(() => { fetchOrders(); }, [fetchOrders]); // Derived data calculations const filteredOrders = orders.filter( (order) => statusFilter === "all" || order.status === statusFilter ); const sortedOrders = [...filteredOrders].sort((a, b) => { const aValue = a[sortConfig.column]; const bValue = b[sortConfig.column]; if (typeof aValue === "string" && typeof bValue === "string") { return sortConfig.direction === "asc" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue); } if (typeof aValue === "number" && typeof bValue === "number") { return sortConfig.direction === "asc" ? aValue - bValue : bValue - aValue; } return 0; }); const totalPages = Math.ceil(sortedOrders.length / ITEMS_PER_PAGE); const paginatedOrders = sortedOrders.slice( (currentPage - 1) * ITEMS_PER_PAGE, currentPage * ITEMS_PER_PAGE ); // Handlers const handleSort = (column: SortableColumns) => { setSortConfig(prev => ({ column, direction: prev.column === column && prev.direction === "asc" ? "desc" : "asc" })); }; const toggleSelection = (orderId: string) => { setSelectedOrders(prev => { const newSet = new Set(prev); newSet.has(orderId) ? newSet.delete(orderId) : newSet.add(orderId); return newSet; }); }; const toggleAll = () => { if (selectedOrders.size === paginatedOrders.length) { setSelectedOrders(new Set()); } else { setSelectedOrders(new Set(paginatedOrders.map(o => o._id))); } }; const markAsShipped = async () => { if (selectedOrders.size === 0) { toast.warning("Please select orders to mark as shipped"); return; } try { await clientFetch("/orders/mark-shipped", { method: "POST", body: JSON.stringify({ orderIds: Array.from(selectedOrders) }) }); setOrders(prev => prev.map(order => selectedOrders.has(order._id) ? { ...order, status: "shipped" } : order ) ); setSelectedOrders(new Set()); toast.success("Selected orders marked as shipped"); } catch (error) { toast.error("Failed to update orders"); console.error("Shipping error:", error); } }; const statusConfig: Record = { paid: { icon: CheckCircle2, color: "text-green-500" }, unpaid: { icon: XCircle, color: "text-red-500" }, confirming: { icon: Loader2, color: "text-yellow-500", animate: "animate-spin" }, shipped: { icon: Truck, color: "text-blue-500" }, completed: { icon: CheckCircle2, color: "text-gray-500" }, disputed: { icon: XCircle, color: "text-orange-500" }, cancelled: { icon: XCircle, color: "text-gray-400" } }; return (
{/* Toolbar */}
{/* Table */} 0 && selectedOrders.size === paginatedOrders.length} onCheckedChange={toggleAll} /> handleSort("orderId")}> Order ID handleSort("totalPrice")}> Total handleSort("status")}> Status handleSort("orderDate")}> Date Buyer Actions {loading ? ( ) : paginatedOrders.length === 0 ? ( No orders found ) : ( paginatedOrders.map(order => { const StatusIcon = statusConfig[order.status as keyof typeof statusConfig]?.icon || XCircle; return ( toggleSelection(order._id)} /> #{order.orderId} £{order.totalPrice.toFixed(2)}
{order.status.charAt(0).toUpperCase() + order.status.slice(1)}
{new Date(order.orderDate).toLocaleDateString("en-GB")} {order.telegramUsername ? `@${order.telegramUsername}` : "-"}
); }) )}
{/* Pagination */}
{selectedOrders.size} of {sortedOrders.length} row(s) selected
Page {currentPage} of {totalPages}
); }