Files
peakskills/components/admin/team-detail/team-skills-tab.tsx
2025-08-27 14:31:05 +02:00

256 lines
9.4 KiB
TypeScript

"use client";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import {
COVERAGE_OBJECTIVES,
isCoverageBelowObjective,
} from "@/lib/evaluation-utils";
interface SkillAnalysis {
skillName: string;
category: string;
importance: "incontournable" | "majeure" | "standard";
experts: Array<{
name: string;
level: number;
canMentor: boolean;
}>;
learners: Array<{
name: string;
currentLevel: number;
}>;
averageLevel: number;
totalEvaluations: number;
expertCount: number;
learnerCount: number;
proficiencyRate: number;
coverage: number;
}
interface TeamSkillsTabProps {
skillAnalysis: SkillAnalysis[];
}
function getSkillLevelLabel(level: number): string {
if (level < 0.5) return "Débutant";
if (level < 1.5) return "Intermé.";
if (level < 2.5) return "Avancé";
return "Expert";
}
function getSkillLevelColor(level: number): string {
if (level < 0.5) return "bg-red-500";
if (level < 1.5) return "bg-orange-500";
if (level < 2.5) return "bg-blue-500";
return "bg-green-500";
}
function getSkillLevelBadgeClasses(level: number): string {
if (level < 0.5) return "bg-red-500/20 border-red-500/30 text-red-300";
if (level < 1.5)
return "bg-orange-500/20 border-orange-500/30 text-orange-300";
if (level < 2.5) return "bg-blue-500/20 border-blue-500/30 text-blue-300";
return "bg-green-500/20 border-green-500/30 text-green-300";
}
export function TeamSkillsTab({ skillAnalysis }: TeamSkillsTabProps) {
const [selectedCategory, setSelectedCategory] = useState<string>("all");
const categories = Array.from(new Set(skillAnalysis.map((s) => s.category)));
const filteredSkills =
selectedCategory === "all"
? skillAnalysis
: skillAnalysis.filter((s) => s.category === selectedCategory);
return (
<>
{/* Filtres par catégorie */}
<div className="bg-white/5 backdrop-blur-sm border border-white/10 rounded-2xl p-4">
<div className="flex flex-wrap gap-2">
<Button
variant={selectedCategory === "all" ? "default" : "ghost"}
size="sm"
onClick={() => setSelectedCategory("all")}
className={
selectedCategory === "all"
? "bg-blue-500 text-white"
: "text-slate-400 hover:text-white hover:bg-white/10"
}
>
Toutes ({skillAnalysis.length})
</Button>
{categories.map((category) => (
<Button
key={category}
variant={selectedCategory === category ? "default" : "ghost"}
size="sm"
onClick={() => setSelectedCategory(category)}
className={
selectedCategory === category
? "bg-blue-500 text-white"
: "text-slate-400 hover:text-white hover:bg-white/10"
}
>
{category} (
{skillAnalysis.filter((s) => s.category === category).length})
</Button>
))}
</div>
</div>
{/* Liste des compétences détaillée */}
<div className="bg-white/5 backdrop-blur-sm border border-white/10 rounded-2xl">
<div className="overflow-hidden">
<table className="w-full">
<thead>
<tr className="border-b border-white/10">
<th className="text-left py-2 px-4 text-xs font-medium text-slate-400">
Compétence
</th>
<th className="text-center py-2 px-2 text-xs font-medium text-slate-400">
Niveau
</th>
<th className="text-center py-2 px-2 text-xs font-medium text-slate-400">
Experts
</th>
<th className="text-center py-2 px-2 text-xs font-medium text-slate-400">
Appren.
</th>
<th className="text-center py-2 px-2 text-xs font-medium text-slate-400">
Couv.
</th>
<th className="text-center py-2 px-4 text-xs font-medium text-slate-400">
Mentors
</th>
</tr>
</thead>
<tbody>
{filteredSkills.map((skill, idx) => {
const target = COVERAGE_OBJECTIVES[skill.importance];
const isUnderTarget = isCoverageBelowObjective(
skill.coverage,
skill.importance
);
return (
<tr
key={idx}
className={`border-b border-white/5 hover:bg-white/5 ${
skill.importance === "incontournable"
? "bg-red-500/5"
: skill.importance === "majeure"
? "bg-blue-500/5"
: ""
}`}
>
<td className="py-2 px-4">
<div className="flex items-center gap-2">
<div
className={`w-1 h-6 rounded-sm ${
skill.importance === "incontournable"
? "bg-red-500"
: skill.importance === "majeure"
? "bg-blue-500"
: "bg-slate-500"
}`}
/>
<div>
<div className="text-sm text-slate-200">
{skill.skillName}
</div>
<div className="text-xs text-slate-400">
{skill.category}
</div>
</div>
</div>
</td>
<td className="py-2 px-2">
<div className="flex items-center justify-center gap-2">
<div
className={`text-sm font-medium ${getSkillLevelBadgeClasses(
skill.averageLevel
)}`}
>
{skill.averageLevel.toFixed(1)}
</div>
<div className="w-12 bg-white/10 rounded-full h-1">
<div
className={`h-1 rounded-full ${getSkillLevelColor(
skill.averageLevel
)}`}
style={{
width: `${(skill.averageLevel / 3) * 100}%`,
}}
/>
</div>
</div>
</td>
<td className="py-2 px-2 text-center">
<span className="text-sm text-green-400 font-medium">
{skill.expertCount}
</span>
</td>
<td className="py-2 px-2 text-center">
<span className="text-sm text-blue-400 font-medium">
{skill.learnerCount}
</span>
</td>
<td className="py-2 px-2">
<div className="flex items-center justify-center gap-2">
<div
className={`text-sm font-medium ${
isUnderTarget ? "text-red-400" : "text-green-400"
}`}
>
{skill.coverage.toFixed(0)}%
</div>
<div className="w-12 bg-white/10 rounded-full h-1">
<div
className={`h-1 rounded-full ${
isUnderTarget ? "bg-red-500" : "bg-green-500"
}`}
style={{ width: `${skill.coverage}%` }}
/>
</div>
</div>
</td>
<td className="py-2 px-4">
<div className="flex items-center justify-center gap-1">
{skill.experts
.filter((e) => e.canMentor)
.slice(0, 2)
.map((expert, i) => (
<Badge
key={i}
variant="outline"
className="text-[10px] text-green-300 border-green-500/30 px-1"
>
{expert.name.split(" ")[0]}
</Badge>
))}
{skill.experts.filter((e) => e.canMentor).length >
2 && (
<Badge
variant="outline"
className="text-[10px] text-slate-400 border-slate-500/30 px-1"
>
+
{skill.experts.filter((e) => e.canMentor).length -
2}
</Badge>
)}
</div>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
</div>
</>
);
}