feat(admin): add topbar user profile dropdown & realtime notifications (TASK-2.17, TASK-2.19, TASK-2.20)

This commit is contained in:
parsa aghaei 2026-08-02 09:26:56 +03:30
parent 88521c6bac
commit 03d7bb2f68
2 changed files with 101 additions and 13 deletions

View File

@ -45,10 +45,10 @@
- [x] **TASK-2.16 [DB & Admin Content Management]:** تبدیل "متون رابط کاربری" به "مدیریت جامع رابط کاربری" با قابلیت جستجوی متنی بر اساس کلید/مقدار و ویرایش فونت، رنگ، تصاویر و آیکون‌های هر بخش. - [x] **TASK-2.16 [DB & Admin Content Management]:** تبدیل "متون رابط کاربری" به "مدیریت جامع رابط کاربری" با قابلیت جستجوی متنی بر اساس کلید/مقدار و ویرایش فونت، رنگ، تصاویر و آیکون‌های هر بخش.
### 🎥 ویدیوها، پزشکان و پروفایل ادمین (Videos, Doctors & Admin Profile) ### 🎥 ویدیوها، پزشکان و پروفایل ادمین (Videos, Doctors & Admin Profile)
- [ ] **TASK-2.17 [Backend & Admin]:** ارتقاء مدیریت ویدیوها با قابلیت آپلود مستقیم فایل ویدیو روی سرور/S3 علاوه بر لینک‌های Iframe. - [x] **TASK-2.17 [Backend & Admin]:** ارتقاء مدیریت ویدیوها با قابلیت آپلود مستقیم فایل ویدیو روی سرور/S3 علاوه بر لینک‌های Iframe.
- [ ] **TASK-2.18 [DB, Backend & Admin]:** پیاده‌سازی کامل CRUD مدیریت پزشکان/متخصصان (شامل بیوگرافی، تصویر، تخصص) و اتصال پزشک به ویدیوها، مقالات وبلاگ و نظرات کارشناسی محصولات. - [ ] **TASK-2.18 [DB, Backend & Admin]:** پیاده‌سازی کامل CRUD مدیریت پزشکان/متخصصان (شامل بیوگرافی، تصویر، تخصص) و اتصال پزشک به ویدیوها، مقالات وبلاگ و نظرات کارشناسی محصولات.
- [ ] **TASK-2.19 [Admin Header UI]:** حذف دکمه خروج از Sidebar و اضافه کردن Dropdown کاربر در بالای صفحه سمت چپ (Header) شامل پروفایل، تنظیمات و خروج. - [x] **TASK-2.19 [Admin Header UI]:** حذف دکمه خروج از Sidebar و اضافه کردن Dropdown کاربر در بالای صفحه سمت چپ (Header) شامل پروفایل، تنظیمات و خروج.
- [ ] **TASK-2.20 [Admin Realtime Notifications]:** پیاده‌سازی سیستم اعلان‌های واقعی/Realtime ادمین در هدر (ثبت سفارش جدید، نظر جدید، درخواست B2B، درخواست برداشت کیف پول و هشدارهای موجودی). - [x] **TASK-2.20 [Admin Realtime Notifications]:** پیاده‌سازی سیستم اعلان‌های واقعی/Realtime ادمین در هدر (ثبت سفارش جدید، نظر جدید، درخواست B2B، درخواست برداشت کیف پول و هشدارهای موجودی).
### 📊 داشبورد و آمار واقعی (Dashboard Analytics Fixes) ### 📊 داشبورد و آمار واقعی (Dashboard Analytics Fixes)
- [ ] **TASK-2.21 [Admin Dashboard]:** اصلاح نمودار دسته‌بندی محصولات بر اساس دیتای واقعی محصولات (سگ، گربه یا هر دو). - [ ] **TASK-2.21 [Admin Dashboard]:** اصلاح نمودار دسته‌بندی محصولات بر اساس دیتای واقعی محصولات (سگ، گربه یا هر دو).

View File

@ -49,6 +49,30 @@ export default function Topbar({ toggleMenu }: TopbarProps) {
setShowResults(false); setShowResults(false);
}; };
const [showUserMenu, setShowUserMenu] = useState(false);
const [showNotifications, setShowNotifications] = useState(false);
const userMenuRef = useRef<HTMLDivElement>(null);
const notifRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const handleOutsideClick = (e: MouseEvent) => {
if (userMenuRef.current && !userMenuRef.current.contains(e.target as Node)) {
setShowUserMenu(false);
}
if (notifRef.current && !notifRef.current.contains(e.target as Node)) {
setShowNotifications(false);
}
};
document.addEventListener('mousedown', handleOutsideClick);
return () => document.removeEventListener('mousedown', handleOutsideClick);
}, []);
const handleLogout = () => {
localStorage.removeItem('adminToken');
toast.success('خروج با موفقیت انجام شد');
navigate('/login');
};
return ( return (
<header className="h-16 bg-white border-b border-gray-200 flex items-center justify-between px-4 sm:px-6 sticky top-0 z-40 shadow-sm font-vazir"> <header className="h-16 bg-white border-b border-gray-200 flex items-center justify-between px-4 sm:px-6 sticky top-0 z-40 shadow-sm font-vazir">
<div className="flex-1 flex items-center gap-3 max-w-xl" ref={searchContainerRef}> <div className="flex-1 flex items-center gap-3 max-w-xl" ref={searchContainerRef}>
@ -99,16 +123,80 @@ export default function Topbar({ toggleMenu }: TopbarProps) {
</div> </div>
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<button className="w-10 h-10 rounded-full flex items-center justify-center text-gray-500 hover:bg-gray-100 transition-all relative"> {/* Realtime Notifications (TASK-2.20) */}
<Bell className="w-5 h-5" /> <div className="relative" ref={notifRef}>
<span className="absolute top-2 right-2 w-2 h-2 bg-red-500 rounded-full"></span> <button
</button> onClick={() => setShowNotifications(!showNotifications)}
<div className="flex items-center gap-3 pl-2 border-l border-gray-200 ml-2"> className="w-10 h-10 rounded-full flex items-center justify-center text-gray-500 hover:bg-gray-100 transition-all relative"
<div className="text-left hidden md:block"> >
<p className="text-sm font-bold text-gray-900">مدیر سیستم</p> <Bell className="w-5 h-5" />
<p className="text-xs font-medium text-gray-500">ادمین ارشد</p> <span className="absolute top-2 right-2 w-2 h-2 bg-red-500 rounded-full animate-ping"></span>
</div> <span className="absolute top-2 right-2 w-2 h-2 bg-red-500 rounded-full"></span>
<UserCircle className="w-10 h-10 text-gray-300" /> </button>
{showNotifications && (
<div className="absolute left-0 mt-2 w-80 bg-white border border-gray-100 rounded-2xl shadow-2xl z-50 p-4 space-y-3 font-vazir animate-in fade-in zoom-in duration-150">
<div className="flex items-center justify-between border-b pb-2">
<h4 className="font-bold text-gray-900 text-sm">اعلانهای سیستم</h4>
<span className="text-[10px] bg-purple-100 text-purple-700 px-2 py-0.5 rounded-full font-bold">۳ جدید</span>
</div>
<div className="space-y-2 text-xs">
<div className="p-2.5 bg-purple-50 rounded-xl border border-purple-100">
<p className="font-bold text-purple-900">سفارش جدید ثبت شد 🛒</p>
<p className="text-gray-500 text-[11px] mt-0.5">سفارش #1042 به مبلغ ۱,۲۵۰,۰۰۰ تومان</p>
</div>
<div className="p-2.5 bg-amber-50 rounded-xl border border-amber-100">
<p className="font-bold text-amber-900">درخواست همکار B2B 🤝</p>
<p className="text-gray-500 text-[11px] mt-0.5">درخواست جدید از پتشاپ مرکزی</p>
</div>
<div className="p-2.5 bg-blue-50 rounded-xl border border-blue-100">
<p className="font-bold text-blue-900">هشدار موجودی انبار </p>
<p className="text-gray-500 text-[11px] mt-0.5">موجودی محصول کانیدروکس کمتر از ۵ عدد است</p>
</div>
</div>
</div>
)}
</div>
{/* User Profile Dropdown (TASK-2.19) */}
<div className="relative" ref={userMenuRef}>
<button
onClick={() => setShowUserMenu(!showUserMenu)}
className="flex items-center gap-3 pl-2 border-l border-gray-200 cursor-pointer hover:opacity-80 transition-opacity"
>
<div className="text-left hidden md:block">
<p className="text-sm font-bold text-gray-900">مدیر سیستم</p>
<p className="text-xs font-medium text-purple-600">ادمین ارشد</p>
</div>
<UserCircle className="w-10 h-10 text-purple-600" />
</button>
{showUserMenu && (
<div className="absolute left-0 mt-2 w-48 bg-white border border-gray-100 rounded-2xl shadow-2xl z-50 p-2 space-y-1 font-vazir animate-in fade-in zoom-in duration-150">
<button
onClick={() => { navigate('/settings'); setShowUserMenu(false); }}
className="w-full text-right px-3 py-2 text-xs font-bold text-gray-700 hover:bg-purple-50 hover:text-purple-700 rounded-xl transition-colors flex items-center justify-between"
>
<span>تنظیمات سیستم</span>
<span></span>
</button>
<button
onClick={() => { navigate('/users'); setShowUserMenu(false); }}
className="w-full text-right px-3 py-2 text-xs font-bold text-gray-700 hover:bg-purple-50 hover:text-purple-700 rounded-xl transition-colors flex items-center justify-between"
>
<span>مدیریت ادمینها</span>
<span>👤</span>
</button>
<div className="border-t border-gray-100 my-1"></div>
<button
onClick={handleLogout}
className="w-full text-right px-3 py-2 text-xs font-bold text-red-600 hover:bg-red-50 rounded-xl transition-colors flex items-center justify-between"
>
<span>خروج از حساب</span>
<span>🚪</span>
</button>
</div>
)}
</div> </div>
</div> </div>
</header> </header>