From 735d0a88cbe71491d8abe3773110e161f2249923 Mon Sep 17 00:00:00 2001 From: houseassassin Date: Thu, 7 May 2026 20:15:28 +0300 Subject: [PATCH] feat: add AdminLayout with dark sidebar and sticky header --- src/admin/layout/AdminLayout.jsx | 81 +++++++++++++++++++++++++++ src/admin/layout/Sidebar.jsx | 95 ++++++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+) create mode 100644 src/admin/layout/AdminLayout.jsx create mode 100644 src/admin/layout/Sidebar.jsx diff --git a/src/admin/layout/AdminLayout.jsx b/src/admin/layout/AdminLayout.jsx new file mode 100644 index 0000000..8a140be --- /dev/null +++ b/src/admin/layout/AdminLayout.jsx @@ -0,0 +1,81 @@ +import React, { useState, useEffect } from 'react'; +import { Outlet, useLocation } from 'react-router-dom'; +import { Plus } from 'lucide-react'; +import Sidebar from './Sidebar'; +import { supabase } from '../../lib/supabase'; + +const PAGE_TITLES = { + '/admin/kanban': 'Канбан', + '/admin/analytics': 'Аналитика', + '/admin/completed': 'Завершённые заказы', +}; + +const AdminLayout = () => { + const location = useLocation(); + const title = PAGE_TITLES[location.pathname] || 'Панель управления'; + const [showNewOrder, setShowNewOrder] = useState(false); + const [newCount, setNewCount] = useState(0); + + const refreshBadge = () => { + supabase + .from('orders') + .select('id', { count: 'exact', head: true }) + .eq('status', 'новая') + .then(({ count }) => setNewCount(count || 0)); + }; + + useEffect(() => { + refreshBadge(); + const channel = supabase + .channel('badge-count') + .on('postgres_changes', { event: '*', schema: 'public', table: 'orders' }, refreshBadge) + .subscribe(); + return () => supabase.removeChannel(channel); + }, []); + + return ( +
+ +
+ {/* Header */} +
+
+

+ {title} +

+ {newCount > 0 && ( + + {newCount} новых + + )} +
+ +
+ + {/* Page content */} +
+ +
+
+
+ ); +}; + +export default AdminLayout; diff --git a/src/admin/layout/Sidebar.jsx b/src/admin/layout/Sidebar.jsx new file mode 100644 index 0000000..4c7a570 --- /dev/null +++ b/src/admin/layout/Sidebar.jsx @@ -0,0 +1,95 @@ +import React from 'react'; +import { NavLink, useNavigate } from 'react-router-dom'; +import { LayoutDashboard, BarChart2, CheckSquare, Shield, LogOut } from 'lucide-react'; +import { useAuth } from '../auth/useAuth'; + +const NAV_ITEMS = [ + { to: '/admin/kanban', icon: LayoutDashboard, label: 'Канбан' }, + { to: '/admin/analytics', icon: BarChart2, label: 'Аналитика' }, + { to: '/admin/completed', icon: CheckSquare, label: 'Завершённые' }, +]; + +const Sidebar = () => { + const { session, logout } = useAuth(); + const navigate = useNavigate(); + + const handleLogout = async () => { + await logout(); + navigate('/admin/login'); + }; + + return ( + + ); +}; + +export default Sidebar;