From fd45910387642ade883ef7e497ba7afe6130f92a Mon Sep 17 00:00:00 2001 From: parsa aghaei Date: Wed, 15 Jul 2026 19:33:33 +0330 Subject: [PATCH] feat(admin): implement live global search, fixed position sidebar, click-to-navigate dashboard cards, and new orders count badge on sidebar --- .../admin-panel/src/components/Layout.tsx | 2 +- .../admin-panel/src/components/Sidebar.tsx | 29 ++++++- .../admin-panel/src/components/Topbar.tsx | 80 ++++++++++++++++++- frontend/admin-panel/src/pages/Dashboard.tsx | 15 ++-- 4 files changed, 112 insertions(+), 14 deletions(-) diff --git a/frontend/admin-panel/src/components/Layout.tsx b/frontend/admin-panel/src/components/Layout.tsx index a0122e8..816e7fa 100644 --- a/frontend/admin-panel/src/components/Layout.tsx +++ b/frontend/admin-panel/src/components/Layout.tsx @@ -9,7 +9,7 @@ export default function Layout() { return (
-
+
setIsMobileMenuOpen(!isMobileMenuOpen)} />
diff --git a/frontend/admin-panel/src/components/Sidebar.tsx b/frontend/admin-panel/src/components/Sidebar.tsx index d03e26b..aed4836 100644 --- a/frontend/admin-panel/src/components/Sidebar.tsx +++ b/frontend/admin-panel/src/components/Sidebar.tsx @@ -1,5 +1,7 @@ -import { Link, useLocation, useNavigate } from 'react-router-dom'; +import { useState, useEffect } from 'react'; +import { Link, useLocation, useNavigate } from 'react-router-dom'; import { Users, ShoppingCart, Tag, Settings, LogOut, TrendingUp, FolderTree, FileText, BookOpen, Heart, Package, LayoutDashboard, Languages, Image } from 'lucide-react'; +import api from '../services/api'; const menuGroups = [ { @@ -50,6 +52,24 @@ interface SidebarProps { export default function Sidebar({ isOpen, setIsOpen }: SidebarProps) { const location = useLocation(); const navigate = useNavigate(); + const [newOrdersCount, setNewOrdersCount] = useState(0); + + useEffect(() => { + const fetchOrdersCount = async () => { + try { + const response = await api.get('/admin/dashboard/stats'); + if (response.data?.success) { + setNewOrdersCount(response.data.data.newOrders); + } + } catch (err) { + console.error('Failed to fetch stats in sidebar', err); + } + }; + fetchOrdersCount(); + // Poll stats every 60 seconds + const interval = setInterval(fetchOrdersCount, 60000); + return () => clearInterval(interval); + }, []); const handleLogout = () => { localStorage.removeItem('adminToken'); @@ -66,7 +86,7 @@ export default function Sidebar({ isOpen, setIsOpen }: SidebarProps) { /> )} -
diff --git a/frontend/admin-panel/src/pages/Dashboard.tsx b/frontend/admin-panel/src/pages/Dashboard.tsx index c8b42be..6c61e32 100644 --- a/frontend/admin-panel/src/pages/Dashboard.tsx +++ b/frontend/admin-panel/src/pages/Dashboard.tsx @@ -1,4 +1,5 @@ -import { useState, useEffect } from 'react'; +import { useState, useEffect } from 'react'; +import { Link } from 'react-router-dom'; import { DollarSign, ShoppingCart, Users, Activity } from 'lucide-react'; import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, PieChart, Pie, Cell } from 'recharts'; import api from '../services/api'; @@ -43,10 +44,10 @@ export default function Dashboard() { const COLORS = ['#0088FE', '#00C49F', '#FFBB28']; const stats = [ - { title: 'درآمد کل', value: `${data.revenue.toLocaleString()} تومان`, icon: DollarSign, color: 'text-green-600', bg: 'bg-green-100' }, - { title: 'سفارشات جدید', value: data.newOrders.toString(), icon: ShoppingCart, color: 'text-blue-600', bg: 'bg-blue-100' }, - { title: 'کاربران فعال', value: data.users.toString(), icon: Users, color: 'text-purple-600', bg: 'bg-purple-100' }, - { title: 'بازدید امروز', value: data.todayVisits.toString(), icon: Activity, color: 'text-orange-600', bg: 'bg-orange-100' }, + { title: 'درآمد کل', value: `${data.revenue.toLocaleString()} تومان`, icon: DollarSign, color: 'text-green-600', bg: 'bg-green-100', link: '/reports' }, + { title: 'سفارشات جدید', value: data.newOrders.toString(), icon: ShoppingCart, color: 'text-blue-600', bg: 'bg-blue-100', link: '/orders' }, + { title: 'کاربران فعال', value: data.users.toString(), icon: Users, color: 'text-purple-600', bg: 'bg-purple-100', link: '/users' }, + { title: 'بازدید امروز', value: data.todayVisits.toString(), icon: Activity, color: 'text-orange-600', bg: 'bg-orange-100', link: '/reports' }, ]; return ( @@ -60,7 +61,7 @@ export default function Dashboard() { {stats.map((stat, i) => { const Icon = stat.icon; return ( -
+
@@ -68,7 +69,7 @@ export default function Dashboard() {

{stat.title}

{stat.value}

-
+ ); })}