feat(improvement): add pagination to endpoints and pages + sync navbar when data changes

This commit is contained in:
2026-03-13 10:30:27 +08:00
parent a9ebbf6a4a
commit 56404792c6
14 changed files with 543 additions and 210 deletions

View File

@@ -9,7 +9,7 @@ import { WorkspaceSelector } from "./WorkspaceSelector"
import { toast } from "sonner"
export function Navbar() {
const { t, lang, setLang } = useTranslation()
const { t, lang, setLanguage } = useTranslation()
const navigate = useNavigate()
const [showLogoutModal, setShowLogoutModal] = useState(false)
const [isDropdownOpen, setIsDropdownOpen] = useState(false)
@@ -23,6 +23,17 @@ export function Navbar() {
return document.documentElement.classList.contains('dark');
});
useEffect(() => {
const handleProfileUpdated = ((e: CustomEvent) => {
if (e.detail) {
setUser((prev: any) => prev ? { ...prev, ...e.detail } : e.detail);
}
}) as EventListener;
window.addEventListener('profile_updated', handleProfileUpdated);
return () => window.removeEventListener('profile_updated', handleProfileUpdated);
}, []);
useEffect(() => {
if (isDarkMode) {
document.documentElement.classList.add('dark');
@@ -83,8 +94,8 @@ export function Navbar() {
const toggleLanguage = () => {
const newLang = isFa ? 'en' : 'fa'
if (setLang) {
setLang(newLang)
if (setLanguage) {
setLanguage(newLang)
} else {
localStorage.setItem('language', newLang)
window.location.reload()
@@ -126,7 +137,14 @@ export function Navbar() {
</button>
{isDropdownOpen && (
<div className={`absolute ${isFa ? 'left-0' : 'right-0'} mt-2 w-56 rounded-lg bg-white dark:bg-slate-900 shadow-lg ring-1 ring-black ring-opacity-5 border border-slate-200 dark:border-slate-800 z-50 py-2 overflow-hidden`}>
<div dir='rtl' className={`absolute ${isFa ? 'left-0' : 'right-0'} mt-2 w-56 rounded-lg bg-white dark:bg-slate-900 shadow-lg ring-1 ring-black ring-opacity-5 border border-slate-200 dark:border-slate-800 z-50 py-2 overflow-hidden`}>
<div className="px-4 py-2 mb-2 border-b border-slate-100 dark:border-slate-800">
<p className="text-sm font-semibold text-slate-800 dark:text-slate-400 truncate">
{user.first_name || user.last_name
? `${user.first_name || ''} ${user.last_name || ''}`.trim()
: user.email}
</p>
</div>
<button
onClick={() => { navigate("/profile"); setIsDropdownOpen(false); }}
className="flex w-full items-center gap-3 px-4 py-2.5 text-sm text-slate-700 dark:text-slate-200 hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors"