feat: review admin overview and popup details fwith importance

This commit is contained in:
Julien Froidefond
2025-08-27 13:16:39 +02:00
parent 94a18b0ca5
commit e9aecca2a5
5 changed files with 415 additions and 82 deletions

View File

@@ -28,8 +28,14 @@ interface TeamDetailModalProps {
skillName: string;
averageLevel: number;
icon?: string;
importance: "incontournable" | "majeure" | "standard";
coverage: number;
}>;
skillCoverage: number;
criticalSkillsCoverage: {
incontournable: number;
majeure: number;
};
members: TeamMember[];
} | null;
}
@@ -113,27 +119,88 @@ export function TeamDetailModal({
<div className="space-y-6">
{/* Stats générales */}
<div className="grid grid-cols-3 gap-4">
<div className="bg-white/5 border border-white/10 rounded-xl p-4 text-center">
<Users className="h-6 w-6 text-green-400 mx-auto mb-2" />
<div className="text-2xl font-bold text-white">
{team.totalMembers}
<div className="grid grid-cols-2 gap-4">
<div className="bg-white/5 border border-white/10 rounded-xl p-4">
<h3 className="text-sm font-medium text-slate-300 mb-3">
Équipe
</h3>
<div className="flex items-center gap-4">
<div className="flex-1 flex items-center gap-3">
<Users className="h-5 w-5 text-green-400" />
<div>
<div className="text-lg font-bold text-white">
{team.totalMembers}
</div>
<div className="text-xs text-slate-400">Membres</div>
</div>
</div>
<div className="flex-1 flex items-center gap-3">
<Eye className="h-5 w-5 text-blue-400" />
<div>
<div className="text-lg font-bold text-white">
{((team.averageSkillLevel / 3) * 100).toFixed(0)}%
</div>
<div className="text-xs text-slate-400">Niveau moyen</div>
</div>
</div>
</div>
<div className="text-xs text-slate-400">Membres</div>
</div>
<div className="bg-white/5 border border-white/10 rounded-xl p-4 text-center">
<Eye className="h-6 w-6 text-blue-400 mx-auto mb-2" />
<div className="text-2xl font-bold text-white">
{((team.averageSkillLevel / 3) * 100).toFixed(0)}%
<div className="bg-white/5 border border-white/10 rounded-xl p-4">
<h3 className="text-sm font-medium text-slate-300 mb-3">
Couverture
</h3>
<div className="space-y-3">
<div className="flex items-center justify-between">
<span className="text-sm text-slate-300">
Incontournables
</span>
<span
className={`text-sm font-bold ${
team.criticalSkillsCoverage.incontournable < 75
? "text-red-400"
: "text-green-400"
}`}
>
{team.criticalSkillsCoverage.incontournable.toFixed(0)}%
</span>
</div>
<div className="w-full bg-slate-700/50 rounded-full h-1.5">
<div
className={`h-1.5 rounded-full transition-all ${
team.criticalSkillsCoverage.incontournable < 75
? "bg-red-500"
: "bg-green-500"
}`}
style={{
width: `${team.criticalSkillsCoverage.incontournable}%`,
}}
/>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-slate-300">Majeures</span>
<span
className={`text-sm font-bold ${
team.criticalSkillsCoverage.majeure < 60
? "text-red-400"
: "text-green-400"
}`}
>
{team.criticalSkillsCoverage.majeure.toFixed(0)}%
</span>
</div>
<div className="w-full bg-slate-700/50 rounded-full h-1.5">
<div
className={`h-1.5 rounded-full transition-all ${
team.criticalSkillsCoverage.majeure < 60
? "bg-red-500"
: "bg-green-500"
}`}
style={{ width: `${team.criticalSkillsCoverage.majeure}%` }}
/>
</div>
</div>
<div className="text-xs text-slate-400">Niveau moyen</div>
</div>
<div className="bg-white/5 border border-white/10 rounded-xl p-4 text-center">
<ExternalLink className="h-6 w-6 text-orange-400 mx-auto mb-2" />
<div className="text-2xl font-bold text-white">
{team.skillCoverage.toFixed(0)}%
</div>
<div className="text-xs text-slate-400">Couverture</div>
</div>
</div>
@@ -141,24 +208,65 @@ export function TeamDetailModal({
<div className="bg-white/5 border border-white/10 rounded-xl p-4">
<h3 className="font-medium text-white mb-3">Top 3 Compétences</h3>
<div className="space-y-2">
{team.topSkills.slice(0, 3).map((skill, idx) => (
<div
key={idx}
className="flex items-center justify-between p-2 bg-white/5 rounded-lg"
>
<span className="text-white text-sm">{skill.skillName}</span>
<div className="flex items-center gap-2">
<span className="text-xs text-slate-400">
{((skill.averageLevel / 3) * 100).toFixed(0)}%
</span>
<div
className={`w-2 h-2 rounded-full ${getSkillLevelColor(
skill.averageLevel
)}`}
/>
{team.topSkills.slice(0, 3).map((skill, idx) => {
const target =
skill.importance === "incontournable"
? 75
: skill.importance === "majeure"
? 60
: 0;
const isUnderTarget = target > 0 && skill.coverage < target;
return (
<div
key={idx}
className="flex items-center justify-between p-2 bg-white/5 rounded-lg"
>
<div className="flex items-center gap-2">
<span className="text-white text-sm">
{skill.skillName}
</span>
<Badge
variant="outline"
className={
skill.importance === "incontournable"
? "border-red-500/30 text-red-400 text-[10px]"
: skill.importance === "majeure"
? "border-blue-500/30 text-blue-400 text-[10px]"
: "border-slate-500/30 text-slate-400 text-[10px]"
}
>
{skill.importance === "incontournable"
? "Incontournable"
: skill.importance === "majeure"
? "Majeure"
: "Standard"}
</Badge>
</div>
<div className="flex items-center gap-3">
<div className="flex items-center gap-1">
<span
className={`text-xs ${
isUnderTarget ? "text-red-400" : "text-green-400"
}`}
>
{skill.coverage.toFixed(0)}%
</span>
{target > 0 && (
<span className="text-[10px] text-slate-500">
(obj. {target}%)
</span>
)}
</div>
<div
className={`w-2 h-2 rounded-full ${getSkillLevelColor(
skill.averageLevel
)}`}
/>
</div>
</div>
</div>
))}
);
})}
</div>
</div>