fix layout
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import dynamic from 'next/dynamic'
|
||||
import ProtectedRoute from '@/components/ProtectedRoute'
|
||||
import { AuthProvider, useAuth } from '@/contexts/AuthContext'
|
||||
import { useAuth } from '@/contexts/AuthContext'
|
||||
import Link from 'next/link'
|
||||
import { usePathname } from 'next/navigation'
|
||||
import {
|
||||
@@ -17,8 +16,7 @@ import {
|
||||
Clock,
|
||||
Building2,
|
||||
LogOut,
|
||||
LayoutDashboard,
|
||||
Users2
|
||||
LayoutDashboard
|
||||
} from 'lucide-react'
|
||||
|
||||
function AdminLayoutContent({ children }: { children: React.ReactNode }) {
|
||||
@@ -29,7 +27,6 @@ function AdminLayoutContent({ children }: { children: React.ReactNode }) {
|
||||
{ icon: LayoutDashboard, label: 'لوحة التحكم', href: '/admin', exact: true },
|
||||
{ icon: Users, label: 'إدارة المستخدمين', href: '/admin/users' },
|
||||
{ icon: Shield, label: 'الأدوار والصلاحيات', href: '/admin/roles' },
|
||||
{ icon: Users2, label: 'مجموعات الصلاحيات', href: '/admin/permission-groups' },
|
||||
{ icon: Database, label: 'النسخ الاحتياطي', href: '/admin/backup' },
|
||||
{ icon: Settings, label: 'إعدادات النظام', href: '/admin/settings' },
|
||||
{ icon: FileText, label: 'سجل العمليات', href: '/admin/audit-logs' },
|
||||
@@ -40,7 +37,9 @@ function AdminLayoutContent({ children }: { children: React.ReactNode }) {
|
||||
]
|
||||
|
||||
const isActive = (href: string, exact?: boolean) => {
|
||||
if (exact) return pathname === href
|
||||
if (exact) {
|
||||
return pathname === href
|
||||
}
|
||||
return pathname.startsWith(href)
|
||||
}
|
||||
|
||||
@@ -58,7 +57,6 @@ function AdminLayoutContent({ children }: { children: React.ReactNode }) {
|
||||
<p className="text-xs text-gray-600">System Admin</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-red-50 border border-red-200 rounded-lg p-3">
|
||||
<p className="text-xs font-semibold text-red-900">{user?.username}</p>
|
||||
<p className="text-xs text-red-700">{user?.role?.name}</p>
|
||||
@@ -74,7 +72,9 @@ function AdminLayoutContent({ children }: { children: React.ReactNode }) {
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
className={`flex items-center gap-3 px-4 py-3 rounded-lg mb-2 transition-all ${
|
||||
active ? 'bg-red-600 text-white shadow-md' : 'text-gray-700 hover:bg-gray-100'
|
||||
active
|
||||
? 'bg-red-600 text-white shadow-md'
|
||||
: 'text-gray-700 hover:bg-gray-100'
|
||||
}`}
|
||||
>
|
||||
<Icon className="h-5 w-5" />
|
||||
@@ -104,30 +104,18 @@ function AdminLayoutContent({ children }: { children: React.ReactNode }) {
|
||||
</aside>
|
||||
|
||||
{/* Main Content */}
|
||||
<main className="mr-64 flex-1 p-8">{children}</main>
|
||||
<main className="mr-64 flex-1 p-8">
|
||||
{children}
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
const AdminLayoutClient = dynamic(
|
||||
() =>
|
||||
Promise.resolve(function AdminLayoutClient({
|
||||
children
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<AuthProvider>
|
||||
<ProtectedRoute>
|
||||
<AdminLayoutContent>{children}</AdminLayoutContent>
|
||||
</ProtectedRoute>
|
||||
</AuthProvider>
|
||||
)
|
||||
}),
|
||||
{ ssr: false }
|
||||
)
|
||||
|
||||
export default function AdminLayout({ children }: { children: React.ReactNode }) {
|
||||
return <AdminLayoutClient>{children}</AdminLayoutClient>
|
||||
return (
|
||||
<ProtectedRoute>
|
||||
<AdminLayoutContent>{children}</AdminLayoutContent>
|
||||
</ProtectedRoute>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,120 +1,69 @@
|
||||
'use client'
|
||||
import type { Metadata } from 'next'
|
||||
import { Cairo, Readex_Pro } from 'next/font/google'
|
||||
import './globals.css'
|
||||
import { Providers } from './providers'
|
||||
import { AuthProvider } from '@/contexts/AuthContext'
|
||||
import { LanguageProvider } from '@/contexts/LanguageContext'
|
||||
import { Toaster } from 'react-hot-toast'
|
||||
|
||||
import ProtectedRoute from '@/components/ProtectedRoute'
|
||||
import { useAuth } from '@/contexts/AuthContext'
|
||||
import Link from 'next/link'
|
||||
import { usePathname } from 'next/navigation'
|
||||
import {
|
||||
Users,
|
||||
Shield,
|
||||
Database,
|
||||
Settings,
|
||||
FileText,
|
||||
Activity,
|
||||
Mail,
|
||||
Key,
|
||||
Clock,
|
||||
Building2,
|
||||
LogOut,
|
||||
LayoutDashboard,
|
||||
Users2
|
||||
} from 'lucide-react'
|
||||
const cairo = Cairo({
|
||||
subsets: ['latin', 'arabic'],
|
||||
variable: '--font-cairo',
|
||||
display: 'swap',
|
||||
})
|
||||
|
||||
function AdminLayoutContent({ children }: { children: React.ReactNode }) {
|
||||
const { user, logout } = useAuth()
|
||||
const pathname = usePathname()
|
||||
const readexPro = Readex_Pro({
|
||||
subsets: ['latin', 'arabic'],
|
||||
variable: '--font-readex',
|
||||
display: 'swap',
|
||||
})
|
||||
|
||||
const menuItems = [
|
||||
{ icon: LayoutDashboard, label: 'لوحة التحكم', href: '/admin', exact: true },
|
||||
{ icon: Users, label: 'إدارة المستخدمين', href: '/admin/users' },
|
||||
{ icon: Shield, label: 'الأدوار والصلاحيات', href: '/admin/roles' },
|
||||
{ icon: Users2, label: 'مجموعات الصلاحيات', href: '/admin/permission-groups' },
|
||||
{ icon: Database, label: 'النسخ الاحتياطي', href: '/admin/backup' },
|
||||
{ icon: Settings, label: 'إعدادات النظام', href: '/admin/settings' },
|
||||
{ icon: FileText, label: 'سجل العمليات', href: '/admin/audit-logs' },
|
||||
{ icon: Activity, label: 'صحة النظام', href: '/admin/health' },
|
||||
{ icon: Mail, label: 'إعدادات البريد', href: '/admin/email' },
|
||||
{ icon: Key, label: 'مفاتيح API', href: '/admin/api-keys' },
|
||||
{ icon: Clock, label: 'المهام المجدولة', href: '/admin/scheduled-jobs' }
|
||||
]
|
||||
|
||||
const isActive = (href: string, exact?: boolean) => {
|
||||
if (exact) {
|
||||
return pathname === href
|
||||
}
|
||||
return pathname.startsWith(href)
|
||||
}
|
||||
export const metadata: Metadata = {
|
||||
title: 'Z.CRM - نظام إدارة علاقات العملاء',
|
||||
description: 'Enterprise CRM System for Contact Management, Sales, HR, Inventory, Projects, and Marketing',
|
||||
}
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 flex">
|
||||
<aside className="w-64 bg-white border-l shadow-lg fixed h-full overflow-y-auto">
|
||||
<div className="p-6 border-b">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<div className="bg-red-600 p-2 rounded-lg">
|
||||
<Shield className="h-6 w-6 text-white" />
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="text-lg font-bold text-gray-900">لوحة الإدارة</h2>
|
||||
<p className="text-xs text-gray-600">System Admin</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-red-50 border border-red-200 rounded-lg p-3">
|
||||
<p className="text-xs font-semibold text-red-900">{user?.username}</p>
|
||||
<p className="text-xs text-red-700">{user?.role?.name}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav className="p-4">
|
||||
{menuItems.map((item) => {
|
||||
const Icon = item.icon
|
||||
const active = isActive(item.href, item.exact)
|
||||
return (
|
||||
<Link
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
className={`flex items-center gap-3 px-4 py-3 rounded-lg mb-2 transition-all ${
|
||||
active
|
||||
? 'bg-red-600 text-white shadow-md'
|
||||
: 'text-gray-700 hover:bg-gray-100'
|
||||
}`}
|
||||
>
|
||||
<Icon className="h-5 w-5" />
|
||||
<span className="font-medium">{item.label}</span>
|
||||
</Link>
|
||||
)
|
||||
})}
|
||||
|
||||
<hr className="my-4 border-gray-200" />
|
||||
|
||||
<Link
|
||||
href="/dashboard"
|
||||
className="flex items-center gap-3 px-4 py-3 rounded-lg mb-2 text-gray-700 hover:bg-gray-100 transition-all"
|
||||
>
|
||||
<Building2 className="h-5 w-5" />
|
||||
<span className="font-medium">العودة للنظام</span>
|
||||
</Link>
|
||||
|
||||
<button
|
||||
onClick={logout}
|
||||
className="w-full flex items-center gap-3 px-4 py-3 rounded-lg text-red-600 hover:bg-red-50 transition-all"
|
||||
>
|
||||
<LogOut className="h-5 w-5" />
|
||||
<span className="font-medium">تسجيل الخروج</span>
|
||||
</button>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
<main className="mr-64 flex-1 p-8">
|
||||
{children}
|
||||
</main>
|
||||
</div>
|
||||
<html lang="en">
|
||||
<body className={`${readexPro.variable} ${cairo.variable} font-readex`}>
|
||||
<LanguageProvider>
|
||||
<AuthProvider>
|
||||
<Providers>{children}</Providers>
|
||||
<Toaster
|
||||
position="top-center"
|
||||
reverseOrder={false}
|
||||
toastOptions={{
|
||||
duration: 4000,
|
||||
style: {
|
||||
background: '#fff',
|
||||
color: '#363636',
|
||||
fontFamily: 'var(--font-readex)',
|
||||
},
|
||||
success: {
|
||||
duration: 3000,
|
||||
iconTheme: {
|
||||
primary: '#10B981',
|
||||
secondary: '#fff',
|
||||
},
|
||||
},
|
||||
error: {
|
||||
duration: 5000,
|
||||
iconTheme: {
|
||||
primary: '#EF4444',
|
||||
secondary: '#fff',
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</AuthProvider>
|
||||
</LanguageProvider>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
|
||||
export default function AdminLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<ProtectedRoute>
|
||||
<AdminLayoutContent>{children}</AdminLayoutContent>
|
||||
</ProtectedRoute>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user