mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-29 16:03:21 +00:00
feat: Création nouveau style / pagination profils annuaires
This commit is contained in:
@ -1,125 +1,50 @@
|
||||
'use client';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import {
|
||||
fetchProfileRoles,
|
||||
updateProfileRoles,
|
||||
deleteProfileRoles,
|
||||
} from '@/app/actions/authAction';
|
||||
import { dissociateGuardian } from '@/app/actions/subscriptionAction';
|
||||
import { fetchProfileRoles } from '@/app/actions/authAction';
|
||||
import logger from '@/utils/logger';
|
||||
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||
import DjangoCSRFToken from '@/components/DjangoCSRFToken';
|
||||
import { useCsrfToken } from '@/context/CsrfContext';
|
||||
import ProfileDirectory from '@/components/ProfileDirectory';
|
||||
import { PARENT_FILTER, SCHOOL_FILTER } from '@/utils/constants';
|
||||
|
||||
export default function Page() {
|
||||
const [profileRoles, setProfileRoles] = useState([]);
|
||||
const [profileRolesDatasParent, setProfileRolesDatasParent] = useState([]);
|
||||
const [profileRolesDatasSchool, setProfileRolesDatasSchool] = useState([]);
|
||||
const [reloadFetch, setReloadFetch] = useState(false);
|
||||
|
||||
const csrfToken = useCsrfToken();
|
||||
const { selectedEstablishmentId } = useEstablishment();
|
||||
|
||||
const requestErrorHandler = (err) => {
|
||||
logger.error('Error fetching data:', err);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedEstablishmentId) {
|
||||
// Fetch data for profileRoles
|
||||
// Fetch data for profileRolesParent
|
||||
handleProfiles();
|
||||
}
|
||||
}, [selectedEstablishmentId, reloadFetch]);
|
||||
|
||||
const handleProfiles = () => {
|
||||
fetchProfileRoles(selectedEstablishmentId)
|
||||
fetchProfileRoles(selectedEstablishmentId, PARENT_FILTER)
|
||||
.then((data) => {
|
||||
setProfileRoles(data);
|
||||
setProfileRolesDatasParent(data);
|
||||
})
|
||||
.catch((error) => logger.error('Error fetching profileRoles:', error));
|
||||
.catch(requestErrorHandler);
|
||||
|
||||
fetchProfileRoles(selectedEstablishmentId, SCHOOL_FILTER)
|
||||
.then((data) => {
|
||||
setProfileRolesDatasSchool(data);
|
||||
})
|
||||
.catch(requestErrorHandler);
|
||||
setReloadFetch(false);
|
||||
};
|
||||
|
||||
const handleEdit = (profileRole) => {
|
||||
const updatedData = { ...profileRole, is_active: !profileRole.is_active };
|
||||
return updateProfileRoles(profileRole.id, updatedData, csrfToken)
|
||||
.then((data) => {
|
||||
setProfileRoles((prevState) =>
|
||||
prevState.map((item) => (item.id === profileRole.id ? data : item))
|
||||
);
|
||||
return data;
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error('Error editing data:', error);
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
|
||||
const handleDelete = (id) => {
|
||||
return deleteProfileRoles(id, csrfToken)
|
||||
.then(() => {
|
||||
setProfileRoles((prevState) =>
|
||||
prevState.filter((item) => item.id !== id)
|
||||
);
|
||||
logger.debug('Profile deleted successfully:', id);
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error('Error deleting profile:', error);
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
|
||||
const handleDissociate = (studentId, guardianId) => {
|
||||
return dissociateGuardian(studentId, guardianId)
|
||||
.then((response) => {
|
||||
logger.debug('Guardian dissociated successfully:', guardianId);
|
||||
|
||||
// Vérifier si le Guardian a été supprimé
|
||||
const isGuardianDeleted = response?.isGuardianDeleted;
|
||||
|
||||
// Mettre à jour le modèle profileRoles
|
||||
setProfileRoles(
|
||||
(prevState) =>
|
||||
prevState
|
||||
.map((profileRole) => {
|
||||
if (profileRole.associated_person?.id === guardianId) {
|
||||
if (isGuardianDeleted) {
|
||||
// Si le Guardian est supprimé, retirer le profileRole
|
||||
return null;
|
||||
} else {
|
||||
// Si le Guardian n'est pas supprimé, mettre à jour les élèves associés
|
||||
const updatedStudents =
|
||||
profileRole.associated_person.students.filter(
|
||||
(student) => student.id !== studentId
|
||||
);
|
||||
return {
|
||||
...profileRole,
|
||||
associated_person: {
|
||||
...profileRole.associated_person,
|
||||
students: updatedStudents, // Mettre à jour les élèves associés
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
setReloadFetch(true);
|
||||
return profileRole; // Conserver les autres profileRoles
|
||||
})
|
||||
.filter(Boolean) // Supprimer les entrées nulles
|
||||
);
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error('Error dissociating guardian:', error);
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-8">
|
||||
<DjangoCSRFToken csrfToken={csrfToken} />
|
||||
|
||||
<div className="w-full p-4">
|
||||
<ProfileDirectory
|
||||
profileRoles={profileRoles}
|
||||
handleActivateProfile={handleEdit}
|
||||
handleDeleteProfile={handleDelete}
|
||||
handleDissociateGuardian={handleDissociate}
|
||||
/>
|
||||
</div>
|
||||
<div className="w-full h-full">
|
||||
<ProfileDirectory
|
||||
parentProfiles={profileRolesDatasParent}
|
||||
schoolProfiles={profileRolesDatasSchool}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ import { useEstablishment } from '@/context/EstablishmentContext';
|
||||
|
||||
// Composant EventCard pour afficher les événements
|
||||
const EventCard = ({ title, date, description, type }) => (
|
||||
<div className="bg-white p-4 rounded-lg shadow-sm border border-gray-100 mb-4">
|
||||
<div className="bg-stone-50 p-4 rounded-lg shadow-sm border border-gray-100 mb-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<CalendarCheck className="text-blue-500" size={20} />
|
||||
<div>
|
||||
@ -125,7 +125,7 @@ export default function DashboardPage() {
|
||||
{/* Événements et KPIs */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-6">
|
||||
{/* Graphique des inscriptions */}
|
||||
<div className="lg:col-span-2 bg-white p-6 rounded-lg shadow-sm border border-gray-100">
|
||||
<div className="lg:col-span-2 bg-stone-50 p-6 rounded-lg shadow-sm border border-gray-100">
|
||||
<h2 className="text-lg font-semibold mb-4">
|
||||
{t('inscriptionTrends')}
|
||||
</h2>
|
||||
@ -136,24 +136,13 @@ export default function DashboardPage() {
|
||||
</div>
|
||||
|
||||
{/* Événements à venir */}
|
||||
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-100">
|
||||
<div className="bg-stone-50 p-6 rounded-lg shadow-sm border border-gray-100">
|
||||
<h2 className="text-lg font-semibold mb-4">{t('upcomingEvents')}</h2>
|
||||
{upcomingEvents.map((event, index) => (
|
||||
<EventCard key={index} {...event} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap">
|
||||
{classes.map((classe) => (
|
||||
<div
|
||||
key={classe.id}
|
||||
className="lg:col-span-2 bg-white p-6 rounded-lg shadow-sm border border-gray-100 mr-4"
|
||||
>
|
||||
<ClasseDetails classe={classe} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -382,10 +382,6 @@ export default function CreateSubscriptionPage() {
|
||||
(profile) => profile.id === formDataRef.current.existingProfileId
|
||||
);
|
||||
|
||||
// Affichez le profil existant dans la console
|
||||
console.log('Profil existant trouvé :', existingProfile?.email);
|
||||
console.log('debug : ', initialGuardianEmail);
|
||||
|
||||
const guardians = (() => {
|
||||
if (formDataRef.current.selectedGuardians.length > 0) {
|
||||
// Cas 3 : Des guardians sont sélectionnés
|
||||
|
||||
@ -47,9 +47,9 @@ import { getCurrentSchoolYear, getNextSchoolYear } from '@/utils/Date';
|
||||
|
||||
import {
|
||||
RegistrationFormStatus,
|
||||
CURRENT_YEAR,
|
||||
NEXT_YEAR,
|
||||
HISTORICAL,
|
||||
CURRENT_YEAR_FILTER,
|
||||
NEXT_YEAR_FILTER,
|
||||
HISTORICAL_FILTER,
|
||||
} from '@/utils/constants';
|
||||
|
||||
export default function Page({ params: { locale } }) {
|
||||
@ -75,7 +75,7 @@ export default function Page({ params: { locale } }) {
|
||||
useState(1);
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [activeTab, setActiveTab] = useState(CURRENT_YEAR);
|
||||
const [activeTab, setActiveTab] = useState(CURRENT_YEAR_FILTER);
|
||||
const [totalCurrentYear, setTotalCurrentYear] = useState(0);
|
||||
const [totalNextYear, setTotalNextYear] = useState(0);
|
||||
const [totalHistorical, setTotalHistorical] = useState(0);
|
||||
@ -190,7 +190,7 @@ export default function Page({ params: { locale } }) {
|
||||
Promise.all([
|
||||
fetchRegisterForms(
|
||||
selectedEstablishmentId,
|
||||
CURRENT_YEAR,
|
||||
CURRENT_YEAR_FILTER,
|
||||
currentSchoolYearPage,
|
||||
itemsPerPage,
|
||||
searchTerm
|
||||
@ -204,10 +204,10 @@ export default function Page({ params: { locale } }) {
|
||||
})
|
||||
.catch(requestErrorHandler),
|
||||
|
||||
fetchRegisterForms(selectedEstablishmentId, NEXT_YEAR)
|
||||
fetchRegisterForms(selectedEstablishmentId, NEXT_YEAR_FILTER)
|
||||
.then(registerFormNextYearDataHandler)
|
||||
.catch(requestErrorHandler),
|
||||
fetchRegisterForms(selectedEstablishmentId, HISTORICAL)
|
||||
fetchRegisterForms(selectedEstablishmentId, HISTORICAL_FILTER)
|
||||
.then(registerFormHistoricalDataHandler)
|
||||
.catch(requestErrorHandler),
|
||||
])
|
||||
@ -232,17 +232,17 @@ export default function Page({ params: { locale } }) {
|
||||
setIsLoading(true);
|
||||
fetchRegisterForms(
|
||||
selectedEstablishmentId,
|
||||
CURRENT_YEAR,
|
||||
CURRENT_YEAR_FILTER,
|
||||
currentSchoolYearPage,
|
||||
itemsPerPage,
|
||||
searchTerm
|
||||
)
|
||||
.then(registerFormCurrrentYearDataHandler)
|
||||
.catch(requestErrorHandler);
|
||||
fetchRegisterForms(selectedEstablishmentId, NEXT_YEAR)
|
||||
fetchRegisterForms(selectedEstablishmentId, NEXT_YEAR_FILTER)
|
||||
.then(registerFormNextYearDataHandler)
|
||||
.catch(requestErrorHandler);
|
||||
fetchRegisterForms(selectedEstablishmentId, HISTORICAL)
|
||||
fetchRegisterForms(selectedEstablishmentId, HISTORICAL_FILTER)
|
||||
.then(registerFormHistoricalDataHandler)
|
||||
.catch(requestErrorHandler);
|
||||
|
||||
@ -261,13 +261,13 @@ export default function Page({ params: { locale } }) {
|
||||
* UseEffect to update page count of tab
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (activeTab === CURRENT_YEAR) {
|
||||
if (activeTab === CURRENT_YEAR_FILTER) {
|
||||
setTotalCurrentSchoolYearPages(
|
||||
Math.ceil(totalCurrentYear / itemsPerPage)
|
||||
);
|
||||
} else if (activeTab === NEXT_YEAR) {
|
||||
} else if (activeTab === NEXT_YEAR_FILTER) {
|
||||
setTotalNextSchoolYearPages(Math.ceil(totalNextYear / itemsPerPage));
|
||||
} else if (activeTab === HISTORICAL) {
|
||||
} else if (activeTab === HISTORICAL_FILTER) {
|
||||
setTotalHistoricalPages(Math.ceil(totalHistorical / itemsPerPage));
|
||||
}
|
||||
}, [currentSchoolYearPage]);
|
||||
@ -376,11 +376,11 @@ export default function Page({ params: { locale } }) {
|
||||
};
|
||||
|
||||
const handlePageChange = (newPage) => {
|
||||
if (activeTab === CURRENT_YEAR) {
|
||||
if (activeTab === CURRENT_YEAR_FILTER) {
|
||||
setCurrentSchoolYearPage(newPage);
|
||||
} else if (activeTab === NEXT_YEAR) {
|
||||
} else if (activeTab === NEXT_YEAR_FILTER) {
|
||||
setCurrentSchoolNextYearPage(newPage);
|
||||
} else if (activeTab === HISTORICAL) {
|
||||
} else if (activeTab === HISTORICAL_FILTER) {
|
||||
setCurrentSchoolHistoricalYearPage(newPage);
|
||||
}
|
||||
};
|
||||
@ -710,8 +710,8 @@ export default function Page({ params: { locale } }) {
|
||||
</span>
|
||||
</>
|
||||
}
|
||||
active={activeTab === CURRENT_YEAR}
|
||||
onClick={() => setActiveTab(CURRENT_YEAR)}
|
||||
active={activeTab === CURRENT_YEAR_FILTER}
|
||||
onClick={() => setActiveTab(CURRENT_YEAR_FILTER)}
|
||||
/>
|
||||
|
||||
{/* Tab pour l'année scolaire prochaine */}
|
||||
@ -724,8 +724,8 @@ export default function Page({ params: { locale } }) {
|
||||
</span>
|
||||
</>
|
||||
}
|
||||
active={activeTab === NEXT_YEAR}
|
||||
onClick={() => setActiveTab(NEXT_YEAR)}
|
||||
active={activeTab === NEXT_YEAR_FILTER}
|
||||
onClick={() => setActiveTab(NEXT_YEAR_FILTER)}
|
||||
/>
|
||||
|
||||
{/* Tab pour l'historique */}
|
||||
@ -738,16 +738,16 @@ export default function Page({ params: { locale } }) {
|
||||
</span>
|
||||
</>
|
||||
}
|
||||
active={activeTab === HISTORICAL}
|
||||
onClick={() => setActiveTab(HISTORICAL)}
|
||||
active={activeTab === HISTORICAL_FILTER}
|
||||
onClick={() => setActiveTab(HISTORICAL_FILTER)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="border-b border-gray-200 mb-6 w-full">
|
||||
{activeTab === CURRENT_YEAR ||
|
||||
activeTab === NEXT_YEAR ||
|
||||
activeTab === HISTORICAL ? (
|
||||
{activeTab === CURRENT_YEAR_FILTER ||
|
||||
activeTab === NEXT_YEAR_FILTER ||
|
||||
activeTab === HISTORICAL_FILTER ? (
|
||||
<React.Fragment>
|
||||
<div className="flex justify-between items-center mb-4 w-full">
|
||||
<div className="relative flex-grow">
|
||||
@ -779,25 +779,25 @@ export default function Page({ params: { locale } }) {
|
||||
<Table
|
||||
key={`${currentSchoolYearPage}-${searchTerm}`}
|
||||
data={
|
||||
activeTab === CURRENT_YEAR
|
||||
activeTab === CURRENT_YEAR_FILTER
|
||||
? registrationFormsDataCurrentYear
|
||||
: activeTab === NEXT_YEAR
|
||||
: activeTab === NEXT_YEAR_FILTER
|
||||
? registrationFormsDataNextYear
|
||||
: registrationFormsDataHistorical
|
||||
}
|
||||
columns={columns}
|
||||
itemsPerPage={itemsPerPage}
|
||||
currentPage={
|
||||
activeTab === CURRENT_YEAR
|
||||
activeTab === CURRENT_YEAR_FILTER
|
||||
? currentSchoolYearPage
|
||||
: activeTab === NEXT_YEAR
|
||||
: activeTab === NEXT_YEAR_FILTER
|
||||
? currentSchoolNextYearPage
|
||||
: currentSchoolHistoricalYearPage
|
||||
}
|
||||
totalPages={
|
||||
activeTab === CURRENT_YEAR
|
||||
activeTab === CURRENT_YEAR_FILTER
|
||||
? totalCurrentSchoolYearPages
|
||||
: activeTab === NEXT_YEAR
|
||||
: activeTab === NEXT_YEAR_FILTER
|
||||
? totalNextSchoolYearPages
|
||||
: totalHistoricalPages
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user