mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-29 16:03:21 +00:00
feat: Gestion multi-profil multi-école
This commit is contained in:
@ -3,7 +3,7 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import Sidebar from '@/components/Sidebar';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import {useTranslations} from 'next-intl';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import Image from 'next/image';
|
||||
import {
|
||||
Users,
|
||||
@ -35,6 +35,9 @@ import ProtectedRoute from '@/components/ProtectedRoute';
|
||||
import { getGravatarUrl } from '@/utils/gravatar';
|
||||
import Footer from '@/components/Footer';
|
||||
import { getRightStr, RIGHTS } from '@/utils/rights';
|
||||
import { getSession } from 'next-auth/react';
|
||||
import logger from '@/utils/logger';
|
||||
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||
|
||||
export default function Layout({
|
||||
children,
|
||||
@ -51,11 +54,12 @@ export default function Layout({
|
||||
"settings": { "id": "settings", "name": t('settings'), "url": FE_ADMIN_SETTINGS_URL, "icon": Settings }
|
||||
};
|
||||
|
||||
const [establishment, setEstablishment] = useState(null);
|
||||
const [establishments, setEstablishments] = useState([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [isPopupVisible, setIsPopupVisible] = useState(false);
|
||||
const [user, setUser] = useState(null);
|
||||
const { data: session } = useSession();
|
||||
const { selectedEstablishmentId, setSelectedEstablishmentId, profileRole, setProfileRole } = useEstablishment();
|
||||
|
||||
const pathname = usePathname();
|
||||
const currentPage = pathname.split('/').pop();
|
||||
@ -80,7 +84,7 @@ export default function Layout({
|
||||
content: (
|
||||
<div className="px-4 py-2">
|
||||
<div className="font-medium">{user?.email || 'Utilisateur'}</div>
|
||||
<div className="text-xs text-gray-400">{getRightStr(user?.role) || ''}</div>
|
||||
<div className="text-xs text-gray-400">{getRightStr(profileRole) || ''}</div>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
@ -106,17 +110,34 @@ export default function Layout({
|
||||
}, [pathname]);
|
||||
|
||||
useEffect(() => {
|
||||
setIsLoading(true);
|
||||
fetchEstablishment()
|
||||
.then(data => {
|
||||
setEstablishment(data);
|
||||
getSession()
|
||||
.then(session => {
|
||||
if (session && session.user) {
|
||||
setUser(session.user);
|
||||
setEstablishments(session.user.roles.map(role => ({
|
||||
id: role.establishment__id,
|
||||
name: role.establishment__name,
|
||||
role_type: role.role_type
|
||||
})));
|
||||
// Sélectionner l'établissement depuis le localStorage ou le premier établissement par défaut
|
||||
const storedEstablishmentId = localStorage.getItem('selectedEstablishmentId');
|
||||
if (storedEstablishmentId) {
|
||||
setSelectedEstablishmentId(storedEstablishmentId);
|
||||
const storedProfileRole = session.user.roles.find(role => role.establishment__id === parseInt(storedEstablishmentId))?.role_type;
|
||||
setProfileRole(storedProfileRole);
|
||||
} else if (session.user.roles.length > 0) {
|
||||
setSelectedEstablishmentId(session.user.roles[0].establishment__id);
|
||||
setProfileRole(session.user.roles[0].role_type);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => console.error('Error fetching establishment : ', error))
|
||||
.finally(() => setIsLoading(false));
|
||||
.catch(err => {
|
||||
logger.error('Error fetching session:', err);
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchUser = async () => {
|
||||
const fetchUser = async () => {
|
||||
if (session) { // Vérifier que la session existe
|
||||
const userData = await getUser();
|
||||
setUser(userData);
|
||||
@ -126,8 +147,6 @@ export default function Layout({
|
||||
fetchUser();
|
||||
}, [session]);
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<ProtectedRoute requiredRight={RIGHTS.ADMIN}>
|
||||
{!isLoading && (
|
||||
@ -138,12 +157,16 @@ export default function Layout({
|
||||
style={{ height: '100vh' }} // Force la hauteur à 100% de la hauteur de la vue
|
||||
>
|
||||
<Sidebar
|
||||
establishment={establishment}
|
||||
establishments={establishments}
|
||||
currentPage={currentPage}
|
||||
items={Object.values(sidebarItems)}
|
||||
|
||||
onCloseMobile={toggleSidebar}
|
||||
|
||||
onEstablishmentChange={(establishmentId) => {
|
||||
const parsedEstablishmentId = parseInt(establishmentId, 10);
|
||||
setSelectedEstablishmentId(parsedEstablishmentId);
|
||||
const role = session.user.roles.find(role => role.establishment__id === parsedEstablishmentId)?.role_type;
|
||||
setProfileRole(role);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@ -39,47 +39,61 @@ export default function DashboardPage() {
|
||||
|
||||
|
||||
const [classes, setClasses] = useState([]);
|
||||
|
||||
const [establishmentId, setEstablishmentId] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
// Fetch data for classes
|
||||
fetchClasses().then(data => {
|
||||
setClasses(data);
|
||||
logger.info('Classes fetched:', data);
|
||||
const nbMaxStudents = data.reduce((acc, classe) => acc + classe.number_of_students, 0);
|
||||
const nbStudents = data.reduce((acc, classe) => acc + classe.students.length, 0);
|
||||
setStructureCapacity(nbMaxStudents);
|
||||
setTotalStudents(nbStudents);
|
||||
|
||||
getSession()
|
||||
.then(session => {
|
||||
if (session && session.user) {
|
||||
setEstablishmentId(session.user.establishment);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
logger.error('Error fetching classes:', error);
|
||||
.catch(err => {
|
||||
logger.error('Error fetching session:', err);
|
||||
});
|
||||
}, []);
|
||||
|
||||
fetchRegisterForms().then(data => {
|
||||
logger.info('Pending registrations fetched:', data);
|
||||
setPendingRegistration(data.count);
|
||||
})
|
||||
.catch(error => {
|
||||
logger.error('Error fetching pending registrations:', error);
|
||||
});
|
||||
useEffect(() => {
|
||||
if (establishmentId) {
|
||||
// Fetch data for classes
|
||||
fetchClasses(establishmentId).then(data => {
|
||||
setClasses(data);
|
||||
logger.info('Classes fetched:', data);
|
||||
const nbMaxStudents = data.reduce((acc, classe) => acc + classe.number_of_students, 0);
|
||||
const nbStudents = data.reduce((acc, classe) => acc + classe.students.length, 0);
|
||||
setStructureCapacity(nbMaxStudents);
|
||||
setTotalStudents(nbStudents);
|
||||
|
||||
fetchUpcomingEvents().then(data => {
|
||||
setUpcomingEvents(data);
|
||||
}).catch(error => {
|
||||
logger.error('Error fetching upcoming events:', error);
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
logger.error('Error fetching classes:', error);
|
||||
});
|
||||
|
||||
// Simulation de chargement des données
|
||||
setTimeout(() => {
|
||||
setMonthlyStats({
|
||||
inscriptions: [150, 180, 210, 245],
|
||||
completionRate: 78
|
||||
});
|
||||
setIsLoading(false);
|
||||
}, 1000);
|
||||
}
|
||||
, []);
|
||||
fetchRegisterForms().then(data => {
|
||||
logger.info('Pending registrations fetched:', data);
|
||||
setPendingRegistration(data.count);
|
||||
})
|
||||
.catch(error => {
|
||||
logger.error('Error fetching pending registrations:', error);
|
||||
});
|
||||
|
||||
fetchUpcomingEvents().then(data => {
|
||||
setUpcomingEvents(data);
|
||||
}).catch(error => {
|
||||
logger.error('Error fetching upcoming events:', error);
|
||||
});
|
||||
|
||||
// Simulation de chargement des données
|
||||
setTimeout(() => {
|
||||
setMonthlyStats({
|
||||
inscriptions: [150, 180, 210, 245],
|
||||
completionRate: 78
|
||||
});
|
||||
setIsLoading(false);
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
, [establishmentId]);
|
||||
|
||||
|
||||
if (isLoading) return <Loader />;
|
||||
|
||||
@ -27,13 +27,13 @@ import {
|
||||
fetchRegistrationTemplateMaster
|
||||
} from "@/app/actions/registerFileGroupAction";
|
||||
import logger from '@/utils/logger';
|
||||
|
||||
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||
|
||||
export default function Page() {
|
||||
const [specialities, setSpecialities] = useState([]);
|
||||
const [classes, setClasses] = useState([]);
|
||||
const [teachers, setTeachers] = useState([]);
|
||||
const [schedules, setSchedules] = useState([]); // Add this line
|
||||
const [schedules, setSchedules] = useState([]);
|
||||
const [registrationDiscounts, setRegistrationDiscounts] = useState([]);
|
||||
const [tuitionDiscounts, setTuitionDiscounts] = useState([]);
|
||||
const [registrationFees, setRegistrationFees] = useState([]);
|
||||
@ -45,54 +45,57 @@ export default function Page() {
|
||||
const [tuitionPaymentModes, setTuitionPaymentModes] = useState([]);
|
||||
|
||||
const csrfToken = useCsrfToken();
|
||||
const { selectedEstablishmentId } = useEstablishment();
|
||||
|
||||
useEffect(() => {
|
||||
// Fetch data for specialities
|
||||
handleSpecialities();
|
||||
if (selectedEstablishmentId) {
|
||||
// Fetch data for specialities
|
||||
handleSpecialities();
|
||||
|
||||
// Fetch data for teachers
|
||||
handleTeachers();
|
||||
// Fetch data for teachers
|
||||
handleTeachers();
|
||||
|
||||
// Fetch data for classes
|
||||
handleClasses();
|
||||
// Fetch data for classes
|
||||
handleClasses();
|
||||
|
||||
// Fetch data for schedules
|
||||
handleSchedules();
|
||||
// Fetch data for schedules
|
||||
handleSchedules();
|
||||
|
||||
// Fetch data for registration discounts
|
||||
handleRegistrationDiscounts();
|
||||
// Fetch data for registration discounts
|
||||
handleRegistrationDiscounts();
|
||||
|
||||
// Fetch data for tuition discounts
|
||||
handleTuitionDiscounts();
|
||||
// Fetch data for tuition discounts
|
||||
handleTuitionDiscounts();
|
||||
|
||||
// Fetch data for registration fees
|
||||
handleRegistrationFees();
|
||||
// Fetch data for registration fees
|
||||
handleRegistrationFees();
|
||||
|
||||
// Fetch data for tuition fees
|
||||
handleTuitionFees();
|
||||
// Fetch data for tuition fees
|
||||
handleTuitionFees();
|
||||
|
||||
// Fetch data for registration file templates
|
||||
fetchRegistrationTemplateMaster()
|
||||
.then((data)=> {
|
||||
setFichiers(data)
|
||||
})
|
||||
.catch(error => logger.error('Error fetching files:', error));
|
||||
// Fetch data for registration file templates
|
||||
fetchRegistrationTemplateMaster()
|
||||
.then((data)=> {
|
||||
setFichiers(data)
|
||||
})
|
||||
.catch(error => logger.error('Error fetching files:', error));
|
||||
|
||||
// Fetch data for registration payment plans
|
||||
handleRegistrationPaymentPlans();
|
||||
// Fetch data for registration payment plans
|
||||
handleRegistrationPaymentPlans();
|
||||
|
||||
// Fetch data for tuition payment plans
|
||||
handleTuitionPaymentPlans();
|
||||
// Fetch data for tuition payment plans
|
||||
handleTuitionPaymentPlans();
|
||||
|
||||
// Fetch data for registration payment modes
|
||||
handleRegistrationPaymentModes();
|
||||
// Fetch data for registration payment modes
|
||||
handleRegistrationPaymentModes();
|
||||
|
||||
// Fetch data for tuition payment modes
|
||||
handleTuitionPaymentModes();
|
||||
}, []);
|
||||
// Fetch data for tuition payment modes
|
||||
handleTuitionPaymentModes();
|
||||
}
|
||||
}, [selectedEstablishmentId]);
|
||||
|
||||
const handleSpecialities = () => {
|
||||
fetchSpecialities()
|
||||
fetchSpecialities(selectedEstablishmentId)
|
||||
.then(data => {
|
||||
setSpecialities(data);
|
||||
})
|
||||
@ -100,7 +103,7 @@ export default function Page() {
|
||||
};
|
||||
|
||||
const handleTeachers = () => {
|
||||
fetchTeachers()
|
||||
fetchTeachers(selectedEstablishmentId)
|
||||
.then(data => {
|
||||
setTeachers(data);
|
||||
})
|
||||
@ -108,7 +111,7 @@ export default function Page() {
|
||||
};
|
||||
|
||||
const handleClasses = () => {
|
||||
fetchClasses()
|
||||
fetchClasses(selectedEstablishmentId)
|
||||
.then(data => {
|
||||
setClasses(data);
|
||||
})
|
||||
@ -124,7 +127,7 @@ export default function Page() {
|
||||
};
|
||||
|
||||
const handleRegistrationDiscounts = () => {
|
||||
fetchRegistrationDiscounts()
|
||||
fetchRegistrationDiscounts(selectedEstablishmentId)
|
||||
.then(data => {
|
||||
setRegistrationDiscounts(data);
|
||||
})
|
||||
@ -132,7 +135,7 @@ export default function Page() {
|
||||
};
|
||||
|
||||
const handleTuitionDiscounts = () => {
|
||||
fetchTuitionDiscounts()
|
||||
fetchTuitionDiscounts(selectedEstablishmentId)
|
||||
.then(data => {
|
||||
setTuitionDiscounts(data);
|
||||
})
|
||||
@ -140,7 +143,7 @@ export default function Page() {
|
||||
};
|
||||
|
||||
const handleRegistrationFees = () => {
|
||||
fetchRegistrationFees()
|
||||
fetchRegistrationFees(selectedEstablishmentId)
|
||||
.then(data => {
|
||||
setRegistrationFees(data);
|
||||
})
|
||||
@ -148,7 +151,7 @@ export default function Page() {
|
||||
};
|
||||
|
||||
const handleTuitionFees = () => {
|
||||
fetchTuitionFees()
|
||||
fetchTuitionFees(selectedEstablishmentId)
|
||||
.then(data => {
|
||||
setTuitionFees(data);
|
||||
})
|
||||
@ -156,7 +159,7 @@ export default function Page() {
|
||||
};
|
||||
|
||||
const handleRegistrationPaymentPlans = () => {
|
||||
fetchRegistrationPaymentPlans()
|
||||
fetchRegistrationPaymentPlans(selectedEstablishmentId)
|
||||
.then(data => {
|
||||
setRegistrationPaymentPlans(data);
|
||||
})
|
||||
@ -164,7 +167,7 @@ export default function Page() {
|
||||
};
|
||||
|
||||
const handleTuitionPaymentPlans = () => {
|
||||
fetchTuitionPaymentPlans()
|
||||
fetchTuitionPaymentPlans(selectedEstablishmentId)
|
||||
.then(data => {
|
||||
setTuitionPaymentPlans(data);
|
||||
})
|
||||
@ -172,7 +175,7 @@ export default function Page() {
|
||||
};
|
||||
|
||||
const handleRegistrationPaymentModes = () => {
|
||||
fetchRegistrationPaymentModes()
|
||||
fetchRegistrationPaymentModes(selectedEstablishmentId)
|
||||
.then(data => {
|
||||
setRegistrationPaymentModes(data);
|
||||
})
|
||||
@ -180,7 +183,7 @@ export default function Page() {
|
||||
};
|
||||
|
||||
const handleTuitionPaymentModes = () => {
|
||||
fetchTuitionPaymentModes()
|
||||
fetchTuitionPaymentModes(selectedEstablishmentId)
|
||||
.then(data => {
|
||||
setTuitionPaymentModes(data);
|
||||
})
|
||||
|
||||
@ -16,6 +16,7 @@ import Modal from '@/components/Modal';
|
||||
import InscriptionForm from '@/components/Inscription/InscriptionForm'
|
||||
import AffectationClasseForm from '@/components/AffectationClasseForm'
|
||||
import { getSession } from 'next-auth/react';
|
||||
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||
|
||||
import {
|
||||
PENDING,
|
||||
@ -50,7 +51,6 @@ import {
|
||||
|
||||
import DjangoCSRFToken from '@/components/DjangoCSRFToken'
|
||||
import { useCsrfToken } from '@/context/CsrfContext';
|
||||
import { ESTABLISHMENT_ID } from '@/utils/Url';
|
||||
import logger from '@/utils/logger';
|
||||
|
||||
export default function Page({ params: { locale } }) {
|
||||
@ -87,9 +87,8 @@ export default function Page({ params: { locale } }) {
|
||||
const [tuitionFees, setTuitionFees] = useState([]);
|
||||
const [groups, setGroups] = useState([]);
|
||||
|
||||
const [establishmentId, setEstablishmentId] = useState(null);
|
||||
|
||||
const csrfToken = useCsrfToken();
|
||||
const { selectedEstablishmentId } = useEstablishment();
|
||||
|
||||
const openModal = () => {
|
||||
setIsOpen(true);
|
||||
@ -167,23 +166,11 @@ const registerFormArchivedDataHandler = (data) => {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getSession()
|
||||
.then(session => {
|
||||
if (session && session.user) {
|
||||
setEstablishmentId(session.user.establishment);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
logger.error('Error fetching session:', err);
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (establishmentId) {
|
||||
if (selectedEstablishmentId) {
|
||||
const fetchInitialData = () => {
|
||||
Promise.all([
|
||||
fetchClasses(),
|
||||
fetchStudents(establishmentId) // Utiliser l'ID de l'établissement ici
|
||||
fetchClasses(selectedEstablishmentId),
|
||||
fetchStudents(selectedEstablishmentId) // Utiliser l'ID de l'établissement ici
|
||||
])
|
||||
.then(([classesData, studentsData]) => {
|
||||
setClasses(classesData);
|
||||
@ -198,21 +185,21 @@ useEffect(() => {
|
||||
|
||||
fetchInitialData();
|
||||
}
|
||||
}, [establishmentId]);
|
||||
}, [selectedEstablishmentId]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (establishmentId) {
|
||||
if (selectedEstablishmentId) {
|
||||
const fetchDataAndSetState = () => {
|
||||
setIsLoading(true);
|
||||
Promise.all([
|
||||
fetchRegisterForms(establishmentId, PENDING, currentPage, itemsPerPage, searchTerm)
|
||||
fetchRegisterForms(selectedEstablishmentId, PENDING, currentPage, itemsPerPage, searchTerm)
|
||||
.then(registerFormPendingDataHandler)
|
||||
.catch(requestErrorHandler),
|
||||
fetchRegisterForms(establishmentId, SUBSCRIBED)
|
||||
fetchRegisterForms(selectedEstablishmentId, SUBSCRIBED)
|
||||
.then(registerFormSubscribedDataHandler)
|
||||
.catch(requestErrorHandler),
|
||||
fetchRegisterForms(establishmentId, ARCHIVED)
|
||||
fetchRegisterForms(selectedEstablishmentId, ARCHIVED)
|
||||
.then(registerFormArchivedDataHandler)
|
||||
.catch(requestErrorHandler),
|
||||
fetchRegistrationTemplateMaster()
|
||||
@ -222,27 +209,27 @@ useEffect(() => {
|
||||
.catch(err => {
|
||||
logger.debug(err.message);
|
||||
}),
|
||||
fetchRegistrationDiscounts()
|
||||
fetchRegistrationDiscounts(selectedEstablishmentId)
|
||||
.then(data => {
|
||||
setRegistrationDiscounts(data);
|
||||
})
|
||||
.catch(requestErrorHandler),
|
||||
fetchTuitionDiscounts()
|
||||
fetchTuitionDiscounts(selectedEstablishmentId)
|
||||
.then(data => {
|
||||
setTuitionDiscounts(data);
|
||||
})
|
||||
.catch(requestErrorHandler),
|
||||
fetchRegistrationFees()
|
||||
fetchRegistrationFees(selectedEstablishmentId)
|
||||
.then(data => {
|
||||
setRegistrationFees(data);
|
||||
})
|
||||
.catch(requestErrorHandler),
|
||||
fetchTuitionFees()
|
||||
fetchTuitionFees(selectedEstablishmentId)
|
||||
.then(data => {
|
||||
setTuitionFees(data);
|
||||
})
|
||||
.catch(requestErrorHandler),
|
||||
fetchRegistrationFileGroups()
|
||||
fetchRegistrationFileGroups(selectedEstablishmentId)
|
||||
.then(data => {
|
||||
setGroups(data);
|
||||
})
|
||||
@ -263,20 +250,20 @@ useEffect(() => {
|
||||
|
||||
fetchDataAndSetState();
|
||||
}
|
||||
}, [establishmentId, reloadFetch, currentPage, searchTerm]);
|
||||
}, [selectedEstablishmentId, reloadFetch, currentPage, searchTerm]);
|
||||
|
||||
useEffect(() => {
|
||||
if (establishmentId) {
|
||||
if (selectedEstablishmentId) {
|
||||
const fetchDataAndSetState = () => {
|
||||
|
||||
setIsLoading(true);
|
||||
fetchRegisterForms(establishmentId, PENDING, currentPage, itemsPerPage, searchTerm)
|
||||
fetchRegisterForms(selectedEstablishmentId, PENDING, currentPage, itemsPerPage, searchTerm)
|
||||
.then(registerFormPendingDataHandler)
|
||||
.catch(requestErrorHandler)
|
||||
fetchRegisterForms(establishmentId, SUBSCRIBED)
|
||||
fetchRegisterForms(selectedEstablishmentId, SUBSCRIBED)
|
||||
.then(registerFormSubscribedDataHandler)
|
||||
.catch(requestErrorHandler)
|
||||
fetchRegisterForms(establishmentId, ARCHIVED)
|
||||
fetchRegisterForms(selectedEstablishmentId, ARCHIVED)
|
||||
.then(registerFormArchivedDataHandler)
|
||||
.catch(requestErrorHandler)
|
||||
fetchRegistrationTemplateMaster()
|
||||
@ -545,7 +532,7 @@ useEffect(()=>{
|
||||
const columns = [
|
||||
{ name: t('studentName'), transform: (row) => row.student.last_name },
|
||||
{ name: t('studentFistName'), transform: (row) => row.student.first_name },
|
||||
{ name: t('mainContactMail'), transform: (row) => row.student.guardians[0].email },
|
||||
{ name: t('mainContactMail'), transform: (row) => row.student.guardians[0].associated_profile_email },
|
||||
{ name: t('phone'), transform: (row) => formatPhoneNumber(row.student.guardians[0].phone) },
|
||||
{ name: t('lastUpdateDate'), transform: (row) => row.formatted_last_update},
|
||||
{ name: t('registrationFileStatus'), transform: (row) => (
|
||||
|
||||
Reference in New Issue
Block a user