75 lines
2.3 KiB
TypeScript
75 lines
2.3 KiB
TypeScript
'use client';
|
||
|
||
import { useEffect, useState } from 'react';
|
||
|
||
type Order = {
|
||
id: string;
|
||
email: string;
|
||
status: string;
|
||
total: number;
|
||
createdAt: string;
|
||
items: { id: string; name: string; quantity: number }[];
|
||
};
|
||
|
||
const STATUSES = ['pending', 'paid', 'shipped', 'canceled'];
|
||
|
||
export default function AdminOrdersPage() {
|
||
const [orders, setOrders] = useState<Order[]>([]);
|
||
|
||
async function load() {
|
||
const res = await fetch('/api/admin/orders');
|
||
const data = (await res.json().catch(() => ({}))) as { orders?: Order[] };
|
||
setOrders(data.orders ?? []);
|
||
}
|
||
|
||
useEffect(() => {
|
||
void load();
|
||
}, []);
|
||
|
||
async function setStatus(id: string, status: string) {
|
||
await fetch(`/api/admin/orders/${id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ status }) });
|
||
await load();
|
||
}
|
||
|
||
return (
|
||
<div className="space-y-6">
|
||
<h1 className="text-2xl font-bold">Orders</h1>
|
||
{orders.length === 0 ? (
|
||
<p className="muted py-6 text-center text-sm">No orders yet.</p>
|
||
) : (
|
||
<div className="space-y-4">
|
||
{orders.map((o) => (
|
||
<div key={o.id} className="card">
|
||
<div className="flex flex-wrap items-center justify-between gap-3">
|
||
<div>
|
||
<p className="font-mono text-sm">{o.id.slice(0, 8)}</p>
|
||
<p className="muted text-xs">
|
||
{o.email} · {new Date(o.createdAt).toLocaleDateString('en-US')}
|
||
</p>
|
||
</div>
|
||
<div className="flex items-center gap-3">
|
||
<span className="font-bold">${(o.total / 100).toFixed(2)}</span>
|
||
<select className="input w-36" value={o.status} onChange={(e) => setStatus(o.id, e.target.value)} aria-label={`Status for order ${o.id}`}>
|
||
{STATUSES.map((s) => (
|
||
<option key={s} value={s}>
|
||
{s}
|
||
</option>
|
||
))}
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<ul className="muted mt-3 space-y-1 text-sm">
|
||
{o.items.map((i) => (
|
||
<li key={i.id}>
|
||
{i.quantity}× {i.name}
|
||
</li>
|
||
))}
|
||
</ul>
|
||
</div>
|
||
))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|