"use client"; import { fetchData } from '@/lib/data-service'; import { useEffect, useState } from "react"; import { useParams } from "next/navigation"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Clipboard, Truck, Package, ArrowRight, ChevronDown } 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"; import Layout from "@/components/layout/layout"; import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "@/components/ui/collapsible"; interface Order { orderId: string; status: string; pgpAddress: string; shippingMethod: { type: string; price: number }; txid: Array; products: Array<{ _id: string; productId: string; quantity: number; pricePerUnit: number; totalItemPrice: number; }>; totalPrice: number; trackingNumber?: string; } const getStatusVariant = (status: string) => { switch (status) { case 'acknowledged': return 'secondary'; case 'paid': return 'default'; case 'shipped': return 'default'; case 'completed': return 'default'; case 'cancelled': return 'destructive'; case 'unpaid': return 'secondary'; default: return 'secondary'; } }; export default function OrderDetailsPage() { const [order, setOrder] = useState(null); const [trackingNumber, setTrackingNumber] = useState(""); const [loading, setLoading] = useState(true); const [error, setError] = useState(""); const [productNames, setProductNames] = useState>({}); 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 [isAcknowledging, setIsAcknowledging] = useState(false); const router = useRouter(); const params = useParams(); const orderId = params?.id; const fetchProductNames = async ( productIds: string[], authToken: string ): Promise> => { const productNamesMap: Record = {}; try { const promises = productIds.map((id) => fetchData(`${process.env.NEXT_PUBLIC_API_URL}/products/${id}`, { method: "GET", headers: { Authorization: `Bearer ${authToken}` }, }) ); const responses = await Promise.all(promises); const results = await Promise.all(responses.map((res) => res)); results.forEach((product, index) => { productNamesMap[productIds[index]] = product.name || "Unknown Product"; }); } catch (err) { console.error("Failed to fetch product names:", err); } return productNamesMap; }; const handleMarkAsPaid = async () => { try { 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: "paid" }), } ); if (response && response.message === "Order status updated successfully") { setIsPaid(true); // Update isPaid state setOrder((prevOrder) => (prevOrder ? { ...prevOrder, status: "paid" } : null)); // Update order status console.log("Order marked as paid successfully."); } else { const errorData = await response.json(); console.error("Failed to mark order as paid:", errorData.message); alert(`Error: ${errorData.message}`); } } catch (error: any) { console.error("An error occurred while marking the order as paid:", error.message); alert("An unexpected error occurred. Please try again."); } }; const handleMarkAsShipped = async () => { try { setIsMarkingShipped(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: "shipped" }), } ); if (response && response.message === "Order status updated successfully") { setOrder((prevOrder) => prevOrder ? { ...prevOrder, status: "shipped" } : null); toast.success("Order marked as shipped successfully!"); } else { throw new Error(response.error || "Failed to mark order as shipped"); } } catch (error: any) { console.error("Failed to mark order as shipped:", error); toast.error(error.message || "Failed to mark order as shipped"); } finally { setIsMarkingShipped(false); } }; const handleMarkAsAcknowledged = async () => { try { setIsAcknowledging(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: "acknowledged" }), } ); if (response && response.message === "Order status updated successfully") { setOrder((prevOrder) => prevOrder ? { ...prevOrder, status: "acknowledged" } : null); toast.success("Order marked as acknowledged!"); } else { throw new Error(response.error || "Failed to mark order as acknowledged"); } } catch (error: any) { console.error("Failed to mark order as acknowledged:", error); toast.error(error.message || "Failed to mark order as acknowledged"); } finally { setIsAcknowledging(false); } }; 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: "DELETE", headers: { Authorization: `Bearer ${authToken}`, }, } ); if (response && response.message === "Order deleted successfully") { toast.success("Order deleted successfully!"); router.push('/dashboard/orders'); } else { throw new Error(response.error || "Failed to delete order"); } } catch (error: any) { console.error("Failed to delete order:", error); toast.error(error.message || "Failed to delete order"); } finally { setIsDiscarding(false); } }; useEffect(() => { const fetchOrderDetails = async () => { try { if (!orderId) return; const authToken = document.cookie.split("Authorization=")[1]; const res = await fetchData( `${process.env.NEXT_PUBLIC_API_URL}/orders/${orderId}`, { method: "GET", headers: { Authorization: `Bearer ${authToken}` }, } ); if (!res) throw new Error("Failed to fetch order details"); const data: Order = await res; setOrder(data); console.log(data); const productIds = data.products.map((product) => product.productId); const productNamesMap = await fetchProductNames(productIds, authToken); setProductNames(productNamesMap); if (data.status === "paid") { setIsPaid(true); } } catch (err: any) { router.push("/dashboard/orders"); setError(err.message); } finally { setLoading(false); } }; 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"); return; } try { setIsSending(true); const authToken = document.cookie.split("Authorization=")[1]; const response = await fetchData( `${process.env.NEXT_PUBLIC_API_URL}/orders/${orderId}/tracking`, { method: "PUT", headers: { "Content-Type": "application/json", Authorization: `Bearer ${authToken}`, }, body: JSON.stringify({ trackingNumber }), } ); if (response.error) throw new Error(response.error); // Update the local state setOrder(prevOrder => prevOrder ? { ...prevOrder, trackingNumber: trackingNumber } : null); toast.success("Tracking number updated successfully!"); setTrackingNumber(""); // Clear the input } catch (err: any) { console.error("Failed to update tracking:", err); toast.error(err.message || "Failed to update tracking number"); } finally { setIsSending(false); } }; const copyToClipboard = (text: string) => { navigator.clipboard.writeText(text); }; if (loading) return (
Loading order details...
); if (error) return (
Error: {error}
); return (

Order Details: {order?.orderId}

{order?.status}
{/* Order Navigation - Moved to top */}
{nextOrderId && ( )}
Navigate Orders
{prevOrderId && ( )}
PGP Encrypted Address Securely encrypted delivery address