refactor: adaptation mobile

This commit is contained in:
Luc SORIGNET
2025-03-01 14:54:25 +01:00
parent d62be6b309
commit 4b8f85e68d
6 changed files with 237 additions and 89 deletions

View File

@ -12,10 +12,12 @@ import {
Calendar,
Settings,
FileText,
LogOut
LogOut,
Menu,
X
} from 'lucide-react';
import DropdownMenu from '@/components/DropdownMenu';
import Logo from '@/components/Logo';
import Popup from '@/components/Popup';
import {
FE_ADMIN_HOME_URL,
@ -31,11 +33,13 @@ import { useSession } from 'next-auth/react';
import { fetchEstablishment } from '@/app/actions/schoolAction';
import ProtectedRoute from '@/components/ProtectedRoute';
import { getGravatarUrl } from '@/utils/gravatar';
import Footer from '@/components/Footer';
export default function Layout({
children,
}) {
const t = useTranslations('sidebar');
const t = useTranslations('sidebar');
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
const sidebarItems = {
"admin": { "id": "admin", "name": t('dashboard'), "url": FE_ADMIN_HOME_URL, "icon": Home },
@ -50,7 +54,7 @@ export default function Layout({
const [isLoading, setIsLoading] = useState(false);
const [isPopupVisible, setIsPopupVisible] = useState(false);
const [user, setUser] = useState(null);
const { data: session } = useSession();
const { data: session } = useSession();
const pathname = usePathname();
const currentPage = pathname.split('/').pop();
@ -58,7 +62,7 @@ export default function Layout({
const headerTitle = sidebarItems[currentPage]?.name || t('dashboard');
const softwareName = "N3WT School";
const softwareVersion = `v${process.env.NEXT_PUBLIC_APP_VERSION}`;
const softwareVersion = `${process.env.NEXT_PUBLIC_APP_VERSION}`;
const handleDisconnect = () => {
setIsPopupVisible(true);
@ -77,6 +81,15 @@ export default function Layout({
},
];
const toggleSidebar = () => {
setIsSidebarOpen(!isSidebarOpen);
};
useEffect(() => {
// Fermer la sidebar quand on change de page sur mobile
setIsSidebarOpen(false);
}, [pathname]);
useEffect(() => {
setIsLoading(true);
fetchEstablishment()
@ -85,7 +98,7 @@ export default function Layout({
})
.catch(error => console.error('Error fetching establishment : ', error))
.finally(() => setIsLoading(false));
}, []);
}, []);
useEffect(() => {
const fetchUser = async () => {
@ -99,54 +112,79 @@ export default function Layout({
}, [session]);
return (
<ProtectedRoute>
{!isLoading && (
<div className="flex min-h-screen bg-gray-50">
<Sidebar establishment={establishment} currentPage={currentPage} items={Object.values(sidebarItems)} className="h-full" />
<div className="flex flex-col flex-1">
{/* Header - h-16 = 64px */}
<header className="h-16 bg-white border-b border-gray-200 px-8 py-4 flex items-center justify-between z-9">
<div className="text-xl font-semibold">{headerTitle}</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-48 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">
{children}
</div>
{/* Footer - h-16 = 64px */}
<footer className="h-16 bg-white border-t border-gray-200 px-8 py-4 flex items-center justify-between">
<div className="text-sm font-light">
<span>&copy; {new Date().getFullYear()} N3WT-INNOV Tous droits réservés.</span>
<div className="text-sm font-light">{softwareName} - {softwareVersion}</div>
</div>
<Logo className="w-8 h-8" />
</footer>
<ProtectedRoute>
{!isLoading && (
<div className="flex min-h-screen bg-gray-50 relative">
{/* 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
establishment={establishment}
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-48 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>
)}
<Popup
visible={isPopupVisible}
message="Êtes-vous sûr(e) de vouloir vous déconnecter ?"
onConfirm={confirmDisconnect}
onCancel={() => setIsPopupVisible(false)}
/>
</ProtectedRoute>
</div>
)}
<Popup
visible={isPopupVisible}
message="Êtes-vous sûr(e) de vouloir vous déconnecter ?"
onConfirm={confirmDisconnect}
onCancel={() => setIsPopupVisible(false)}
/>
</ProtectedRoute>
);
}