mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
159 lines
6.0 KiB
JavaScript
159 lines
6.0 KiB
JavaScript
import React, { useState, useMemo, useEffect } from 'react';
|
|
import { BookOpen, CheckCircle, AlertCircle, Clock } from 'lucide-react';
|
|
import RadioList from '@/components/Form/RadioList';
|
|
|
|
const LEVELS = [
|
|
{ value: 0, label: 'Non évalué' },
|
|
{ value: 1, label: '1 - Non acquis' },
|
|
{ value: 2, label: "2 - En cours d'acquisition" },
|
|
{ value: 3, label: '3 - Acquis' },
|
|
];
|
|
|
|
const getGradeStyle = (grade) => {
|
|
switch (grade) {
|
|
case 1:
|
|
return 'bg-red-50 border-red-200';
|
|
case 2:
|
|
return 'bg-yellow-50 border-yellow-200';
|
|
case 3:
|
|
return 'bg-emerald-50 border-emerald-200';
|
|
default:
|
|
return 'bg-gray-50 border-gray-200';
|
|
}
|
|
};
|
|
|
|
export default function GradeView({ data, grades, onGradeChange }) {
|
|
const [openDomains, setOpenDomains] = useState({});
|
|
const [openCategories, setOpenCategories] = useState({});
|
|
|
|
// Initialiser tout ouvert au premier rendu ou quand data change
|
|
useEffect(() => {
|
|
if (data && data.length > 0) {
|
|
// Initialisation des domaines et catégories (collapsed)
|
|
const domains = {};
|
|
const categories = {};
|
|
data.forEach((domaine) => {
|
|
domains[domaine.domaine_id] = false;
|
|
domaine.categories.forEach((cat) => {
|
|
categories[cat.categorie_id] = false;
|
|
});
|
|
});
|
|
setOpenDomains(domains);
|
|
setOpenCategories(categories);
|
|
}
|
|
}, [data]);
|
|
|
|
// Calcul du nombre total de compétences
|
|
const totalCompetencies = useMemo(
|
|
() =>
|
|
(data || []).reduce(
|
|
(sum, domaine) =>
|
|
sum +
|
|
domaine.categories.reduce(
|
|
(catSum, cat) => catSum + cat.competences.length,
|
|
0
|
|
),
|
|
0
|
|
),
|
|
[data]
|
|
);
|
|
|
|
if (!data) return null;
|
|
|
|
const toggleDomain = (id) =>
|
|
setOpenDomains((prev) => ({ ...prev, [id]: !prev[id] }));
|
|
|
|
const toggleCategory = (id) =>
|
|
setOpenCategories((prev) => ({ ...prev, [id]: !prev[id] }));
|
|
|
|
return (
|
|
<div className="w-full">
|
|
<div className="mb-4 mr-4 text-right text-emerald-700 font-semibold">
|
|
{totalCompetencies} compétence{totalCompetencies > 1 ? 's' : ''} au
|
|
total
|
|
</div>
|
|
{data.map((domaine) => (
|
|
<div key={domaine.domaine_id} className="mb-8">
|
|
<div
|
|
className={
|
|
'flex items-center justify-between cursor-pointer px-6 py-4 rounded-lg transition bg-emerald-50 border border-emerald-200 shadow-sm hover:bg-emerald-100'
|
|
}
|
|
onClick={() => toggleDomain(domaine.domaine_id)}
|
|
>
|
|
<div className="flex items-center gap-3">
|
|
<BookOpen className="w-7 h-7 text-emerald-600" />
|
|
<span className="text-2xl font-bold text-emerald-800">
|
|
{domaine.domaine_nom}
|
|
</span>
|
|
</div>
|
|
<span className="text-emerald-700 text-xl">
|
|
{openDomains[domaine.domaine_id] ? '▼' : '►'}
|
|
</span>
|
|
</div>
|
|
{openDomains[domaine.domaine_id] && (
|
|
<div className="mt-4">
|
|
{domaine.categories.map((categorie) => (
|
|
<div key={categorie.categorie_id} className="mb-10 mr-4">
|
|
<button
|
|
type="button"
|
|
className="flex items-center gap-2 text-lg font-semibold text-emerald-700 mb-4 hover:underline"
|
|
onClick={() => toggleCategory(categorie.categorie_id)}
|
|
>
|
|
{openCategories[categorie.categorie_id] ? '▼' : '►'}{' '}
|
|
{categorie.categorie_nom}
|
|
</button>
|
|
{openCategories[categorie.categorie_id] && (
|
|
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-8 w-full">
|
|
{categorie.competences.map((competence) => {
|
|
const grade = grades[competence.competence_id];
|
|
return (
|
|
<div
|
|
key={competence.competence_id}
|
|
className={`border rounded-xl p-6 flex flex-col shadow transition hover:shadow-md ${getGradeStyle(grade)}`}
|
|
>
|
|
<div className="mb-4 pb-4 border-b border-emerald-800 flex items-center min-h-[48px]">
|
|
<span className="text-gray-900 font-semibold text-base">
|
|
{competence.nom}
|
|
</span>
|
|
</div>
|
|
<div className="flex-1 flex items-center">
|
|
<RadioList
|
|
key={`grade-${competence.competence_id}-${grades[competence.competence_id] ?? 0}`}
|
|
items={LEVELS.map(({ value, label }) => ({
|
|
id: value,
|
|
label,
|
|
}))}
|
|
formData={{
|
|
[`grade-${competence.competence_id}`]:
|
|
grades[competence.competence_id] !==
|
|
undefined
|
|
? grades[competence.competence_id]
|
|
: 0,
|
|
}}
|
|
handleChange={(e) =>
|
|
onGradeChange(
|
|
competence.competence_id,
|
|
parseInt(e.target.value, 10)
|
|
)
|
|
}
|
|
fieldName={`grade-${competence.competence_id}`}
|
|
disabled={competence.state === 'required'}
|
|
className="mt-2"
|
|
/>
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
<hr className="my-6 border-emerald-100" />
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|