Files
peakskills/components/admin/team-detail/team-detail-client-wrapper.tsx
2025-08-24 22:03:15 +02:00

201 lines
6.0 KiB
TypeScript

"use client";
import React, { useState, useEffect } from "react";
import { TeamStats, TeamMember } from "@/lib/admin-types";
import { TeamDetailHeader } from "./team-detail-header";
import { TeamMetricsCards } from "./team-metrics-cards";
import { TeamDetailTabs } from "./team-detail-tabs";
import { TeamMemberModal } from "@/components/admin";
interface TeamDetailClientWrapperProps {
team: TeamStats;
teamId: string;
}
interface SkillAnalysis {
skillName: string;
category: string;
experts: Array<{
name: string;
level: number;
canMentor: boolean;
}>;
learners: Array<{
name: string;
currentLevel: number;
}>;
averageLevel: number;
totalEvaluations: number;
expertCount: number;
learnerCount: number;
proficiencyRate: number;
}
interface TeamInsights {
averageTeamLevel: number;
totalExperts: number;
totalLearners: number;
skillGaps: number;
strongSkills: number;
}
export function TeamDetailClientWrapper({
team,
teamId,
}: TeamDetailClientWrapperProps) {
const [skillAnalysis, setSkillAnalysis] = useState<SkillAnalysis[]>([]);
const [selectedMember, setSelectedMember] = useState<TeamMember | null>(null);
const [isMemberModalOpen, setIsMemberModalOpen] = useState(false);
useEffect(() => {
// Analyser les compétences avec les vraies données
const skillMap = new Map<string, any>();
team.members.forEach((member) => {
member.skills.forEach((skill) => {
if (!skillMap.has(skill.skillName)) {
skillMap.set(skill.skillName, {
skillName: skill.skillName,
category: skill.category,
experts: [],
learners: [],
averageLevel: 0,
totalEvaluations: 0,
});
}
const skillData = skillMap.get(skill.skillName);
skillData.totalEvaluations++;
skillData.averageLevel += skill.level;
if (skill.level >= 2) {
skillData.experts.push({
name: `${member.firstName} ${member.lastName}`,
level: skill.level,
canMentor: skill.canMentor,
});
}
if (skill.wantsToLearn) {
skillData.learners.push({
name: `${member.firstName} ${member.lastName}`,
currentLevel: skill.level,
});
}
});
});
const skills = Array.from(skillMap.values())
.map(
(skill): SkillAnalysis => ({
...skill,
averageLevel: skill.averageLevel / skill.totalEvaluations,
expertCount: skill.experts.length,
learnerCount: skill.learners.length,
proficiencyRate:
(skill.experts.length / skill.totalEvaluations) * 100,
})
)
.sort((a, b) => b.averageLevel - a.averageLevel);
setSkillAnalysis(skills);
}, [team]);
const handleExportReport = () => {
const reportData = {
team: team.teamName,
direction: team.direction,
exportDate: new Date().toLocaleDateString(),
detailedStats: {
totalMembers: team.totalMembers,
averageSkillLevel: team.averageSkillLevel,
skillCoverage: team.skillCoverage,
},
members: team.members.map((member) => ({
name: `${member.firstName} ${member.lastName}`,
joinDate: member.joinDate,
skillCount: member.skills.length,
skills: member.skills,
})),
skillAnalysis,
};
const dataStr = JSON.stringify(reportData, null, 2);
const dataUri =
"data:application/json;charset=utf-8," + encodeURIComponent(dataStr);
const exportFileDefaultName = `rapport-detaille-${team.teamName.toLowerCase()}-${
new Date().toISOString().split("T")[0]
}.json`;
const linkElement = document.createElement("a");
linkElement.setAttribute("href", dataUri);
linkElement.setAttribute("download", exportFileDefaultName);
linkElement.click();
};
const teamInsights: TeamInsights = {
averageTeamLevel:
team.members.reduce((sum, member) => {
const memberAvg =
member.skills.reduce((s, skill) => s + skill.level, 0) /
member.skills.length;
return sum + memberAvg;
}, 0) / team.members.length,
totalExperts: team.members.reduce(
(sum, member) =>
sum + member.skills.filter((s) => s.level >= 2 && s.canMentor).length,
0
),
totalLearners: team.members.reduce(
(sum, member) => sum + member.skills.filter((s) => s.wantsToLearn).length,
0
),
skillGaps: skillAnalysis.filter((s) => s.averageLevel < 1.5).length,
strongSkills: skillAnalysis.filter((s) => s.averageLevel >= 2.5).length,
};
return (
<div className="min-h-screen bg-gradient-to-br from-slate-950 via-slate-900 to-slate-950 relative overflow-hidden">
{/* Background Effects */}
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_top,_var(--tw-gradient-stops))] from-blue-900/20 via-slate-900 to-slate-950" />
<div className="absolute inset-0 bg-grid-white/5 bg-[size:50px_50px]" />
<div className="absolute inset-0 bg-gradient-to-t from-slate-950 via-transparent to-transparent" />
<div className="relative z-10 container mx-auto px-6 py-8 max-w-7xl space-y-8">
{/* Header */}
<TeamDetailHeader
teamName={team.teamName}
direction={team.direction}
onExport={handleExportReport}
/>
{/* Métriques principales */}
<TeamMetricsCards
totalMembers={team.totalMembers}
teamInsights={teamInsights}
skillCoverage={team.skillCoverage}
/>
{/* Contenu principal avec onglets */}
<TeamDetailTabs
team={team}
skillAnalysis={skillAnalysis}
teamInsights={teamInsights}
onMemberClick={(member) => {
setSelectedMember(member);
setIsMemberModalOpen(true);
}}
/>
{/* Modal détail membre */}
<TeamMemberModal
isOpen={isMemberModalOpen}
onClose={() => setIsMemberModalOpen(false)}
member={selectedMember}
/>
</div>
</div>
);
}