99 lines
3.3 KiB
React
99 lines
3.3 KiB
React
import { useState, useEffect } from "react";
|
||
import { getAllOrders, updateOrderStatus } from "../api/index";
|
||
import { useNavigate, useParams } from "react-router-dom";
|
||
|
||
const STATUSES = [
|
||
{ value: "new", label: "Новый" },
|
||
{ value: "packed", label: "Собран" },
|
||
{ value: "delivered", label: "Доставлен" },
|
||
{ value: "cancel", label: "Отменён" },
|
||
];
|
||
|
||
export default function AdminOrders() {
|
||
const [orders, setOrders] = useState([]);
|
||
const [loading, setLoading] = useState(true);
|
||
|
||
const loadOrders = () => {
|
||
getAllOrders()
|
||
.then((res) => setOrders(res.data))
|
||
.catch(() => { })
|
||
.finally(() => setLoading(false));
|
||
};
|
||
|
||
useEffect(() => {
|
||
loadOrders();
|
||
}, []);
|
||
|
||
const handleStatusChange = async (id, newStatus) => {
|
||
try {
|
||
await updateOrderStatus(id, { status: newStatus });
|
||
setOrders((prev) =>
|
||
prev.map((o) => (o.id === id ? { ...o, status: newStatus } : o)),
|
||
);
|
||
} catch {
|
||
alert("Не удалось изменить статус");
|
||
}
|
||
};
|
||
|
||
const navigate = useNavigate();
|
||
|
||
if (loading) return <p className="text-white/60">Загрузка...</p>;
|
||
|
||
return (
|
||
<div className="flex flex-col gap-4">
|
||
{orders.length === 0 ? (
|
||
<p className="text-white/60">Заказов нет</p>
|
||
) : (
|
||
orders.map((order) => (
|
||
<div
|
||
key={order.id}
|
||
className="bg-white/5 rounded-lg p-4 border border-white/10 hover:bg-white/10"
|
||
onClick={() => navigate(`/admin/orders/${order.id}`)}
|
||
>
|
||
{/* шапка: номер + селект статуса */}
|
||
<div className="flex justify-between items-center mb-3">
|
||
<span className="font-medium text-white">Заказ #{order.id}</span>
|
||
<select
|
||
value={order.status}
|
||
onChange={(e) => handleStatusChange(order.id, e.target.value)}
|
||
className="bg-slate-700 text-white text-sm rounded px-3 py-1 border border-white/10"
|
||
>
|
||
{STATUSES.map((s) => (
|
||
<option key={s.value} value={s.value}>
|
||
{s.label}
|
||
</option>
|
||
))}
|
||
</select>
|
||
</div>
|
||
|
||
{/* товары заказа */}
|
||
<div className="flex flex-col gap-2 mb-3 text-sm text-white/70">
|
||
{order.items?.map((oi) => (
|
||
<div key={oi.id} className="flex items-center gap-3">
|
||
<img
|
||
src={`/static/items/${oi.item?.avatar_url}`}
|
||
alt=""
|
||
className="w-20 h-20 object-cover rounded shrink-0"
|
||
/>
|
||
<span className="grow">{oi.item?.name}</span>
|
||
<span className="whitespace-nowrap">
|
||
{oi.quantity} {oi.item?.unit} × {oi.price} ₽
|
||
</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
{/* подвал: адрес + итог */}
|
||
<div className="flex justify-between pt-2 border-t border-white/10 text-sm">
|
||
<span className="text-white/50">{order.delivery_address}</span>
|
||
<span className="font-medium text-white">
|
||
Итого: {order.total_price} ₽
|
||
</span>
|
||
</div>
|
||
</div>
|
||
))
|
||
)}
|
||
</div>
|
||
);
|
||
}
|