122 lines
4.2 KiB
TypeScript
122 lines
4.2 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { useApp } from '../context/AppContext';
|
|
import { useApi } from '../hooks/useApi';
|
|
import { OrderData } from '../types';
|
|
|
|
export function Orders() {
|
|
const [orders, setOrders] = useState<OrderData[]>([]);
|
|
const [loading, setLoading] = useState<boolean>(true);
|
|
const navigate = useNavigate();
|
|
const { user } = useApp();
|
|
const { getOrders } = useApi();
|
|
|
|
useEffect(() => {
|
|
if (!user) {
|
|
navigate('/login');
|
|
return;
|
|
}
|
|
fetchOrders();
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [user, navigate]);
|
|
|
|
const fetchOrders = async () => {
|
|
try {
|
|
const data = await getOrders();
|
|
setOrders(data);
|
|
} catch (error) {
|
|
console.error('Error fetching orders:', error);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
const getStatusColor = (status: string): string => {
|
|
const colors: Record<string, string> = {
|
|
pending: 'bg-yellow-900 text-yellow-200 border-yellow-700',
|
|
processing: 'bg-blue-900 text-blue-200 border-blue-700',
|
|
shipped: 'bg-purple-900 text-purple-200 border-purple-700',
|
|
delivered: 'bg-green-900 text-green-200 border-green-700',
|
|
cancelled: 'bg-red-900 text-red-200 border-red-700',
|
|
};
|
|
return colors[status] || 'bg-gray-900 text-gray-200 border-gray-700';
|
|
};
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="text-center py-12">
|
|
<div className="text-gray-400">Loading orders...</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
<h1 className="text-3xl font-bold text-white mb-8">My Orders</h1>
|
|
|
|
{orders.length === 0 ? (
|
|
<div className="text-center py-12">
|
|
<p className="text-gray-400 mb-8">You have no orders yet</p>
|
|
<button
|
|
onClick={() => navigate('/products')}
|
|
className="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-lg transition-colors"
|
|
>
|
|
Browse Products
|
|
</button>
|
|
</div>
|
|
) : (
|
|
<div className="space-y-6">
|
|
{orders.map((order) => (
|
|
<div
|
|
key={order.id}
|
|
className="bg-gray-800 rounded-lg border border-gray-700 overflow-hidden"
|
|
>
|
|
<div className="p-4 border-b border-gray-700 flex justify-between items-center">
|
|
<div>
|
|
<h3 className="text-lg font-semibold text-white">Order #{order.id}</h3>
|
|
<p className="text-sm text-gray-400">
|
|
{new Date(order.created_at).toLocaleDateString()}
|
|
</p>
|
|
</div>
|
|
<span
|
|
className={`px-3 py-1 rounded-full text-sm font-medium border ${getStatusColor(
|
|
order.status
|
|
)}`}
|
|
>
|
|
{order.status.charAt(0).toUpperCase() + order.status.slice(1)}
|
|
</span>
|
|
</div>
|
|
|
|
<div className="p-4">
|
|
{order.items.map((item) => (
|
|
<div
|
|
key={item.id}
|
|
className="flex justify-between items-center py-2 border-b border-gray-700 last:border-b-0"
|
|
>
|
|
<div>
|
|
<p className="text-white font-medium">Product #{item.product_id}</p>
|
|
<p className="text-sm text-gray-400">Quantity: {item.quantity}</p>
|
|
</div>
|
|
<p className="text-white font-bold">
|
|
${(item.price * item.quantity).toFixed(2)}
|
|
</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
<div className="p-4 bg-gray-750 border-t border-gray-700 flex justify-between items-center">
|
|
<div className="text-sm text-gray-400">
|
|
{order.shipping_address && <span>Ship to: {order.shipping_address}</span>}
|
|
</div>
|
|
<div className="text-xl">
|
|
<span className="text-gray-400">Total:</span>{' '}
|
|
<span className="text-white font-bold">${order.total_amount}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|