refactor: Changement des IconTextInput en TextInput, modification du composant step

This commit is contained in:
Luc SORIGNET
2025-01-27 11:20:44 +01:00
parent 6f1631a75b
commit a248898203
16 changed files with 270 additions and 127 deletions

View File

@ -319,8 +319,8 @@ class ChildrenListView(APIView):
"""
# Récupération des élèves d'un parent
# idProfile : identifiant du profil connecté rattaché aux fiches d'élèves
def get(self, request, _idProfile):
students = bdd.getObjects(_objectName=RegistrationForm, _columnName='student__guardians__associated_profile__id', _value=_idProfile)
def get(self, request, _id):
students = bdd.getObjects(_objectName=RegistrationForm, _columnName='student__guardians__associated_profile__id', _value=_id)
students_serializer = RegistrationFormByParentSerializer(students, many=True)
return JsonResponse(students_serializer.data, safe=False)

View File

@ -1,31 +1,19 @@
'use client'
import React, { useState, useEffect } from 'react';
import React, { useState } from 'react';
import InscriptionFormShared from '@/components/Inscription/InscriptionFormShared';
import { useSearchParams, redirect, useRouter } from 'next/navigation';
import { useSearchParams, useRouter } from 'next/navigation';
import useCsrfToken from '@/hooks/useCsrfToken';
import { FE_PARENTS_HOME_URL} from '@/utils/Url';
import { mockStudent } from '@/data/mockStudent';
import { fetchLastGuardian, fetchRegisterForm } from '@/app/lib/subscriptionAction';
const useFakeData = process.env.NEXT_PUBLIC_USE_FAKE_DATA === 'true';
import { editRegisterForm} from '@/app/lib/subscriptionAction';
export default function Page() {
const searchParams = useSearchParams();
const idProfil = searchParams.get('id');
const studentId = searchParams.get('studentId');
const router = useRouter();
const [initialData, setInitialData] = useState(null);
const csrfToken = useCsrfToken();
const [currentProfil, setCurrentProfil] = useState("");
const handleSubmit = async (data) => {
if (useFakeData) {
console.log('Fake submit:', data);
return;
}
try {
const result = await editRegisterForm(studentId, data, csrfToken);
console.log('Success:', result);
@ -41,7 +29,6 @@ export default function Page() {
csrfToken={csrfToken}
onSubmit={handleSubmit}
cancelUrl={FE_PARENTS_HOME_URL}
isLoading={isLoading}
/>
);
}

View File

@ -17,9 +17,10 @@ export default function Layout({
const router = useRouter(); // Définition de router
const [messages, setMessages] = useState([]);
const [userId, setUserId] = useLocalStorage("userId", '') ;
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
setIsLoading(true);
setUserId(userId)
fetchMessages(userId)
.then(data => {
@ -30,8 +31,15 @@ export default function Layout({
})
.catch(error => {
console.error('Error fetching data:', error);
})
.finally(() => {
setIsLoading(false);
});
}, []);
}, [userId]);
if (isLoading) {
return <div>Loading...</div>;
}
return (
<ProtectedRoute>

View File

@ -5,7 +5,7 @@ import { GraduationCap } from 'lucide-react';
const ClasseDetails = ({ classe }) => {
if (!classe) return null;
const nombreElevesInscrits = classe.eleves.length;
const nombreElevesInscrits = classe?.eleves?.length||0;
const capaciteTotale = classe.number_of_students;
const pourcentage = Math.round((nombreElevesInscrits / capaciteTotale) * 100);
@ -34,7 +34,7 @@ const ClasseDetails = ({ classe }) => {
</div>
</div>
</div>
{/* Section Capacité de la Classe */}
<div className="flex items-center space-x-4">
<div className="flex items-center">

View File

@ -6,8 +6,8 @@ import Button from '@/components/Button';
import Table from '@/components/Table';
import FeesSection from '@/components/Structure/Tarification/FeesSection';
import DiscountsSection from '@/components/Structure/Tarification/DiscountsSection';
import Navigation from '@/components/Navigation';
import StepTitle from '@/components/StepTitle';
import SectionTitle from '@/components/SectionTitle';
import ProgressStep from '@/components/ProgressStep';
const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, registrationFees, tuitionFees, onSubmit, currentStep }) => {
const [formData, setFormData] = useState({
@ -37,8 +37,8 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
4: 'Frais de scolarité',
5: 'Récapitulatif'
};
const steps = ['1', '2', '3', '4', 'Récap'];
const steps = ['Élève', 'Responsable', 'Inscription', 'Scolarité', 'Récap'];
const isStep1Valid = formData.studentLastName && formData.studentFirstName;
const isStep2Valid = (
@ -136,7 +136,7 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
return { ...prevData, selectedRegistrationFees };
});
};
const handleTuitionFeeSelection = (feeId) => {
setFormData((prevData) => {
const selectedTuitionFees = prevData.selectedTuitionFees.includes(feeId)
@ -147,7 +147,7 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
return { ...prevData, selectedTuitionFees };
});
};
const handleRegistrationDiscountSelection = (discountId) => {
setFormData((prevData) => {
const selectedRegistrationDiscounts = prevData.selectedRegistrationDiscounts.includes(discountId)
@ -169,7 +169,7 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
return { ...prevData, selectedTuitionDiscounts };
});
};
const calculateFinalRegistrationAmount = (selectedRegistrationFees, selectedRegistrationDiscounts) => {
const totalFees = selectedRegistrationFees.reduce((sum, feeId) => {
const fee = registrationFees.find(f => f.id === feeId);
@ -178,7 +178,7 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
}
return sum;
}, 0);
const totalDiscounts = selectedRegistrationDiscounts.reduce((sum, discountId) => {
const discount = registrationDiscounts.find(d => d.id === discountId);
if (discount) {
@ -190,9 +190,9 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
}
return sum;
}, 0);
const finalAmount = totalFees - totalDiscounts;
return finalAmount.toFixed(2);
};
@ -204,7 +204,7 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
}
return sum;
}, 0);
const totalDiscounts = selectedTuitionDiscounts.reduce((sum, discountId) => {
const discount = tuitionDiscounts.find(d => d.id === discountId);
if (discount) {
@ -216,20 +216,20 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
}
return sum;
}, 0);
const finalAmount = totalFees - totalDiscounts;
return finalAmount.toFixed(2);
};
return (
<div className="space-y-4 mt-6">
<Navigation
<ProgressStep
steps={steps}
step={step}
stepTitles={stepTitles}
currentStep={step}
setStep={setStep}
isStepValid={isStepValid}
stepTitles={stepTitles}
/>
{step === 1 && (
@ -257,15 +257,6 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
{step === 2 && (
<div className="mt-6">
<InputTextIcon
name="guardianPhone"
type="tel"
IconItem={Phone}
placeholder="Numéro de téléphone (optionnel)"
value={formData.guardianPhone}
onChange={handleChange}
className="w-full mt-4"
/>
<div className="flex flex-col space-y-4 mt-6">
<label className="flex items-center space-x-3">
<input
@ -291,6 +282,7 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
</label>
</div>
{formData.responsableType === 'new' && (
<>
<InputTextIcon
name="guardianEmail"
type="email"
@ -300,6 +292,16 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
onChange={handleChange}
className="w-full mt-4"
/>
<InputTextIcon
name="guardianPhone"
type="tel"
IconItem={Phone}
placeholder="Numéro de téléphone (optionnel)"
value={formData.guardianPhone}
onChange={handleChange}
className="w-full mt-4"
/>
</>
)}
{formData.responsableType === 'existing' && (
@ -364,7 +366,7 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
handleFeeSelection={handleRegistrationFeeSelection}
/>
</div>
<StepTitle title='Réductions' />
<SectionTitle title='Réductions' />
<div className="mb-4">
{registrationDiscounts.length > 0 ? (
<DiscountsSection
@ -381,16 +383,16 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
</p>
)}
</div>
<StepTitle title='Montant total' />
<SectionTitle title='Montant total' />
<Table
data={[ {id: 1}]}
columns={[
{
name: 'LIBELLE',
name: 'LIBELLE',
transform: () => <span>MONTANT TOTAL</span>
},
{
name: 'TOTAL',
name: 'TOTAL',
transform: () => <b>{totalRegistrationAmount} </b>
}
]}
@ -403,7 +405,7 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
<span className="block sm:inline"> Aucun frais d'inscription n'a été créé.</span>
</p>
)}
</div>
</div>
)}
{step === 4 && (
@ -419,7 +421,7 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
handleFeeSelection={handleTuitionFeeSelection}
/>
</div>
<StepTitle title='Réductions' />
<SectionTitle title='Réductions' />
<div className="mb-4">
{tuitionDiscounts.length > 0 ? (
<DiscountsSection
@ -436,16 +438,16 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
</p>
)}
</div>
<StepTitle title='Montant total' />
<SectionTitle title='Montant total' />
<Table
data={[ {id: 1}]}
columns={[
{
name: 'LIBELLE',
name: 'LIBELLE',
transform: () => <span>MONTANT TOTAL</span>
},
{
name: 'TOTAL',
name: 'TOTAL',
transform: () => <b>{totalTuitionAmount} €</b>
}
]}

View File

@ -39,7 +39,18 @@ export default function InscriptionFormShared({
}) {
// États pour gérer les données du formulaire
const [isLoading, setIsLoading] = useState(true);
const [formData, setFormData] = useState({});
const [formData, setFormData] = useState({
id: '',
last_name: '',
first_name: '',
address: '',
birth_date: '',
birth_place: '',
birth_postal_code: '',
nationality: '',
attending_physician: '',
level: ''
});
const [guardians, setGuardians] = useState([]);

View File

@ -5,9 +5,9 @@ const Modal = ({ isOpen, setIsOpen, title, ContentComponent }) => {
<Dialog.Root open={isOpen} onOpenChange={setIsOpen}>
<Dialog.Portal>
<Dialog.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
<Dialog.Content className="fixed inset-0 flex items-center justify-center">
<div className="inline-block align-bottom bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle" style={{ width: '600px', maxWidth: '90%' }}>
<div className="flex justify-between items-start">
<Dialog.Content className="fixed inset-0 flex items-center justify-center p-4">
<div className="inline-block bg-white rounded-lg px-6 py-5 text-left shadow-xl transform transition-all sm:my-8 min-w-[500px] w-max m-12 h-max">
<div className="flex justify-between items-start mb-4">
<Dialog.Title className="text-xl font-medium text-gray-900">
{title}
</Dialog.Title>
@ -23,7 +23,7 @@ const Modal = ({ isOpen, setIsOpen, title, ContentComponent }) => {
</button>
</Dialog.Close>
</div>
<div className="mt-2">
<div className="w-full">
<ContentComponent />
</div>
</div>

View File

@ -1,30 +0,0 @@
import React from 'react';
import StepTitle from '@/components/StepTitle';
const Navigation = ({ steps, step, setStep, isStepValid, stepTitles }) => {
return (
<div className="relative mb-4">
<div className="relative flex justify-between">
{steps.map((stepLabel, index) => {
const isCurrentStep = step === index + 1;
return (
<div key={index} className="flex flex-col items-center">
<div className={`mb-4 ${isCurrentStep ? 'text-gray-500 font-extrabold' : 'text-gray-500'}`}>
{stepLabel}
</div>
<div
className={`w-4 h-4 rounded-full mb-4 ${isStepValid(index + 1) ? 'bg-emerald-500' : 'bg-yellow-300'} cursor-pointer`}
onClick={() => setStep(index + 1)}
style={{ transform: 'translateY(-50%)' }}
></div>
</div>
);
})}
</div>
<StepTitle title={stepTitles[step]} />
</div>
);
};
export default Navigation;

View File

@ -0,0 +1,157 @@
import React, { useState, useEffect } from 'react';
const Step = ({ number, title, isActive, isValid, isCompleted, onClick }) => {
return (
<div className="flex-shrink-0 flex justify-center relative mx-4">
<div className={`
w-8 h-8 rounded-full
flex items-center justify-center
text-sm font-semibold
${isCompleted
? 'bg-emerald-600 text-white'
: isActive
? 'bg-emerald-600 text-white'
: 'bg-gray-200 text-gray-600'
}
`}>
{isCompleted ? (
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
</svg>
) : (
number
)}
</div>
<div className="absolute top-12 left-1/2 -translate-x-1/2">
<span className={`
text-xs font-medium w-20 text-center block break-words
${isActive ? 'text-emerald-600' : 'text-gray-500'}
`}>
{title}
</span>
</div>
</div>
);
};
const SpacerStep = ({ isCompleted }) => {
return (
<div className={`flex-1 h-0.5 ${isCompleted ? 'bg-emerald-600' : 'bg-gray-200'}`} />
);
};
const Dots = () => {
return (
<div className="text-gray-500 relative flex items-center mx-4">
<span>...</span>
<div className="absolute top-8 left-1/2 -translate-x-1/2">
<span className="text-xs font-medium w-20 text-center block">...</span>
</div>
</div>
);
};
const ProgressStep = ({ steps, stepTitles, currentStep, setStep, isStepValid }) => {
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
const [visibleSteps, setVisibleSteps] = useState(steps);
useEffect(() => {
const handleResize = () => setWindowWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
useEffect(() => {
const calculateVisibleSteps = () => {
const minWidth = 150; // Largeur minimale estimée par étape
const maxVisibleSteps = Math.floor(windowWidth / minWidth);
if (maxVisibleSteps >= steps.length) {
setVisibleSteps(steps);
return;
}
if (maxVisibleSteps < 4) {
// Garder seulement première, dernière et courante
let filtered = [steps[0]];
if (currentStep > 1 && currentStep < steps.length) {
filtered.push('...');
filtered.push(steps[currentStep - 1]);
}
if (currentStep < steps.length) {
filtered.push('...');
}
filtered.push(steps[steps.length - 1]);
setVisibleSteps(filtered);
} else {
// Garder première, dernière, courante et quelques étapes adjacentes
let filtered = [steps[0]];
if (currentStep > 2) filtered.push('...');
if (currentStep > 1 && currentStep < steps.length) {
filtered.push(steps[currentStep - 1]);
}
if (currentStep < steps.length - 1) filtered.push('...');
filtered.push(steps[steps.length - 1]);
setVisibleSteps(filtered);
}
};
calculateVisibleSteps();
}, [windowWidth, currentStep, steps]);
const handleStepClick = (stepIndex) => {
// Vérifie si on peut naviguer vers l'étape (toutes les étapes précédentes doivent être valides)
const canNavigate = Array.from({ length: stepIndex }, (_, i) => i + 1)
.every(step => isStepValid(step));
if (canNavigate) {
setStep(stepIndex + 1);
}
};
return (
<div className="w-full py-6">
<div className="flex items-center min-h-[100px]">
{visibleSteps.map((step, index) => {
if (step === '...') {
return (
<div key={`dots-${index}`} className="flex-1 flex items-center justify-center">
<Dots />
{index !== visibleSteps.length - 1 && <SpacerStep isCompleted={false} />}
</div>
);
}
const originalIndex = steps.indexOf(step);
return (
<div
key={index}
className={`
flex-1 relative
${Array.from({ length: originalIndex + 1 }, (_, i) => i + 1).every(s => isStepValid(s)) ? 'cursor-pointer' : 'cursor-not-allowed'}
`}
onClick={() => handleStepClick(originalIndex)}
>
<div className="flex items-center">
<div className="w-full flex items-center">
<Step
number={originalIndex + 1}
title={stepTitles ? stepTitles[originalIndex + 1] : step}
isActive={currentStep === originalIndex + 1}
isCompleted={currentStep > originalIndex + 1}
isValid={isStepValid(originalIndex + 1)}
/>
{index !== visibleSteps.length - 1 && (
<SpacerStep isCompleted={currentStep > originalIndex + 1} />
)}
</div>
</div>
</div>
);
})}
</div>
</div>
);
};
export default ProgressStep;

View File

@ -14,6 +14,9 @@ const ProtectedRoute = ({ children }) => {
}
}, [userId, router]);
if (!userId) {
return <div>Loading...</div>;
}
// Afficher les enfants seulement si l'utilisateur est connecté
return userId ? children : null;
};

View File

@ -1,6 +1,6 @@
import React from 'react';
const StepTitle = ({ title }) => {
const SectionTitle = ({ title }) => {
return (
<div className="relative mb-4">
<div className="absolute inset-0 flex items-center">
@ -13,4 +13,4 @@ const StepTitle = ({ title }) => {
);
};
export default StepTitle;
export default SectionTitle;

View File

@ -8,6 +8,7 @@ import { createProfile, updateProfile } from '@/app/lib/authAction';
import useCsrfToken from '@/hooks/useCsrfToken';
import { DndProvider, useDrag, useDrop } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import InputText from '@/components/InputText';
const ItemTypes = {
SPECIALITY: 'speciality',
@ -158,7 +159,7 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
const handleChange = (e) => {
const { name, value } = e.target;
let parsedValue = value;
if (editingTeacher) {
setFormData((prevData) => ({
...prevData,
@ -203,7 +204,7 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
switch (column) {
case 'NOM':
return (
<InputTextIcon
<InputText
name="last_name"
value={currentData.last_name}
onChange={handleChange}
@ -213,7 +214,7 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
);
case 'PRENOM':
return (
<InputTextIcon
<InputText
name="first_name"
value={currentData.first_name}
onChange={handleChange}
@ -223,7 +224,7 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
);
case 'EMAIL':
return (
<InputTextIcon
<InputText
name="email"
value={currentData.email}
onChange={handleChange}

View File

@ -35,14 +35,14 @@ const ScheduleManagement = ({ handleUpdatePlanning, classes }) => {
setSelectedLevel(niveau);
const currentPlanning = selectedClass.plannings_read.find(planning => planning.niveau === niveau);
const currentPlanning = selectedClass.plannings_read?.find(planning => planning.niveau === niveau);
setSchedule(currentPlanning ? currentPlanning.planning : {});
}
}, [selectedClass, niveauxLabels]);
useEffect(() => {
if (selectedClass && selectedLevel) {
const currentPlanning = selectedClass.plannings_read.find(planning => planning.niveau === selectedLevel);
const currentPlanning = selectedClass.plannings_read?.find(planning => planning.niveau === selectedLevel);
setSchedule(currentPlanning ? currentPlanning.planning : {});
}
}, [selectedClass, selectedLevel]);

View File

@ -1,9 +1,9 @@
import React, { useState } from 'react';
import { Plus, Trash2, Edit3, Check, X, Percent, EuroIcon, Tag } from 'lucide-react';
import Table from '@/components/Table';
import InputTextIcon from '@/components/InputTextIcon';
import Popup from '@/components/Popup';
import CheckBox from '@/components/CheckBox';
import InputText from '@/components/InputText';
const DiscountsSection = ({ discounts, setDiscounts, handleCreate, handleEdit, handleDelete, type, subscriptionMode = false, selectedDiscounts, handleDiscountSelection }) => {
const [editingDiscount, setEditingDiscount] = useState(null);
@ -103,7 +103,7 @@ const DiscountsSection = ({ discounts, setDiscounts, handleCreate, handleEdit, h
const renderInputField = (field, value, onChange, placeholder) => (
<div>
<InputTextIcon
<InputText
name={field}
type={field === 'amount' ? 'number' : 'text'}
value={value}

View File

@ -1,9 +1,9 @@
import React, { useState } from 'react';
import { Plus, Trash2, Edit3, Check, X, EyeOff, Eye, CreditCard, BookOpen } from 'lucide-react';
import Table from '@/components/Table';
import InputTextIcon from '@/components/InputTextIcon';
import Popup from '@/components/Popup';
import CheckBox from '@/components/CheckBox';
import InputText from '@/components/InputText';
const FeesSection = ({ fees, setFees, discounts, handleCreate, handleEdit, handleDelete, type, subscriptionMode = false, selectedFees, handleFeeSelection }) => {
const [editingFee, setEditingFee] = useState(null);
@ -112,7 +112,7 @@ const FeesSection = ({ fees, setFees, discounts, handleCreate, handleEdit, handl
const renderInputField = (field, value, onChange, placeholder) => (
<div className="flex justify-center items-center h-full">
<InputTextIcon
<InputText
name={field}
type={field === 'base_amount' ? 'number' : 'text'}
value={value}

View File

@ -39,7 +39,7 @@ export const ClassesProvider = ({ children }) => {
{ id: 2, label: 'Semestriel' },
{ id: 3, label: 'Trimestriel' },
];
const selectedDays = {
1: 'lundi',
2: 'mardi',
@ -60,14 +60,14 @@ export const ClassesProvider = ({ children }) => {
const getNiveauxTabs = (levels) => {
// Trier les levels par id
const sortedNiveaux = levels.sort((a, b) => a - b);
// Mapper les labels correspondants
return sortedNiveaux.map(niveauId => {
const niveau = allNiveaux.find(n => n.id === niveauId);
return niveau ? { id: niveau.id, title: niveau.name, icon: School } : { id: 'unknown', title: 'Niveau inconnu', icon: null };
});
};
const generateAgeToNiveaux = (minAge, maxAge) => {
if (minAge === null || isNaN(minAge)) {
@ -112,7 +112,7 @@ export const ClassesProvider = ({ children }) => {
const updatePlannings = (formData, existingPlannings) => {
return formData.levels.map(niveau => {
let existingPlanning = existingPlannings.find(planning => planning.niveau === niveau);
const emploiDuTemps = formData.opening_days.reduce((acc, dayId) => {
const dayName = selectedDays[dayId];
if (dayName) {
@ -167,7 +167,7 @@ export const ClassesProvider = ({ children }) => {
}
// Fusionner les plannings existants avec les nouvelles données
return existingPlanning
return existingPlanning
? { ...existingPlanning, ...updatedPlanning }
: updatedPlanning;
});
@ -176,17 +176,21 @@ export const ClassesProvider = ({ children }) => {
const groupSpecialitiesBySubject = (teachers) => {
const groupedSpecialities = {};
if (!teachers) return [];
teachers.forEach(teacher => {
teacher.specialites.forEach(specialite => {
if (!groupedSpecialities[specialite.id]) {
groupedSpecialities[specialite.id] = {
...specialite,
teachers: [`${teacher.nom} ${teacher.prenom}`],
};
} else {
groupedSpecialities[specialite.id].teachers.push(`${teacher.nom} ${teacher.prenom}`);
}
});
if (teacher && teacher.specialites) {
teacher.specialites.forEach(specialite => {
if (!groupedSpecialities[specialite.id]) {
groupedSpecialities[specialite.id] = {
...specialite,
teachers: [`${teacher.nom} ${teacher.prenom}`],
};
} else {
groupedSpecialities[specialite.id].teachers.push(`${teacher.nom} ${teacher.prenom}`);
}
});
}
});
return Object.values(groupedSpecialities);
@ -202,15 +206,15 @@ export const ClassesProvider = ({ children }) => {
};
return (
<ClassesContext.Provider value={{ schoolYears,
getNiveauxLabels,
getNiveauxTabs,
generateAgeToNiveaux,
niveauxPremierCycle,
niveauxSecondCycle,
niveauxTroisiemeCycle,
typeEmploiDuTemps,
updatePlannings,
<ClassesContext.Provider value={{ schoolYears,
getNiveauxLabels,
getNiveauxTabs,
generateAgeToNiveaux,
niveauxPremierCycle,
niveauxSecondCycle,
niveauxTroisiemeCycle,
typeEmploiDuTemps,
updatePlannings,
getAmbianceText,
getAmbianceName,
groupSpecialitiesBySubject,