kanban-app/frontend/src/pages/Orders.tsx

123 lines
4.2 KiB
TypeScript
Raw Normal View History

2026-02-25 09:29:45 +00:00
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() {
2026-02-25 09:29:45 +00:00
const [orders, setOrders] = useState<OrderData[]>([]);
const [loading, setLoading] = useState<boolean>(true);
const navigate = useNavigate();
const { user } = useApp();
const { getOrders } = useApi();
useEffect(() => {
if (!user) {
2026-02-25 09:29:45 +00:00
navigate('/login');
return;
}
2026-02-25 09:29:45 +00:00
fetchOrders();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [user, navigate]);
const fetchOrders = async () => {
try {
2026-02-25 09:29:45 +00:00
const data = await getOrders();
setOrders(data);
} catch (error) {
2026-02-25 09:29:45 +00:00
console.error('Error fetching orders:', error);
} finally {
2026-02-25 09:29:45 +00:00
setLoading(false);
}
2026-02-25 09:29:45 +00:00
};
2026-02-24 08:52:57 +00:00
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',
2026-02-25 09:29:45 +00:00
};
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>
2026-02-25 09:29:45 +00:00
);
}
return (
<div>
<h1 className="text-3xl font-bold text-white mb-8">My Orders</h1>
2026-02-25 09:29:45 +00:00
{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>
2026-02-25 09:29:45 +00:00
<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>
2026-02-25 09:29:45 +00:00
<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>
2026-02-25 09:29:45 +00:00
<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>
2026-02-25 09:29:45 +00:00
<div className="p-4 bg-gray-750 border-t border-gray-700 flex justify-between items-center">
<div className="text-sm text-gray-400">
2026-02-25 09:29:45 +00:00
{order.shipping_address && <span>Ship to: {order.shipping_address}</span>}
</div>
<div className="text-xl">
<span className="text-gray-400">Total:</span>{' '}
2026-02-25 09:29:45 +00:00
<span className="text-white font-bold">${order.total_amount}</span>
</div>
</div>
</div>
))}
</div>
)}
</div>
2026-02-25 09:29:45 +00:00
);
}