Files
n3wt-school/Front-End/src/app/[locale]/admin/layout.js
Luc SORIGNET 4248a589c5 feat(frontend): refonte mobile planning et ameliorations suivi pedagogique [#NEWTS-4]
Fonction PWA et ajout du responsive design

Planning mobile :
- Nouvelle vue DayView avec bandeau semaine scrollable, date picker natif et navigation integree
- ScheduleNavigation converti en drawer overlay sur mobile, sidebar fixe sur desktop
- Suppression double barre navigation mobile, controles deplaces dans DayView
- Date picker natif via label+input sur mobile

Suivi pedagogique :
- Refactorisation page grades avec composant Table partage
- Colonnes stats par periode, absences, actions (Fiche + Evaluer)
- Lien cliquable sur la classe vers SchoolClassManagement

feat(backend): ajout associated_class_id dans StudentByRFCreationSerializer [#NEWTS-4]

UI global :
- Remplacement fleches texte par icones Lucide ChevronDown/ChevronRight
- Pagination conditionnelle sur tous les tableaux plats
- Layout responsive mobile : cartes separees fond transparent
- Table.js : pagination optionnelle, wrapper md uniquement
2026-03-16 12:27:06 +01:00

169 lines
4.4 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 {
LayoutDashboard,
FileText,
School,
Users,
Award,
Calendar,
Settings,
MessageSquare,
} from 'lucide-react';
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,
FE_ADMIN_MESSAGERIE_URL,
} from '@/utils/Url';
import { disconnect } from '@/app/actions/authAction';
import ProtectedRoute from '@/components/ProtectedRoute';
import Footer from '@/components/Footer';
import MobileTopbar from '@/components/MobileTopbar';
import { RIGHTS } from '@/utils/rights';
import { useEstablishment } from '@/context/EstablishmentContext';
export default function Layout({ children }) {
const t = useTranslations('sidebar');
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
const { profileRole, establishments, clearContext } =
useEstablishment();
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('educational_monitoring'),
url: FE_ADMIN_GRADES_URL,
icon: Award,
},
planning: {
id: 'planning',
name: t('events'),
url: FE_ADMIN_PLANNING_URL,
icon: Calendar,
},
messagerie: {
id: 'messagerie',
name: t('messagerie'),
url: FE_ADMIN_MESSAGERIE_URL,
icon: MessageSquare,
},
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 softwareName = 'N3WT School';
const softwareVersion = `${process.env.NEXT_PUBLIC_APP_VERSION}`;
const confirmDisconnect = () => {
setIsPopupVisible(false);
disconnect();
clearContext();
};
const toggleSidebar = () => {
setIsSidebarOpen(!isSidebarOpen);
};
useEffect(() => {
// Fermer la sidebar quand on change de page sur mobile
setIsSidebarOpen(false);
}, [pathname]);
// Filtrage dynamique des items de la sidebar selon le rôle
let sidebarItemsToDisplay = Object.values(sidebarItems);
if (profileRole === 0) {
// Si pas admin, on retire "directory" et "settings"
sidebarItemsToDisplay = sidebarItemsToDisplay.filter(
(item) => item.id !== 'directory' && item.id !== 'settings'
);
}
return (
<ProtectedRoute requiredRight={[RIGHTS.ADMIN, RIGHTS.TEACHER]}>
{/* Topbar mobile (hamburger + logo) */}
<MobileTopbar onMenuClick={toggleSidebar} />
{/* Sidebar */}
<div
className={`absolute top-14 md:top-0 bottom-0 left-0 z-30 w-64 bg-white border-r border-gray-200 box-border ${
isSidebarOpen ? 'block' : 'hidden md:block'
}`}
>
<Sidebar
establishments={establishments}
currentPage={currentPage}
items={sidebarItemsToDisplay}
onCloseMobile={toggleSidebar}
/>
</div>
{/* Overlay for mobile */}
{isSidebarOpen && (
<div
className="fixed inset-0 bg-black bg-opacity-50 z-20 md:hidden"
onClick={toggleSidebar}
/>
)}
{/* Main container */}
<div className="absolute overflow-auto bg-gradient-to-br from-emerald-50 via-sky-50 to-emerald-100 top-14 md:top-0 bottom-16 left-0 md:left-64 right-0">
{children}
</div>
{/* Footer */}
<Footer softwareName={softwareName} softwareVersion={softwareVersion} />
<Popup
isOpen={isPopupVisible}
message="Êtes-vous sûr(e) de vouloir vous déconnecter ?"
onConfirm={confirmDisconnect}
onCancel={() => setIsPopupVisible(false)}
/>
</ProtectedRoute>
);
}