feat: CRUD admin for skills and teams
This commit is contained in:
192
components/admin/overview/direction-overview.tsx
Normal file
192
components/admin/overview/direction-overview.tsx
Normal file
@@ -0,0 +1,192 @@
|
||||
"use client";
|
||||
|
||||
import { Building2, Users, TrendingUp, BarChart3, Target } from "lucide-react";
|
||||
import {
|
||||
TeamStatsCard,
|
||||
getSkillLevelLabel,
|
||||
getSkillLevelColor,
|
||||
} from "../team-detail/team-stats-card";
|
||||
|
||||
interface DirectionOverviewProps {
|
||||
direction: string;
|
||||
teams: Array<{
|
||||
teamId: string;
|
||||
teamName: string;
|
||||
direction: string;
|
||||
totalMembers: number;
|
||||
averageSkillLevel: number;
|
||||
topSkills: Array<{ skillName: string; averageLevel: number }>;
|
||||
skillCoverage: number;
|
||||
}>;
|
||||
totalMembers: number;
|
||||
averageSkillLevel: number;
|
||||
topCategories: Array<{ category: string; averageLevel: number }>;
|
||||
onViewTeamDetails?: (team: any) => void;
|
||||
onExportTeamReport?: (team: any) => void;
|
||||
}
|
||||
|
||||
export function DirectionOverview({
|
||||
direction,
|
||||
teams,
|
||||
totalMembers,
|
||||
averageSkillLevel,
|
||||
topCategories,
|
||||
onViewTeamDetails = () => {},
|
||||
onExportTeamReport = () => {},
|
||||
}: DirectionOverviewProps) {
|
||||
return (
|
||||
<div className="bg-white/5 backdrop-blur-sm border border-white/10 rounded-2xl overflow-hidden">
|
||||
<div className="bg-white/5 border-b border-white/10 p-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="p-2 bg-purple-500/20 border border-purple-500/30 rounded-xl">
|
||||
<Building2 className="h-5 w-5 text-purple-400" />
|
||||
</div>
|
||||
<h2 className="text-xl font-bold text-white">
|
||||
Direction {direction}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center gap-2 px-3 py-2 bg-green-500/20 border border-green-500/30 rounded-xl">
|
||||
<Users className="h-3 w-3 text-green-400" />
|
||||
<span className="text-sm text-green-300 font-medium">
|
||||
{totalMembers}
|
||||
</span>
|
||||
</div>
|
||||
<div className="px-3 py-2 bg-blue-500/20 border border-blue-500/30 rounded-xl">
|
||||
<span className="text-sm text-blue-300 font-medium">
|
||||
Niveau: {getSkillLevelLabel(averageSkillLevel)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-6 space-y-6">
|
||||
{/* Direction Metrics */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
{/* Top Categories */}
|
||||
<div className="bg-white/5 border border-white/10 rounded-xl p-4">
|
||||
<div className="flex items-center gap-2 mb-4">
|
||||
<BarChart3 className="h-4 w-4 text-slate-400" />
|
||||
<h4 className="text-sm font-medium text-slate-300">
|
||||
Top Catégories
|
||||
</h4>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
{topCategories.slice(0, 4).map((cat, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
className="flex items-center justify-between p-2 bg-white/5 rounded-lg"
|
||||
>
|
||||
<span className="text-sm text-white">{cat.category}</span>
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className={`w-2 h-2 rounded-full ${getSkillLevelColor(
|
||||
cat.averageLevel
|
||||
)}`}
|
||||
/>
|
||||
<span className="text-xs font-medium text-slate-300 min-w-8 text-right">
|
||||
{cat.averageLevel.toFixed(1)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Overall Progress */}
|
||||
<div className="bg-white/5 border border-white/10 rounded-xl p-4">
|
||||
<div className="flex items-center gap-2 mb-4">
|
||||
<TrendingUp className="h-4 w-4 text-slate-400" />
|
||||
<h4 className="text-sm font-medium text-slate-300">
|
||||
Progression Globale
|
||||
</h4>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-sm text-slate-400">
|
||||
Maîtrise globale:
|
||||
</span>
|
||||
<span className="text-lg font-bold text-white">
|
||||
{((averageSkillLevel / 3) * 100).toFixed(0)}%
|
||||
</span>
|
||||
</div>
|
||||
<div className="w-full bg-white/10 rounded-full h-2">
|
||||
<div
|
||||
className="bg-gradient-to-r from-blue-500 to-blue-400 h-2 rounded-full transition-all"
|
||||
style={{ width: `${(averageSkillLevel / 3) * 100}%` }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="pt-2 text-xs text-slate-500">
|
||||
Basé sur {teams.length} équipes
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Team Distribution */}
|
||||
<div className="bg-white/5 border border-white/10 rounded-xl p-4">
|
||||
<div className="flex items-center gap-2 mb-4">
|
||||
<Target className="h-4 w-4 text-slate-400" />
|
||||
<h4 className="text-sm font-medium text-slate-300">
|
||||
Répartition
|
||||
</h4>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<div className="text-center">
|
||||
<div className="text-2xl font-bold text-white">
|
||||
{teams.length}
|
||||
</div>
|
||||
<div className="text-xs text-slate-400">équipes actives</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between text-xs">
|
||||
<span className="text-slate-400">Membres par équipe:</span>
|
||||
<span className="text-white font-medium">
|
||||
{(totalMembers / teams.length).toFixed(1)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between text-xs">
|
||||
<span className="text-slate-400">Équipes performantes:</span>
|
||||
<span className="text-white font-medium">
|
||||
{teams.filter((t) => t.averageSkillLevel > 2).length}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Teams Grid */}
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="p-2 bg-blue-500/20 border border-blue-500/30 rounded-xl">
|
||||
<Users className="h-4 w-4 text-blue-400" />
|
||||
</div>
|
||||
<h4 className="text-lg font-semibold text-white">
|
||||
Équipes de la direction
|
||||
</h4>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{teams.map((team) => (
|
||||
<TeamStatsCard
|
||||
key={team.teamId}
|
||||
teamId={team.teamId}
|
||||
teamName={team.teamName}
|
||||
direction={team.direction}
|
||||
totalMembers={team.totalMembers}
|
||||
averageSkillLevel={team.averageSkillLevel}
|
||||
topSkills={team.topSkills}
|
||||
skillCoverage={team.skillCoverage}
|
||||
onViewDetails={() => onViewTeamDetails(team)}
|
||||
onViewReport={() => onExportTeamReport(team)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user