fix layout

This commit is contained in:
yotakii
2026-03-02 14:35:36 +03:00
parent cdb69af654
commit 03ec18c5e6
2 changed files with 79 additions and 142 deletions

View File

@@ -1,8 +1,7 @@
'use client' 'use client'
import dynamic from 'next/dynamic'
import ProtectedRoute from '@/components/ProtectedRoute' import ProtectedRoute from '@/components/ProtectedRoute'
import { AuthProvider, useAuth } from '@/contexts/AuthContext' import { useAuth } from '@/contexts/AuthContext'
import Link from 'next/link' import Link from 'next/link'
import { usePathname } from 'next/navigation' import { usePathname } from 'next/navigation'
import { import {
@@ -17,8 +16,7 @@ import {
Clock, Clock,
Building2, Building2,
LogOut, LogOut,
LayoutDashboard, LayoutDashboard
Users2
} from 'lucide-react' } from 'lucide-react'
function AdminLayoutContent({ children }: { children: React.ReactNode }) { function AdminLayoutContent({ children }: { children: React.ReactNode }) {
@@ -29,7 +27,6 @@ function AdminLayoutContent({ children }: { children: React.ReactNode }) {
{ icon: LayoutDashboard, label: 'لوحة التحكم', href: '/admin', exact: true }, { icon: LayoutDashboard, label: 'لوحة التحكم', href: '/admin', exact: true },
{ icon: Users, label: 'إدارة المستخدمين', href: '/admin/users' }, { icon: Users, label: 'إدارة المستخدمين', href: '/admin/users' },
{ icon: Shield, label: 'الأدوار والصلاحيات', href: '/admin/roles' }, { icon: Shield, label: 'الأدوار والصلاحيات', href: '/admin/roles' },
{ icon: Users2, label: 'مجموعات الصلاحيات', href: '/admin/permission-groups' },
{ icon: Database, label: 'النسخ الاحتياطي', href: '/admin/backup' }, { icon: Database, label: 'النسخ الاحتياطي', href: '/admin/backup' },
{ icon: Settings, label: 'إعدادات النظام', href: '/admin/settings' }, { icon: Settings, label: 'إعدادات النظام', href: '/admin/settings' },
{ icon: FileText, label: 'سجل العمليات', href: '/admin/audit-logs' }, { icon: FileText, label: 'سجل العمليات', href: '/admin/audit-logs' },
@@ -40,7 +37,9 @@ function AdminLayoutContent({ children }: { children: React.ReactNode }) {
] ]
const isActive = (href: string, exact?: boolean) => { const isActive = (href: string, exact?: boolean) => {
if (exact) return pathname === href if (exact) {
return pathname === href
}
return pathname.startsWith(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> <p className="text-xs text-gray-600">System Admin</p>
</div> </div>
</div> </div>
<div className="bg-red-50 border border-red-200 rounded-lg p-3"> <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 font-semibold text-red-900">{user?.username}</p>
<p className="text-xs text-red-700">{user?.role?.name}</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} key={item.href}
href={item.href} href={item.href}
className={`flex items-center gap-3 px-4 py-3 rounded-lg mb-2 transition-all ${ 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" /> <Icon className="h-5 w-5" />
@@ -104,30 +104,18 @@ function AdminLayoutContent({ children }: { children: React.ReactNode }) {
</aside> </aside>
{/* Main Content */} {/* Main Content */}
<main className="mr-64 flex-1 p-8">{children}</main> <main className="mr-64 flex-1 p-8">
{children}
</main>
</div> </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 }) { export default function AdminLayout({ children }: { children: React.ReactNode }) {
return <AdminLayoutClient>{children}</AdminLayoutClient> return (
<ProtectedRoute>
<AdminLayoutContent>{children}</AdminLayoutContent>
</ProtectedRoute>
)
} }

View File

@@ -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' const cairo = Cairo({
import { useAuth } from '@/contexts/AuthContext' subsets: ['latin', 'arabic'],
import Link from 'next/link' variable: '--font-cairo',
import { usePathname } from 'next/navigation' display: 'swap',
import { })
Users,
Shield,
Database,
Settings,
FileText,
Activity,
Mail,
Key,
Clock,
Building2,
LogOut,
LayoutDashboard,
Users2
} from 'lucide-react'
function AdminLayoutContent({ children }: { children: React.ReactNode }) { const readexPro = Readex_Pro({
const { user, logout } = useAuth() subsets: ['latin', 'arabic'],
const pathname = usePathname() variable: '--font-readex',
display: 'swap',
})
const menuItems = [ export const metadata: Metadata = {
{ icon: LayoutDashboard, label: 'لوحة التحكم', href: '/admin', exact: true }, title: 'Z.CRM - نظام إدارة علاقات العملاء',
{ icon: Users, label: 'إدارة المستخدمين', href: '/admin/users' }, description: 'Enterprise CRM System for Contact Management, Sales, HR, Inventory, Projects, and Marketing',
{ 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 default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return ( return (
<div className="min-h-screen bg-gray-50 flex"> <html lang="en">
<aside className="w-64 bg-white border-l shadow-lg fixed h-full overflow-y-auto"> <body className={`${readexPro.variable} ${cairo.variable} font-readex`}>
<div className="p-6 border-b"> <LanguageProvider>
<div className="flex items-center gap-3 mb-4"> <AuthProvider>
<div className="bg-red-600 p-2 rounded-lg"> <Providers>{children}</Providers>
<Shield className="h-6 w-6 text-white" /> <Toaster
</div> position="top-center"
<div> reverseOrder={false}
<h2 className="text-lg font-bold text-gray-900">لوحة الإدارة</h2> toastOptions={{
<p className="text-xs text-gray-600">System Admin</p> duration: 4000,
</div> style: {
</div> background: '#fff',
<div className="bg-red-50 border border-red-200 rounded-lg p-3"> color: '#363636',
<p className="text-xs font-semibold text-red-900">{user?.username}</p> fontFamily: 'var(--font-readex)',
<p className="text-xs text-red-700">{user?.role?.name}</p> },
</div> success: {
</div> duration: 3000,
iconTheme: {
<nav className="p-4"> primary: '#10B981',
{menuItems.map((item) => { secondary: '#fff',
const Icon = item.icon },
const active = isActive(item.href, item.exact) },
return ( error: {
<Link duration: 5000,
key={item.href} iconTheme: {
href={item.href} primary: '#EF4444',
className={`flex items-center gap-3 px-4 py-3 rounded-lg mb-2 transition-all ${ secondary: '#fff',
active },
? 'bg-red-600 text-white shadow-md' },
: 'text-gray-700 hover:bg-gray-100' }}
}`} />
> </AuthProvider>
<Icon className="h-5 w-5" /> </LanguageProvider>
<span className="font-medium">{item.label}</span> </body>
</Link> </html>
)
})}
<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>
) )
} }
export default function AdminLayout({ children }: { children: React.ReactNode }) {
return (
<ProtectedRoute>
<AdminLayoutContent>{children}</AdminLayoutContent>
</ProtectedRoute>
)
}