"use client"; import { useState, useEffect, useCallback } from "react"; import { useAuth } from "@/lib/AuthContext"; import { useRouter } from "next/navigation"; import { ShoppingBag, Package, User, Clock, ChevronRight, Loader2, Inbox, } from "lucide-react"; import ErrorFeedback from "@/components/ErrorFeedback"; // ── Types ── interface OrderListing { id: string; title: string; category: string; priceFlh: number; } interface OrderParty { id: string; name: string; email: string; avatar?: string | null; } interface Order { id: string; listingId: string; buyerId: string; sellerId: string; status: string; amountFlh: number; platformFee: number; packageName?: string | null; createdAt: string; listing: OrderListing; buyer: OrderParty; seller: OrderParty; } // ── Status helpers ── const STATUS_COLORS: Record = { pending: { bg: "bg-gray-800/60", text: "text-gray-400", label: "Pending" }, paid: { bg: "bg-blue-900/20 border border-blue-700/30", text: "text-blue-400", label: "Paid" }, in_progress: { bg: "bg-amber-900/20 border border-amber-700/30", text: "text-amber-400", label: "In Progress" }, delivered: { bg: "bg-purple-900/20 border border-purple-700/30", text: "text-purple-400", label: "Delivered" }, completed: { bg: "bg-emerald-900/20 border border-emerald-700/30", text: "text-emerald-400", label: "Completed" }, disputed: { bg: "bg-red-900/20 border border-red-700/30", text: "text-red-400", label: "Disputed" }, cancelled: { bg: "bg-gray-800/40 border border-gray-700/30", text: "text-gray-500", label: "Cancelled" }, }; function getStatusStyle(status: string) { return STATUS_COLORS[status] || STATUS_COLORS.pending; } function formatDate(dateStr: string) { const d = new Date(dateStr); return d.toLocaleDateString("en-MY", { year: "numeric", month: "short", day: "numeric", }); } function timeAgo(dateStr: string): string { const now = Date.now(); const then = new Date(dateStr).getTime(); const diffSec = Math.floor((now - then) / 1000); if (diffSec < 60) return "just now"; const diffMin = Math.floor(diffSec / 60); if (diffMin < 60) return `${diffMin}m ago`; const diffHr = Math.floor(diffMin / 60); if (diffHr < 24) return `${diffHr}h ago`; const diffDay = Math.floor(diffHr / 24); if (diffDay < 7) return `${diffDay}d ago`; return formatDate(dateStr); } export default function OrdersPage() { const { user, token, loading } = useAuth(); const router = useRouter(); const [tab, setTab] = useState<"buyer" | "seller">("buyer"); const [orders, setOrders] = useState([]); const [loadingOrders, setLoadingOrders] = useState(true); const [error, setError] = useState(null); // ── Auth redirect ── useEffect(() => { if (!loading && !token) { router.push("/auth"); } }, [loading, token, router]); // ── Fetch orders ── const fetchOrders = useCallback(async () => { if (!token) return; setLoadingOrders(true); setError(null); try { const res = await fetch(`/mobile/api/souq/orders?role=${tab}&limit=50`, { headers: { Authorization: `Bearer ${token}` }, }); const data = await res.json(); if (res.ok) { setOrders(data.orders || []); } else { setError(data.error || "Failed to load orders"); } } catch { setError("Network error. Please try again."); } finally { setLoadingOrders(false); } }, [token, tab]); useEffect(() => { if (token) fetchOrders(); }, [token, fetchOrders]); // ── Loading (auth) ── if (loading) { return (
); } if (!user) return null; return (
{/* Header */}

My Orders

{/* Tabs */}
{/* Content */}
{loadingOrders ? (

Loading orders...

) : error ? ( ) : orders.length === 0 ? (

No orders yet

{tab === "buyer" ? "You haven't placed any orders yet. Browse the marketplace to get started." : "No one has ordered from you yet. List your services to start selling."}

) : ( orders.map((order) => { const sc = getStatusStyle(order.status); return ( ); }) )}
); }