254 lines
9.4 KiB
TypeScript
254 lines
9.4 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Badge } from "@/components/ui/badge";
|
|
|
|
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 =
|
|
skill.importance === "incontournable"
|
|
? 75
|
|
: skill.importance === "majeure"
|
|
? 60
|
|
: 0;
|
|
const isUnderTarget = target > 0 && skill.coverage < target;
|
|
|
|
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>
|
|
</>
|
|
);
|
|
}
|