feat: add team members functionality and modal

- Introduced `onViewMembers` prop in `TreeItemRow` to handle viewing team members.
- Added `TeamMembersModal` to display members of a selected team.
- Implemented state management for team members in `TeamsManagement`, including fetching and updating stats.
- Enhanced `AdminManagementService` with methods to fetch and remove team members.
This commit is contained in:
Julien Froidefond
2025-08-22 09:28:52 +02:00
parent 7ad970c73c
commit c0e2b9533b
5 changed files with 445 additions and 4 deletions

View File

@@ -35,6 +35,7 @@ import {
TreeSearchControls,
TeamMetrics,
} from "@/components/admin";
import { TeamMembersModal } from "@/components/admin/management/team-members-modal";
interface TeamsManagementProps {
teams: TeamType[];
@@ -55,6 +56,8 @@ export function TeamsManagement({
const [searchTerm, setSearchTerm] = useState("");
const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
const [isMembersModalOpen, setIsMembersModalOpen] = useState(false);
const [selectedTeam, setSelectedTeam] = useState<any>(null);
const [editingTeam, setEditingTeam] = useState<any>(null);
const [teamFormData, setTeamFormData] = useState<TeamFormData>({
name: "",
@@ -67,7 +70,8 @@ export function TeamsManagement({
new Set()
);
// État pour gérer la liste des équipes
// État local pour les stats des équipes
const [localTeamStats, setLocalTeamStats] = useState<TeamStats[]>(teamStats);
// Grouper les teams par direction et filtrer en fonction de la recherche
const filteredTeamsByDirection = useMemo(() => {
@@ -129,8 +133,8 @@ export function TeamsManagement({
[]
);
const getTeamStats = (teamId: string) => {
return teamStats.find((stats) => stats.teamId === teamId);
const getTeamStats = (teamId: string): TeamStats | undefined => {
return localTeamStats.find((stats) => stats.teamId === teamId);
};
// Charger les teams depuis l'API
@@ -149,6 +153,18 @@ export function TeamsManagement({
}
};
// Rafraîchir les stats des équipes depuis l'API des équipes
const refreshTeamStats = async () => {
try {
const teamsData = await AdminManagementService.getTeams();
// Fusionner avec les stats existantes pour préserver les métriques
const updatedStats = mergeTeamStats(localTeamStats, teamsData);
setLocalTeamStats(updatedStats);
} catch (error) {
console.error("Error refreshing team stats:", error);
}
};
// Charger les teams au montage du composant
useEffect(() => {
fetchTeams();
@@ -205,6 +221,41 @@ export function TeamsManagement({
setIsEditDialogOpen(true);
};
const handleViewMembers = (team: any) => {
setSelectedTeam(team);
setIsMembersModalOpen(true);
};
// Fonction pour mettre à jour les stats d'une équipe après suppression d'un membre
const updateTeamStatsAfterMemberRemoval = (teamId: string) => {
setLocalTeamStats((prev) =>
prev.map((stats) =>
stats.teamId === teamId
? { ...stats, totalMembers: Math.max(0, stats.totalMembers - 1) }
: stats
)
);
};
// Fonction pour fusionner les stats existantes avec les nouvelles données
const mergeTeamStats = (existingStats: TeamStats[], newTeams: Team[]) => {
return newTeams.map((team) => {
const existingStat = existingStats.find(
(stat) => stat.teamId === team.id
);
return {
teamId: team.id,
teamName: team.name,
direction: team.direction,
totalMembers: team.memberCount,
averageSkillLevel: existingStat?.averageSkillLevel || 0,
skillCoverage: existingStat?.skillCoverage || 0,
topSkillsCount: existingStat?.topSkillsCount || 0,
topSkills: existingStat?.topSkills || [],
};
});
};
const handleUpdateTeam = async () => {
if (!editingTeam || !teamFormData.name || !teamFormData.direction) {
toast({
@@ -466,8 +517,10 @@ export function TeamsManagement({
}
onEdit={() => handleEditTeam(team)}
onDelete={() => handleDeleteTeam(team.id)}
onViewMembers={() => handleViewMembers(team)}
canDelete={!stats || stats.totalMembers === 0}
showSeparator={teamIndex > 0}
hasMembers={stats ? stats.totalMembers > 0 : false}
additionalInfo={
stats ? (
<TeamMetrics
@@ -542,6 +595,27 @@ export function TeamsManagement({
</div>
</DialogContent>
</Dialog>
{/* Modal des membres d'équipe */}
{selectedTeam && (
<TeamMembersModal
teamId={selectedTeam.id}
teamName={selectedTeam.name}
isOpen={isMembersModalOpen}
onClose={() => {
setIsMembersModalOpen(false);
setSelectedTeam(null);
// Rafraîchir les stats depuis l'API pour s'assurer de la cohérence
refreshTeamStats();
}}
onMemberRemoved={() => {
// Mettre à jour les stats localement
if (selectedTeam) {
updateTeamStatsAfterMemberRemoval(selectedTeam.id);
}
}}
/>
)}
</div>
);
}