feat: enhance team overview and skills tabs with improved skill distribution and UI

- Updated team overview tab to calculate and display skill distribution by individual skill levels.
- Refactored skill tab layout for better responsiveness and readability, including adjustments to grid and text sizes.
- Added a new utility function to calculate skill level distribution for cleaner code and reusability.
- Improved visual elements for better user interaction and clarity in skill metrics.
This commit is contained in:
Julien Froidefond
2025-08-22 13:59:51 +02:00
parent 8974a9b579
commit 5c76ec0549
3 changed files with 103 additions and 97 deletions

View File

@@ -1,6 +1,6 @@
"use client";
import { Star, BarChart3, Target } from "lucide-react";
import { BarChart3, Target, Star } from "lucide-react";
import { TeamStats } from "@/services/admin-service";
import { TechIcon } from "@/components/icons/tech-icon";
@@ -125,75 +125,74 @@ export function TeamOverviewTab({
<div className="bg-white/5 backdrop-blur-sm border border-white/10 rounded-2xl p-6">
<h3 className="text-lg font-semibold text-white mb-6 flex items-center gap-2">
<BarChart3 className="h-5 w-5 text-blue-400" />
Répartition des niveaux
Répartition des niveaux par compétence
</h3>
<div className="space-y-4">
{[
{
label: "Expert",
count: team.members.filter(
(m) =>
m.skills.reduce((avg, s) => avg + s.level, 0) /
m.skills.length >=
2.5
).length,
color: "bg-green-500",
},
{
label: "Avancé",
count: team.members.filter((m) => {
const avg =
m.skills.reduce((avg, s) => avg + s.level, 0) /
m.skills.length;
return avg >= 2 && avg < 2.5;
}).length,
color: "bg-blue-500",
},
{
label: "Intermédiaire",
count: team.members.filter((m) => {
const avg =
m.skills.reduce((avg, s) => avg + s.level, 0) /
m.skills.length;
return avg >= 1 && avg < 2;
}).length,
color: "bg-orange-500",
},
{
label: "Débutant",
count: team.members.filter(
(m) =>
m.skills.reduce((avg, s) => avg + s.level, 0) /
m.skills.length <
1
).length,
color: "bg-red-500",
},
].map((level, idx) => (
<div
key={idx}
className="flex items-center justify-between p-3 bg-white/5 rounded-lg"
>
<div className="flex items-center gap-3">
<div className={`w-3 h-3 rounded-full ${level.color}`} />
<span className="text-white font-medium">{level.label}</span>
</div>
<div className="flex items-center gap-3">
<span className="text-white font-bold">{level.count}</span>
<div className="w-16 bg-white/10 rounded-full h-2">
<div
className={`h-2 rounded-full ${level.color}`}
style={{
width: `${(level.count / team.totalMembers) * 100}%`,
}}
/>
{(() => {
// Calculer la répartition par compétence individuelle
const allSkills = team.members.flatMap((m) => m.skills);
const totalSkills = allSkills.length;
const levelDistribution = {
expert: allSkills.filter((s) => s.level === 3).length,
autonomous: allSkills.filter((s) => s.level === 2).length,
notAutonomous: allSkills.filter((s) => s.level === 1).length,
never: allSkills.filter((s) => s.level === 0).length,
};
return [
{
label: "Expert",
count: levelDistribution.expert,
total: totalSkills,
color: "bg-green-500",
},
{
label: "Autonome",
count: levelDistribution.autonomous,
total: totalSkills,
color: "bg-blue-500",
},
{
label: "Pas autonome",
count: levelDistribution.notAutonomous,
total: totalSkills,
color: "bg-orange-500",
},
{
label: "Jamais utilisé",
count: levelDistribution.never,
total: totalSkills,
color: "bg-red-500",
},
].map((level, idx) => (
<div
key={idx}
className="flex items-center justify-between p-3 bg-white/5 rounded-lg"
>
<div className="flex items-center gap-3">
<div className={`w-3 h-3 rounded-full ${level.color}`} />
<span className="text-white font-medium">
{level.label}
</span>
</div>
<div className="flex items-center gap-3">
<span className="text-white font-bold">{level.count}</span>
<div className="w-16 bg-white/10 rounded-full h-2">
<div
className={`h-2 rounded-full ${level.color}`}
style={{
width: `${(level.count / level.total) * 100}%`,
}}
/>
</div>
<span className="text-xs text-slate-400 w-10 text-right">
{((level.count / level.total) * 100).toFixed(0)}%
</span>
</div>
<span className="text-xs text-slate-400 w-10 text-right">
{((level.count / team.totalMembers) * 100).toFixed(0)}%
</span>
</div>
</div>
))}
));
})()}
</div>
</div>
@@ -221,16 +220,6 @@ export function TeamOverviewTab({
{teamInsights.totalLearners}
</span>
</div>
<div className="flex items-center justify-between p-3 bg-white/5 rounded-lg">
<span className="text-slate-300">Mentors disponibles</span>
<span className="text-white font-bold">
{skillAnalysis.reduce(
(sum, skill) =>
sum + skill.experts.filter((e) => e.canMentor).length,
0
)}
</span>
</div>
</div>
</div>
</div>