mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-29 07:53:23 +00:00
refactor: adaptation mobile
This commit is contained in:
@ -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>© {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>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user