feat: add admin page

This commit is contained in:
2026-06-24 20:15:20 +03:00
parent 45d1353091
commit 2c22cee60b
3 changed files with 168 additions and 0 deletions
+24
View File
@@ -9,6 +9,7 @@ import Contact from "./pages/Contact";
import Cart from "./pages/Cart";
import Profile from "./pages/Profile";
import ItemPage from "./pages/ItemPage";
import AdminPage from "./pages/AdminPage";
const PrivateRoute = ({ children }) => {
const token = localStorage.getItem("token");
@@ -19,6 +20,21 @@ const PrivateRoute = ({ children }) => {
return children;
};
const AdminRoute = ({ children }) => {
const token = localStorage.getItem("token");
const user = JSON.parse(localStorage.getItem("user") || "{}");
if (!token) {
return <Navigate to="/login" replace />;
}
if (user.role !== "Админ") {
return <Navigate to="/" replace />;
}
return children;
};
export default function App() {
return (
<BrowserRouter>
@@ -38,6 +54,14 @@ export default function App() {
</PrivateRoute>
}
/>
<Route
path="/admin"
element={
<AdminRoute>
<AdminPage />
</AdminRoute>
}
/>
<Route path="items/:id" element={<ItemPage />} />
<Route path="*" element={<NotFoundPage />} />
</Routes>
+94
View File
@@ -0,0 +1,94 @@
import { useState, useEffect } from "react";
import { getAllItems, deleteItem } from "../api/index";
export default function AdminItems() {
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(true);
const loadItems = () => {
getAllItems()
.then((res) => setItems(res.data))
.catch(() => { })
.finally(() => setLoading(false));
};
useEffect(() => {
loadItems();
}, []);
const handleDelete = async (id, name) => {
if (!confirm(`Удалить товар "${name}"?`)) return;
try {
await deleteItem(id);
setItems((prev) => prev.filter((it) => it.id !== id));
} catch {
alert("Не удалось удалить товар");
}
};
if (loading) return <p className="text-white/60">Загрузка...</p>;
return (
<div>
{/* Кнопка добавления (форму подключим следующим шагом) */}
<button className="mb-6 bg-gold text-black px-6 py-2 rounded-md font-medium uppercase text-sm">
+ Добавить товар
</button>
{/* Таблица товаров */}
<div className="overflow-x-auto">
<table className="w-full text-sm text-left">
<thead className="text-white/50 uppercase text-xs border-b border-white/10">
<tr>
<th className="py-3 pr-4">Фото</th>
<th className="py-3 pr-4">Название</th>
<th className="py-3 pr-4">Категория</th>
<th className="py-3 pr-4">Цена</th>
<th className="py-3 pr-4">Остаток</th>
<th className="py-3 pr-4">Тип</th>
<th className="py-3 pr-4">Действия</th>
</tr>
</thead>
<tbody>
{items.map((item) => (
<tr
key={item.id}
className="border-b border-white/5 hover:bg-white/5 transition-colors"
>
<td className="py-3 pr-4">
<img
src={item.avatar_url}
alt=""
className="w-12 h-12 object-cover rounded"
/>
</td>
<td className="py-3 pr-4 font-medium">{item.name}</td>
<td className="py-3 pr-4 text-white/70">{item.category}</td>
<td className="py-3 pr-4">{item.price} </td>
<td className="py-3 pr-4">
{item.stock} {item.unit}
</td>
<td className="py-3 pr-4 text-white/70">
{item.unit_type === "piece" ? "шт" : "вес"}
</td>
<td className="py-3 pr-4">
<div className="flex gap-2">
<button className="text-blue-400 hover:text-blue-300 text-sm">
Изменить
</button>
<button
onClick={() => handleDelete(item.id, item.name)}
className="text-red-400 hover:text-red-300 text-sm"
>
Удалить
</button>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}
+50
View File
@@ -0,0 +1,50 @@
import { useState } from "react";
import PageLayout from "../components/PageLayout";
import AdminItems from "../components/AdminItems";
// import AdminOrders from "../components/AdminOrders"; // добавим позже
// import AdminStaff from "../components/AdminStaff"; // добавим позже
export default function AdminPage() {
const [tab, setTab] = useState("items");
const tabs = [
{ key: "items", label: "Товары" },
{ key: "orders", label: "Заказы" },
{ key: "staff", label: "Сотрудники" },
];
return (
<PageLayout>
<main className="px-6 md:px-16 grow w-full mb-10 text-white">
<h1 className="text-2xl md:text-4xl font-medium uppercase mb-8">
Админ-панель
</h1>
{/* Вкладки */}
<div className="flex gap-2 mb-8 border-b border-white/10">
{tabs.map((t) => (
<button
key={t.key}
onClick={() => setTab(t.key)}
className={`px-4 py-2 text-sm uppercase transition-colors ${tab === t.key
? "text-white border-b-2 border-gold"
: "text-white/50 hover:text-white/80"
}`}
>
{t.label}
</button>
))}
</div>
{/* Содержимое активной вкладки */}
{tab === "items" && <AdminItems />}
{tab === "orders" && (
<p className="text-white/50">Раздел заказов в разработке</p>
)}
{tab === "staff" && (
<p className="text-white/50">Раздел сотрудников в разработке</p>
)}
</main>
</PageLayout>
);
}