feat: Génération d'une page de suivi pédagogique + fix utilisation

certains des composants
This commit is contained in:
N3WT DE COMPET
2025-05-04 15:45:28 +02:00
parent e9650c992e
commit 2a6b3bdf63
7 changed files with 194 additions and 98 deletions

View File

@ -4,7 +4,7 @@
"structure": "Structure", "structure": "Structure",
"directory": "Directory", "directory": "Directory",
"events": "Events", "events": "Events",
"grades": "Grades", "educational_monitoring": "Educational Monitoring",
"settings": "Settings", "settings": "Settings",
"schoolAdmin": "School Administration" "schoolAdmin": "School Administration"
} }

View File

@ -4,7 +4,7 @@
"structure": "Structure", "structure": "Structure",
"directory": "Annuaire", "directory": "Annuaire",
"events": "Evenements", "events": "Evenements",
"grades": "Notes", "educational_monitoring": "Suivi pédagogique",
"settings": "Paramètres", "settings": "Paramètres",
"schoolAdmin": "Administration Scolaire" "schoolAdmin": "Administration Scolaire"
} }

View File

@ -1,10 +1,144 @@
'use client'; 'use client';
import React, { useState, useEffect } from 'react'; import React, { useState } from 'react';
import SelectChoice from '@/components/SelectChoice';
import Button from '@/components/Button';
import Table from '@/components/Table';
export default function Page() { export default function Page() {
const [formData, setFormData] = useState({
selectedStudent: null,
absences: [],
competenceReview: [
{ competence: 'Lecture', score: null },
{ competence: 'Écriture', score: null },
{ competence: 'Mathématiques', score: null },
{ competence: 'Sciences', score: null },
],
});
const students = [
{ id: 1, name: 'John Doe', class: 'CM2' },
{ id: 2, name: 'Jane Smith', class: 'CE1' },
{ id: 3, name: 'Alice Johnson', class: 'CM1' },
];
const absences = [
{ date: '2023-09-01', reason: 'Maladie' },
{ date: '2023-09-15', reason: 'Vacances' },
{ date: '2023-10-05', reason: 'Retard justifié' },
];
const handleChange = (field, value) => {
setFormData((prev) => ({ ...prev, [field]: value }));
};
const handleScoreChange = (index, score) => {
const updatedCompetenceReview = [...formData.competenceReview];
updatedCompetenceReview[index].score = score;
setFormData((prev) => ({
...prev,
competenceReview: updatedCompetenceReview,
}));
};
return ( return (
<div className="p-8"> <div className="p-8 space-y-8">
<h1 className="heading-section">Statistiques</h1> <h1 className="heading-section">Suivi pédagogique</h1>
{/* Sélection de l'élève */}
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
<h2 className="text-xl font-semibold mb-4">Sélectionner un élève</h2>
<SelectChoice
name="selectedStudent"
label="Élève"
placeHolder="Sélectionnez un élève"
selected={formData.selectedStudent}
callback={(e) => handleChange('selectedStudent', e.target.value)}
choices={students.map((student) => ({
value: student.id,
label: `${student.name} - Classe : ${student.class}`,
}))}
required
/>
</div>
{/* Liste des absences */}
{formData.selectedStudent && (
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
<h2 className="text-xl font-semibold mb-4">Liste des absences</h2>
<ul className="space-y-2">
{absences.map((absence, index) => (
<li
key={index}
className="flex justify-between items-center bg-gray-50 p-4 rounded-md border border-gray-100"
>
<span className="text-gray-800">{absence.date}</span>
<span className="text-gray-500 italic">{absence.reason}</span>
</li>
))}
</ul>
</div>
)}
{/* Bilan de compétence */}
{formData.selectedStudent && (
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
<h2 className="text-xl font-semibold mb-4">Bilan de compétence</h2>
<Table
data={formData.competenceReview}
columns={[
{
name: 'Compétence',
transform: (row) => row.competence,
},
{
name: '1',
transform: (row, index) => (
<input
type="radio"
name={`score-${index}`}
value="1"
checked={row.score === '1'}
onChange={() => handleScoreChange(index, '1')}
/>
),
},
{
name: '2',
transform: (row, index) => (
<input
type="radio"
name={`score-${index}`}
value="2"
checked={row.score === '2'}
onChange={() => handleScoreChange(index, '2')}
/>
),
},
{
name: '3',
transform: (row, index) => (
<input
type="radio"
name={`score-${index}`}
value="3"
checked={row.score === '3'}
onChange={() => handleScoreChange(index, '3')}
/>
),
},
]}
/>
<div className="mt-4">
<Button
text="Enregistrer"
onClick={() => console.log('FormData:', formData)}
primary
className="bg-emerald-500 text-white hover:bg-emerald-600"
/>
</div>
</div>
)}
</div> </div>
); );
} }

View File

@ -70,7 +70,7 @@ export default function Layout({ children }) {
}, },
grades: { grades: {
id: 'grades', id: 'grades',
name: t('grades'), name: t('educational_monitoring'),
url: FE_ADMIN_GRADES_URL, url: FE_ADMIN_GRADES_URL,
icon: Award, icon: Award,
}, },

View File

@ -6,11 +6,9 @@ const CheckBox = ({
handleChange, handleChange,
fieldName, fieldName,
itemLabelFunc = () => null, itemLabelFunc = () => null,
labelAttenuated = () => false,
horizontal, horizontal,
}) => { }) => {
const isChecked = formData[fieldName].includes(parseInt(item.id)); const isChecked = formData[fieldName].includes(parseInt(item.id));
const isAttenuated = labelAttenuated(item) && !isChecked;
return ( return (
<div <div
key={item.id} key={item.id}
@ -19,7 +17,7 @@ const CheckBox = ({
{horizontal && ( {horizontal && (
<label <label
htmlFor={`${fieldName}-${item.id}`} htmlFor={`${fieldName}-${item.id}`}
className={`block text-sm text-center mb-1 ${isAttenuated ? 'text-gray-300' : 'font-bold text-emerald-600'}`} className="block text-sm text-center mb-1 font-medium text-gray-700"
> >
{itemLabelFunc(item)} {itemLabelFunc(item)}
</label> </label>
@ -37,7 +35,7 @@ const CheckBox = ({
{!horizontal && ( {!horizontal && (
<label <label
htmlFor={`${fieldName}-${item.id}`} htmlFor={`${fieldName}-${item.id}`}
className={`block text-sm ${isAttenuated ? 'text-gray-300' : 'font-bold text-emerald-600'}`} className="block text-sm text-center mb-1 font-medium text-gray-700"
> >
{itemLabelFunc(item)} {itemLabelFunc(item)}
</label> </label>

View File

@ -1,42 +0,0 @@
import React from 'react';
import CheckBox from '@/components/CheckBox';
const CheckBoxList = ({
items,
formData,
handleChange,
fieldName,
label,
icon: Icon,
className,
itemLabelFunc = (item) => item.name,
labelAttenuated = () => false,
horizontal = false, // Ajouter l'option horizontal
}) => {
return (
<div className={`mb-4 w-full ${className}`}>
<label className="block text-sm font-medium text-gray-700 flex items-center">
{Icon && <Icon className="w-5 h-5 mr-2" />}
{label}
</label>
<div
className={`mt-2 grid ${horizontal ? 'grid-cols-6 gap-2' : 'grid-cols-1 gap-4'}`}
>
{items.map((item) => (
<CheckBox
key={`${fieldName}-${item.id}`}
item={item}
formData={formData}
handleChange={handleChange}
fieldName={fieldName}
itemLabelFunc={itemLabelFunc}
labelAttenuated={labelAttenuated}
horizontal={horizontal}
/>
))}
</div>
</div>
);
};
export default CheckBoxList;

View File

@ -12,6 +12,8 @@ import logger from '@/utils/logger';
import Popup from '@/components/Popup'; import Popup from '@/components/Popup';
import InputPhone from '../InputPhone'; import InputPhone from '../InputPhone';
import { PhoneLabel } from '../PhoneLabel'; import { PhoneLabel } from '../PhoneLabel';
import CheckBox from '@/components/CheckBox';
import RadioList from '@/components/RadioList';
const InscriptionForm = ({ const InscriptionForm = ({
students, students,
@ -547,27 +549,35 @@ const InscriptionForm = ({
{selectedStudent.first_name} : {selectedStudent.first_name} :
</h3> </h3>
{existingGuardians.map((guardian) => ( {existingGuardians.map((guardian) => (
<div key={guardian.id}> <div key={guardian.id} className="mt-2">
<label className="flex items-center space-x-3 mt-2"> <CheckBox
<input item={{ id: guardian.id }}
type="checkbox" formData={{
checked={formData.selectedGuardians.includes( selectedGuardians: formData.selectedGuardians,
guardian.id }}
)} handleChange={() =>
className="form-checkbox h-5 w-5 text-emerald-600" setFormData((prevData) => {
onChange={() => const isSelected =
handleResponsableSelection( prevData.selectedGuardians.includes(guardian.id);
guardian.id, const updatedSelectedGuardians = isSelected
guardian.associated_profile_email ? prevData.selectedGuardians.filter(
) (id) => id !== guardian.id
) // Retirer le guardian si décoché
: [...prevData.selectedGuardians, guardian.id]; // Ajouter le guardian si coché
return {
...prevData,
selectedGuardians: updatedSelectedGuardians,
};
})
}
fieldName="selectedGuardians"
itemLabelFunc={() =>
guardian.last_name && guardian.first_name
? `${guardian.last_name} ${guardian.first_name} - ${guardian.associated_profile_email}`
: `${guardian.associated_profile_email}`
} }
/> />
<span className="text-gray-900">
{guardian.last_name && guardian.first_name
? `${guardian.last_name} ${guardian.first_name} - ${guardian.associated_profile_email}`
: `${guardian.associated_profile_email}`}
</span>
</label>
</div> </div>
))} ))}
</div> </div>
@ -719,31 +729,28 @@ const InscriptionForm = ({
{groups.length > 0 ? ( {groups.length > 0 ? (
<div className="space-y-4"> <div className="space-y-4">
<h3 className="font-bold">Sélectionnez un groupe de documents</h3> <h3 className="font-bold">Sélectionnez un groupe de documents</h3>
{groups.map((group) => ( <RadioList
<div key={group.id} className="flex items-center space-x-3"> sectionLabel=""
<input items={groups.map((group) => ({
type="radio" id: group.id,
name="fileGroup" label: `${group.name}${
value={group.id} group.description ? ` (${group.description})` : ''
checked={formData.selectedFileGroup === group.id} }`,
onChange={(e) => }))}
setFormData({ formData={{
...formData, ...formData,
selectedFileGroup: parseInt(e.target.value), selectedFileGroup: parseInt(formData.selectedFileGroup, 10),
}) }}
} handleChange={(e) => {
className="form-radio h-4 w-4 text-emerald-600" const value = parseInt(e.target.value, 10);
setFormData((prevData) => ({
...prevData,
selectedFileGroup: value,
}));
}}
fieldName="selectedFileGroup"
className="mt-4"
/> />
<label className="text-gray-900">
{group.name}
{group.description && (
<span className="text-sm text-gray-500 ml-2">
({group.description})
</span>
)}
</label>
</div>
))}
</div> </div>
) : ( ) : (
<p <p
@ -752,7 +759,6 @@ const InscriptionForm = ({
> >
<strong className="font-bold">Attention!</strong> <strong className="font-bold">Attention!</strong>
<span className="block sm:inline"> <span className="block sm:inline">
{' '}
Aucun groupe de documents n&apos;a été créé. Aucun groupe de documents n&apos;a été créé.
</span> </span>
</p> </p>