feat(web): add React Query, dark mode toggle, and error retry UX
- Install @tanstack/react-query with exponential backoff retry config - Create QueryClientProvider and custom hooks for listings, analytics, payments, and subscription API calls - Migrate 5 dashboard pages from useState/useEffect to React Query hooks - Add dark mode CSS variables and ThemeProvider with localStorage persistence - Add theme toggle button in dashboard header (sun/moon icon) - Enhance error boundaries with auto-retry, retry count, and loading state Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
import Link from 'next/link';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useTheme } from '@/components/providers/theme-provider';
|
||||
import { useAuthStore } from '@/lib/auth-store';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
@@ -19,6 +20,7 @@ const navItems = [
|
||||
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
|
||||
const pathname = usePathname();
|
||||
const { user, logout } = useAuthStore();
|
||||
const { theme, toggleTheme } = useTheme();
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
@@ -53,6 +55,23 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
|
||||
{user.fullName}
|
||||
</span>
|
||||
)}
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={toggleTheme}
|
||||
aria-label={theme === 'light' ? 'Chuyển sang chế độ tối' : 'Chuyển sang chế độ sáng'}
|
||||
className="h-9 w-9 p-0"
|
||||
>
|
||||
{theme === 'light' ? (
|
||||
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
|
||||
</svg>
|
||||
) : (
|
||||
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
|
||||
</svg>
|
||||
)}
|
||||
</Button>
|
||||
<Button variant="ghost" size="sm" onClick={() => logout()}>
|
||||
Đăng xuất
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user