diff --git a/app/dashboard/orders/[id]/page.tsx b/app/dashboard/orders/[id]/page.tsx index f6dc233..3a18e62 100644 --- a/app/dashboard/orders/[id]/page.tsx +++ b/app/dashboard/orders/[id]/page.tsx @@ -3,7 +3,6 @@ import { fetchData } from '@/lib/data-service'; import { useEffect, useState } from "react"; import { useParams } from "next/navigation"; -import Layout from "@/components/layout/layout"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; @@ -25,9 +24,20 @@ import { CardTitle, } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; -import { Clipboard, Truck, Package } from "lucide-react"; +import { Clipboard, Truck, Package, ArrowRight } from "lucide-react"; import { useRouter } from "next/navigation"; import { toast } from "sonner"; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from "@/components/ui/alert-dialog"; interface Order { orderId: string; @@ -70,6 +80,13 @@ export default function OrderDetailsPage() { const [isPaid, setIsPaid] = useState(false); const [isSending, setIsSending] = useState(false); const [isMarkingShipped, setIsMarkingShipped] = useState(false); + const [isDiscarding, setIsDiscarding] = useState(false); + const [nextOrderId, setNextOrderId] = useState(null); + const [prevOrderId, setPrevOrderId] = useState(null); + const [totalOrders, setTotalOrders] = useState(0); + const [currentOrderNumber, setCurrentOrderNumber] = useState(0); + const [totalPages, setTotalPages] = useState(1); + const [currentPage, setCurrentPage] = useState(1); const router = useRouter(); const params = useParams(); @@ -160,6 +177,36 @@ export default function OrderDetailsPage() { } }; + const handleDiscardOrder = async () => { + try { + setIsDiscarding(true); + const authToken = document.cookie.split("Authorization=")[1]; + const response = await fetchData( + `${process.env.NEXT_PUBLIC_API_URL}/orders/${orderId}`, + { + method: "PUT", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${authToken}`, + }, + body: JSON.stringify({ status: "cancelled" }), + } + ); + + if (response && response.message === "Order status updated successfully") { + setOrder((prevOrder) => prevOrder ? { ...prevOrder, status: "cancelled" } : null); + toast.success("Order discarded successfully!"); + } else { + throw new Error(response.error || "Failed to discard order"); + } + } catch (error: any) { + console.error("Failed to discard order:", error); + toast.error(error.message || "Failed to discard order"); + } finally { + setIsDiscarding(false); + } + }; + useEffect(() => { const fetchOrderDetails = async () => { try { @@ -199,6 +246,60 @@ export default function OrderDetailsPage() { fetchOrderDetails(); }, [orderId]); + useEffect(() => { + const fetchAdjacentOrders = async () => { + try { + const authToken = document.cookie.split("Authorization=")[1]; + + if (!order?.orderId) return; + + // Fetch previous and next orders in parallel + const [prevOrdersRes, nextOrdersRes] = await Promise.all([ + // Get one order before the current one (newer orders) + fetchData( + `${process.env.NEXT_PUBLIC_API_URL}/orders?limit=1&after=${order.orderId}`, + { + method: "GET", + headers: { Authorization: `Bearer ${authToken}` }, + } + ), + // Get one order after the current one (older orders) + fetchData( + `${process.env.NEXT_PUBLIC_API_URL}/orders?limit=1&before=${order.orderId}`, + { + method: "GET", + headers: { Authorization: `Bearer ${authToken}` }, + } + ) + ]); + + // Set previous (newer) order ID if exists + if (prevOrdersRes?.orders?.length > 0) { + setPrevOrderId(prevOrdersRes.orders[0]._id); + } else { + setPrevOrderId(null); + } + + // Set next (older) order ID if exists + if (nextOrdersRes?.orders?.length > 0) { + setNextOrderId(nextOrdersRes.orders[0]._id); + } else { + setNextOrderId(null); + } + + console.log('Current order:', order.orderId); + console.log('Newer order:', prevOrdersRes?.orders?.[0]?._id); + console.log('Older order:', nextOrdersRes?.orders?.[0]?._id); + } catch (error) { + console.error("Failed to fetch adjacent orders:", error); + } + }; + + if (order) { + fetchAdjacentOrders(); + } + }, [order]); + const handleAddTracking = async () => { if (!trackingNumber) { toast.error("Please enter a tracking number"); @@ -249,10 +350,12 @@ export default function OrderDetailsPage() { return
Error: {error}
; return ( - +
-

Order Details: {order?.orderId}

+
+

Order Details: {order?.orderId}

+
{order?.status} @@ -383,31 +486,94 @@ export default function OrderDetailsPage() {
-
- {order?.status === "unpaid" && ( - - )} - - {order?.status === "paid" && ( - - )} +
+
+ {order?.status !== "cancelled" && ( + + + + + + + Are you sure? + + This action will discard the order and cannot be undone. + + + + Cancel + + Discard Order + + + + + )} +
+
+ {order?.status === "unpaid" && ( + + )} + + {order?.status === "paid" && ( + + )} +
+
+ + {/* Order Navigation */} +
+
+ {prevOrderId && ( + + )} +
+
+ {nextOrderId && ( + + )} +
- +
); } \ No newline at end of file diff --git a/components/tables/order-table.tsx b/components/tables/order-table.tsx index 3d1b23f..63ece16 100644 --- a/components/tables/order-table.tsx +++ b/components/tables/order-table.tsx @@ -67,6 +67,8 @@ export default function OrderTable() { const [loading, setLoading] = useState(true); const [statusFilter, setStatusFilter] = useState("all"); const [currentPage, setCurrentPage] = useState(1); + const [totalPages, setTotalPages] = useState(1); + const [totalOrders, setTotalOrders] = useState(0); const [sortConfig, setSortConfig] = useState<{ column: SortableColumns; direction: "asc" | "desc"; @@ -75,24 +77,42 @@ export default function OrderTable() { const [isShipping, setIsShipping] = useState(false); const ITEMS_PER_PAGE = 10; - // Fetch orders with error handling + // Fetch orders with server-side pagination const fetchOrders = useCallback(async () => { try { setLoading(true); - const data = await clientFetch("/orders"); + const queryParams = new URLSearchParams({ + page: currentPage.toString(), + limit: ITEMS_PER_PAGE.toString(), + ...(statusFilter !== "all" && { status: statusFilter }), + }); + + const data = await clientFetch(`/orders?${queryParams}`); + setOrders(data.orders || []); + setTotalPages(data.totalPages || 1); + setTotalOrders(data.totalOrders || 0); } catch (error) { toast.error("Failed to fetch orders"); console.error("Fetch error:", error); } finally { setLoading(false); } - }, []); + }, [currentPage, statusFilter]); useEffect(() => { fetchOrders(); }, [fetchOrders]); + // Reset to first page when filter changes + useEffect(() => { + setCurrentPage(1); + }, [statusFilter]); + + const handlePageChange = (newPage: number) => { + setCurrentPage(newPage); + }; + // Derived data calculations const filteredOrders = orders.filter( (order) => statusFilter === "all" || order.status === statusFilter @@ -115,7 +135,6 @@ export default function OrderTable() { return 0; }); - const totalPages = Math.ceil(sortedOrders.length / ITEMS_PER_PAGE); const paginatedOrders = sortedOrders.slice( (currentPage - 1) * ITEMS_PER_PAGE, currentPage * ITEMS_PER_PAGE @@ -202,19 +221,24 @@ export default function OrderTable() {
{/* Toolbar */}
- +
+ +
+ Total Orders: {totalOrders} +
+
@@ -246,47 +270,39 @@ export default function OrderTable() {
{/* Table */} - - - - - 0 && selectedOrders.size === paginatedOrders.length} - onCheckedChange={toggleAll} - /> - - handleSort("orderId")}> - Order ID - - handleSort("totalPrice")}> - Total - - handleSort("status")}> - Status - - handleSort("orderDate")}> - Date - - Buyer - Actions - - - - - {loading ? ( +
+ {loading && ( +
+ +
+ )} +
+ - - - + + 0} + onCheckedChange={toggleAll} + /> + + handleSort("orderId")}> + Order ID + + handleSort("totalPrice")}> + Total + + handleSort("status")}> + Status + + handleSort("orderDate")}> + Date + + Buyer + Actions - ) : paginatedOrders.length === 0 ? ( - - - No orders found - - - ) : ( - paginatedOrders.map(order => { + + + {orders.map((order) => { const StatusIcon = statusConfig[order.status as keyof typeof statusConfig]?.icon || XCircle; return ( @@ -321,36 +337,34 @@ export default function OrderTable() { ); - }) - )} - -
+ })} + + +
{/* Pagination */} -
-
- {selectedOrders.size} of {sortedOrders.length} row(s) selected +
+
+ Page {currentPage} of {totalPages}
- -
+
- - Page {currentPage} of {totalPages} -