Files
n3wt-school/Front-End/src/app/[locale]/admin/layout.js
2025-05-01 12:19:07 +02:00

221 lines
6.2 KiB
JavaScript

'use client';
import React, { useState, useEffect } from 'react';
import Sidebar from '@/components/Sidebar';
import { usePathname } from 'next/navigation';
import { useTranslations } from 'next-intl';
import Image from 'next/image';
import {
LayoutDashboard,
FileText,
School,
Users,
Award,
Calendar,
Settings,
LogOut,
Menu,
X,
} from 'lucide-react';
import DropdownMenu from '@/components/DropdownMenu';
import Popup from '@/components/Popup';
import {
FE_ADMIN_HOME_URL,
FE_ADMIN_SUBSCRIPTIONS_URL,
FE_ADMIN_STRUCTURE_URL,
FE_ADMIN_DIRECTORY_URL,
FE_ADMIN_GRADES_URL,
FE_ADMIN_PLANNING_URL,
FE_ADMIN_SETTINGS_URL,
} from '@/utils/Url';
import { disconnect } from '@/app/actions/authAction';
import ProtectedRoute from '@/components/ProtectedRoute';
import { getGravatarUrl } from '@/utils/gravatar';
import Footer from '@/components/Footer';
import { getRightStr, RIGHTS } from '@/utils/rights';
import logger from '@/utils/logger';
import { useEstablishment } from '@/context/EstablishmentContext';
export default function Layout({ children }) {
const t = useTranslations('sidebar');
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
const { profileRole, establishments, user, clearContext } =
useEstablishment();
// Déplacer le reste du code ici...
const sidebarItems = {
admin: {
id: 'admin',
name: t('dashboard'),
url: FE_ADMIN_HOME_URL,
icon: LayoutDashboard,
},
subscriptions: {
id: 'subscriptions',
name: t('subscriptions'),
url: FE_ADMIN_SUBSCRIPTIONS_URL,
icon: FileText,
},
structure: {
id: 'structure',
name: t('structure'),
url: FE_ADMIN_STRUCTURE_URL,
icon: School,
},
directory: {
id: 'directory',
name: t('directory'),
url: FE_ADMIN_DIRECTORY_URL,
icon: Users,
},
grades: {
id: 'grades',
name: t('grades'),
url: FE_ADMIN_GRADES_URL,
icon: Award,
},
planning: {
id: 'planning',
name: t('events'),
url: FE_ADMIN_PLANNING_URL,
icon: Calendar,
},
settings: {
id: 'settings',
name: t('settings'),
url: FE_ADMIN_SETTINGS_URL,
icon: Settings,
},
};
const [isPopupVisible, setIsPopupVisible] = useState(false);
const pathname = usePathname();
const currentPage = pathname.split('/').pop();
const headerTitle = sidebarItems[currentPage]?.name || t('dashboard');
const softwareName = 'N3WT School';
const softwareVersion = `${process.env.NEXT_PUBLIC_APP_VERSION}`;
const handleDisconnect = () => {
setIsPopupVisible(true);
};
const confirmDisconnect = () => {
setIsPopupVisible(false);
disconnect();
clearContext();
};
const dropdownItems = [
{
type: 'info',
content: (
<div className="px-4 py-2">
<div className="font-medium">{user?.email || 'Utilisateur'}</div>
<div className="text-xs text-gray-400">
{getRightStr(profileRole) || ''}
</div>
</div>
),
},
{
type: 'separator',
content: <hr className="my-2 border-gray-200" />,
},
{
type: 'item',
label: 'Déconnexion',
onClick: handleDisconnect,
icon: LogOut,
},
];
const toggleSidebar = () => {
setIsSidebarOpen(!isSidebarOpen);
};
useEffect(() => {
// Fermer la sidebar quand on change de page sur mobile
setIsSidebarOpen(false);
}, [pathname]);
return (
<ProtectedRoute requiredRight={[RIGHTS.ADMIN, RIGHTS.TEACHER]}>
<div className="flex min-h-screen bg-gray-50 relative">
{/* Retirer la condition !isLoading car on gère déjà le chargement au début */}
{/* Sidebar avec hauteur forcée */}
<div
className={`md:block ${isSidebarOpen ? 'block' : 'hidden'} fixed md:relative inset-y-0 left-0 z-30 h-full`}
style={{ height: '100vh' }} // Force la hauteur à 100% de la hauteur de la vue
>
<Sidebar
establishments={establishments}
currentPage={currentPage}
items={Object.values(sidebarItems)}
onCloseMobile={toggleSidebar}
/>
</div>
{/* Overlay pour fermer la sidebar en cliquant à l'extérieur sur mobile */}
{isSidebarOpen && (
<div
className="fixed inset-0 bg-black bg-opacity-50 z-20 md:hidden"
onClick={toggleSidebar}
/>
)}
<div className="flex-1 flex flex-col">
{/* Header responsive */}
<header className="h-16 bg-white border-b border-gray-200 px-4 md:px-8 py-4 flex items-center justify-between z-10">
<div className="flex items-center">
<button
className="mr-4 md:hidden text-gray-600 hover:text-gray-900"
onClick={toggleSidebar}
aria-label="Toggle menu"
>
{isSidebarOpen ? <X size={24} /> : <Menu size={24} />}
</button>
<div className="text-lg md:text-xl font-semibold">
{headerTitle}
</div>
</div>
<DropdownMenu
buttonContent={
<Image
src={getGravatarUrl(user?.email)}
alt="Profile"
className="w-8 h-8 rounded-full cursor-pointer"
width={32}
height={32}
/>
}
items={dropdownItems}
buttonClassName=""
menuClassName="absolute right-0 mt-2 w-64 bg-white border border-gray-200 rounded shadow-lg"
/>
</header>
{/* Main Content */}
<div className="flex-1 flex flex-col">
{/* Content avec scroll si nécessaire */}
<div className="flex-1 overflow-auto p-4 md:p-6">{children}</div>
{/* Footer responsive */}
<Footer
softwareName={softwareName}
softwareVersion={softwareVersion}
/>
</div>
</div>
</div>
<Popup
visible={isPopupVisible}
message="Êtes-vous sûr(e) de vouloir vous déconnecter ?"
onConfirm={confirmDisconnect}
onCancel={() => setIsPopupVisible(false)}
/>
</ProtectedRoute>
);
}