Files
ember-market-frontend/components/order-table.tsx
2025-02-07 16:52:28 +00:00

198 lines
6.2 KiB
TypeScript

"use client";
import { useState, useEffect } 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,
Loader,
CheckCircle,
XCircle,
ChevronLeft,
ChevronRight,
} from "lucide-react";
import Link from "next/link";
import { fetchWithAuthClient } from "@/lib/client-utils";
import { toast } from "sonner";
// ✅ Define Order Type
interface Order {
_id: string;
orderId: number;
status: string;
totalPrice: number;
escrowExpiresAt: string;
telegramUsername: string;
}
interface OrdersResponse {
orders: Order[];
page: number;
totalPages: number;
}
export default function OrderTable() {
const [orders, setOrders] = useState<Order[] | null>(null);
const [loading, setLoading] = useState<boolean>(true);
const [statusFilter, setStatusFilter] = useState<string>("all"); // ✅ Status Filter
const [currentPage, setCurrentPage] = useState<number>(1);
const [totalPages, setTotalPages] = useState<number>(1);
// ✅ Fetch Orders with Pagination & Filtering
useEffect(() => {
const fetchOrders = async () => {
try {
setLoading(true);
const query = new URLSearchParams({
page: currentPage.toString(),
limit: "10",
});
if (statusFilter !== "all") {
query.append("status", statusFilter);
}
const response: OrdersResponse = await fetchWithAuthClient(
`/orders?${query.toString()}`
);
if (response.orders) {
setOrders(response.orders);
setTotalPages(response.totalPages);
} else {
throw new Error("Invalid API response format");
}
} catch (error) {
toast.error("Failed to fetch orders.");
console.error("Error fetching orders:", error);
} finally {
setLoading(false);
}
};
fetchOrders();
}, [statusFilter, currentPage]);
return (
<div className="rounded-lg border dark:border-zinc-700 shadow-sm overflow-hidden">
{/* ✅ Filtering UI */}
<div className="p-4 flex justify-between items-center border-b dark:border-zinc-700">
<h2 className="text-lg font-semibold text-gray-900 dark:text-white">
Orders
</h2>
<Select value={statusFilter} onValueChange={setStatusFilter}>
<SelectTrigger className="w-32">
<SelectValue placeholder="Filter Status" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">All</SelectItem>
<SelectItem value="paid">Paid</SelectItem>
<SelectItem value="unpaid">Unpaid</SelectItem>
<SelectItem value="shipped">Shipped</SelectItem>
<SelectItem value="completed">Completed</SelectItem>
</SelectContent>
</Select>
</div>
<Table>
<TableHeader className="bg-gray-50 dark:bg-zinc-800/50">
<TableRow>
<TableHead className="w-[150px] text-center">Order ID</TableHead>{" "}
{/* Center-aligned */}
<TableHead className="text-center">Total (£)</TableHead>
<TableHead className="text-center">Status</TableHead>
<TableHead className="text-center">Buyer</TableHead>
<TableHead className="text-right">Action</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{loading ? (
<TableRow>
<TableCell colSpan={6} className="text-center py-4">
<Loader className="h-5 w-5 animate-spin" />
</TableCell>
</TableRow>
) : orders && orders.length > 0 ? (
orders.map((order) => (
<TableRow
key={order._id}
className="transition-colors hover:bg-gray-50 dark:hover:bg-zinc-800/70"
>
<TableCell className="font-medium text-center">
#{order.orderId}
</TableCell>
<TableCell className="text-center">
£{order.totalPrice.toFixed(2)}
</TableCell>
<TableCell className="text-center">
{order.status === "paid" ? (
<div className="text-green-500 flex items-center justify-center">
<CheckCircle className="h-4 w-4 mr-1" /> Paid
</div>
) : (
<div className="text-red-500 flex items-center justify-center">
<XCircle className="h-4 w-4 mr-1" /> {order.status}
</div>
)}
</TableCell>
<TableCell className="text-center">
@{order.telegramUsername}
</TableCell>
<TableCell className="text-right">
<Link href={`/dashboard/orders/${order._id}`}>
<Button size="sm" variant="ghost">
<Eye className="h-4 w-4" />
</Button>
</Link>
</TableCell>
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={6} className="h-24 text-center">
No orders found.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<div className="p-4 flex justify-between items-center border-t dark:border-zinc-700">
<Button
variant="outline"
size="sm"
disabled={currentPage === 1}
onClick={() => setCurrentPage((prev) => Math.max(prev - 1, 1))}
>
<ChevronLeft className="h-4 w-4" /> Previous
</Button>
<span className="text-sm text-gray-500 dark:text-gray-400">
Page {currentPage} of {totalPages}
</span>
<Button
variant="outline"
size="sm"
disabled={currentPage >= totalPages}
onClick={() => setCurrentPage((prev) => prev + 1)}
>
Next <ChevronRight className="h-4 w-4" />
</Button>
</div>
</div>
);
}