feat: my team page

This commit is contained in:
Julien Froidefond
2025-08-27 10:53:11 +02:00
parent b7e6fa257e
commit c7a5b25501
11 changed files with 1529 additions and 0 deletions

View File

@@ -0,0 +1,166 @@
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { TeamReviewData } from "@/lib/team-review-types";
import { Progress } from "@/components/ui/progress";
import { Badge } from "@/components/ui/badge";
import { AlertTriangle } from "lucide-react";
interface TeamOverviewProps {
team: TeamReviewData["team"];
stats: TeamReviewData["stats"];
members: TeamReviewData["members"];
categoryCoverage: TeamReviewData["categoryCoverage"];
}
export function TeamOverview({
team,
stats,
members,
categoryCoverage,
}: TeamOverviewProps) {
// Trouver les top contributeurs
const topContributors = [...members]
.sort((a, b) => b.expertSkills - a.expertSkills)
.slice(0, 3);
// Trouver les catégories les plus fortes
const strongestCategories = [...categoryCoverage]
.sort((a, b) => b.coverage - a.coverage)
.slice(0, 2);
// Trouver les catégories qui nécessitent de l'attention
const categoriesNeedingAttention = [...categoryCoverage]
.filter((cat) => {
// Une catégorie nécessite de l'attention si :
// - Couverture faible (< 40%)
// - OU pas assez d'experts (< 2) avec une équipe de taille significative (> 5)
// - OU beaucoup d'apprenants (> 30% de l'équipe) avec peu de mentors (< 2)
return (
cat.coverage < 40 ||
(cat.experts < 2 && stats.totalMembers > 5) ||
(cat.learners > stats.totalMembers * 0.3 && cat.mentors < 2)
);
})
.sort((a, b) => {
// Prioriser les catégories avec le plus de besoins
const aScore = a.learners * 2 - a.mentors - a.experts;
const bScore = b.learners * 2 - b.mentors - b.experts;
return bScore - aScore;
})
.slice(0, 2);
return (
<Card className="bg-white/5 border-white/10 backdrop-blur">
<CardHeader>
<CardTitle className="text-slate-200">Vue d'ensemble</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{/* Points forts */}
<div>
<h3 className="text-sm font-medium text-slate-200 mb-4">
Points forts
</h3>
<div className="space-y-4">
{strongestCategories.map((cat) => (
<div key={cat.category} className="space-y-2">
<div className="flex justify-between items-center">
<p className="text-sm font-medium text-slate-300">
{cat.category}
</p>
<span className="text-sm text-slate-400">
{cat.coverage.toFixed(0)}%
</span>
</div>
<Progress value={cat.coverage} className="bg-white/10" />
<p className="text-xs text-slate-400">
{cat.experts} experts • {cat.mentors} mentors
</p>
</div>
))}
</div>
</div>
{/* Top contributeurs */}
<div>
<h3 className="text-sm font-medium text-slate-200 mb-4">
Top contributeurs
</h3>
<div className="space-y-4">
{topContributors.map((member) => (
<div key={member.member.uuid} className="space-y-1">
<p className="text-sm font-medium text-slate-300">
{member.member.firstName} {member.member.lastName}
</p>
<div className="flex gap-2 text-xs">
<Badge
variant="secondary"
className="bg-white/10 text-slate-300 border-white/20"
>
{member.expertSkills} expertises
</Badge>
{member.mentorSkills > 0 && (
<Badge
variant="outline"
className="text-slate-300 border-white/20"
>
{member.mentorSkills} mentorats
</Badge>
)}
</div>
</div>
))}
</div>
</div>
{/* Points d'attention */}
<div>
<h3 className="text-sm font-medium flex items-center gap-2 text-amber-400 mb-4">
<AlertTriangle size={16} />
Besoins prioritaires
</h3>
<div className="space-y-4">
{categoriesNeedingAttention.map((cat) => (
<div key={cat.category} className="space-y-2">
<div className="flex justify-between items-center">
<p className="text-sm font-medium text-slate-300">
{cat.category}
</p>
<div className="flex items-center gap-2">
<Badge
variant="outline"
className="text-amber-400 border-amber-400/30"
>
{cat.learners} apprenants
</Badge>
</div>
</div>
<div className="flex items-center gap-4 text-sm text-slate-400">
<span>{cat.experts} experts</span>
<span>{cat.mentors} mentors</span>
</div>
<div className="text-xs text-amber-400/80">
{cat.coverage < 40 && "Couverture insuffisante • "}
{cat.experts < 2 &&
stats.totalMembers > 5 &&
"Manque d'experts • "}
{cat.learners > stats.totalMembers * 0.3 &&
cat.mentors < 2 &&
"Besoin de mentors"}
</div>
</div>
))}
{stats.learningNeeds > 0 && (
<div className="pt-2 border-t border-white/10">
<p className="text-sm text-amber-400 flex items-center gap-2">
<AlertTriangle size={16} />
{stats.learningNeeds} compétences sans expert ni mentor
</p>
</div>
)}
</div>
</div>
</div>
</CardContent>
</Card>
);
}