"use client"; import { useState, useEffect, useMemo } from "react"; import { Plus, Edit, Trash2, Users, Search, Building2 } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Card, CardContent } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { useToast } from "@/hooks/use-toast"; import { SkillCategory, Team as TeamType } from "@/lib/types"; import { TeamStats } from "@/services/admin-service"; import { AdminManagementService, Team, } from "@/services/admin-management-service"; import { TreeViewContainer, TreeCategoryHeader, TreeItemRow, TreeSearchControls, TeamMetrics, } from "@/components/admin"; interface TeamsManagementProps { teams: TeamType[]; teamStats: TeamStats[]; skillCategories: SkillCategory[]; } interface TeamFormData { name: string; direction: string; } export function TeamsManagement({ teams, teamStats, skillCategories, }: TeamsManagementProps) { const [searchTerm, setSearchTerm] = useState(""); const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false); const [isEditDialogOpen, setIsEditDialogOpen] = useState(false); const [editingTeam, setEditingTeam] = useState(null); const [teamFormData, setTeamFormData] = useState({ name: "", direction: "", }); const { toast } = useToast(); // État pour les directions ouvertes/fermées const [expandedDirections, setExpandedDirections] = useState>( new Set() ); // État pour gérer la liste des équipes // Grouper les teams par direction et filtrer en fonction de la recherche const filteredTeamsByDirection = useMemo(() => { // Grouper les teams par direction const teamsByDirection = teams.reduce((acc, team) => { if (!acc[team.direction]) { acc[team.direction] = []; } acc[team.direction].push(team); return acc; }, {} as Record); // Filtrer les teams en fonction de la recherche return Object.entries(teamsByDirection).reduce( (acc, [direction, directionTeams]) => { const filteredTeams = directionTeams.filter((team) => { const matchesSearch = team.name .toLowerCase() .includes(searchTerm.toLowerCase()); return matchesSearch; }); if (filteredTeams.length > 0) { acc[direction] = filteredTeams; } return acc; }, {} as Record ); }, [teams, searchTerm]); // Fonctions pour gérer l'expansion des directions const toggleDirection = useMemo( () => (direction: string) => { setExpandedDirections((prev) => { const newExpanded = new Set(prev); if (newExpanded.has(direction)) { newExpanded.delete(direction); } else { newExpanded.add(direction); } return newExpanded; }); }, [] ); const expandAll = useMemo( () => () => { setExpandedDirections(new Set(Object.keys(filteredTeamsByDirection))); }, [filteredTeamsByDirection] ); const collapseAll = useMemo( () => () => { setExpandedDirections(new Set()); }, [] ); const getTeamStats = (teamId: string) => { return teamStats.find((stats) => stats.teamId === teamId); }; // Charger les teams depuis l'API const fetchTeams = async () => { try { const teamsData = await AdminManagementService.getTeams(); // Note: on garde les teams existantes pour la compatibilité // Les nouvelles teams créées via l'API seront visibles après rafraîchissement } catch (error) { console.error("Error fetching teams:", error); toast({ title: "Erreur", description: "Impossible de charger les teams", variant: "destructive", }); } }; // Charger les teams au montage du composant useEffect(() => { fetchTeams(); }, []); // Ouvrir automatiquement les directions qui contiennent des résultats lors de la recherche useEffect(() => { if (searchTerm.trim()) { const directionsWithResults = Object.keys(filteredTeamsByDirection); setExpandedDirections(new Set(directionsWithResults)); } else { // Si pas de recherche, fermer toutes les directions setExpandedDirections(new Set()); } }, [searchTerm, filteredTeamsByDirection]); const handleCreateTeam = async () => { if (!teamFormData.name || !teamFormData.direction) { toast({ title: "Erreur", description: "Veuillez remplir tous les champs obligatoires", variant: "destructive", }); return; } try { const newTeam = await AdminManagementService.createTeam(teamFormData); toast({ title: "Succès", description: "Équipe créée avec succès", }); setTeamFormData({ name: "", direction: "" }); setIsCreateDialogOpen(false); // Rafraîchir la page pour voir les changements window.location.reload(); } catch (error: any) { toast({ title: "Erreur", description: error.message || "Erreur lors de la création de l'équipe", variant: "destructive", }); } }; const handleEditTeam = (team: any) => { setEditingTeam(team); setTeamFormData({ name: team.name, direction: team.direction, }); setIsEditDialogOpen(true); }; const handleUpdateTeam = async () => { if (!editingTeam || !teamFormData.name || !teamFormData.direction) { toast({ title: "Erreur", description: "Veuillez remplir tous les champs obligatoires", variant: "destructive", }); return; } try { await AdminManagementService.updateTeam({ id: editingTeam.id, ...teamFormData, memberCount: editingTeam.memberCount || 0, }); toast({ title: "Succès", description: "Équipe mise à jour avec succès", }); setIsEditDialogOpen(false); setEditingTeam(null); setTeamFormData({ name: "", direction: "" }); // Rafraîchir la page pour voir les changements window.location.reload(); } catch (error: any) { toast({ title: "Erreur", description: error.message || "Erreur lors de la mise à jour de l'équipe", variant: "destructive", }); } }; const handleDeleteTeam = async (teamId: string) => { const team = teams.find((t) => t.id === teamId); const stats = getTeamStats(teamId); if (stats && stats.totalMembers > 0) { toast({ title: "Erreur", description: "Impossible de supprimer une équipe qui contient des membres", variant: "destructive", }); return; } if ( confirm( `Êtes-vous sûr de vouloir supprimer l'équipe "${team?.name}" ? Cette action est irréversible.` ) ) { try { await AdminManagementService.deleteTeam(teamId); toast({ title: "Succès", description: "Équipe supprimée avec succès", }); // Rafraîchir la page pour voir les changements window.location.reload(); } catch (error: any) { toast({ title: "Erreur", description: error.message || "Erreur lors de la suppression de l'équipe", variant: "destructive", }); } } }; const handleDeleteDirection = async (direction: string) => { // Vérifier si des équipes de cette direction ont des membres const teamsInDirection = teams.filter( (team) => team.direction === direction ); const hasMembers = teamsInDirection.some((team) => { const stats = getTeamStats(team.id); return stats && stats.totalMembers > 0; }); if (hasMembers) { toast({ title: "Erreur", description: `Impossible de supprimer la direction "${direction}" car certaines équipes ont des membres`, variant: "destructive", }); return; } if ( confirm( `Êtes-vous sûr de vouloir supprimer la direction "${direction}" et TOUTES ses équipes ?\n\n⚠️ Cette action est irréversible !\n\nÉquipes qui seront supprimées :\n${teamsInDirection .map((t) => `• ${t.name}`) .join("\n")}` ) ) { try { await AdminManagementService.deleteDirection(direction); toast({ title: "Succès", description: `Direction "${direction}" et toutes ses équipes supprimées avec succès`, variant: "default", }); // Rafraîchir la page pour voir les changements window.location.reload(); } catch (error: any) { toast({ title: "Erreur", description: error.message || "Erreur lors de la suppression de la direction", variant: "destructive", }); } } }; const resetForm = () => { setTeamFormData({ name: "", direction: "" }); }; // Extraire les directions uniques pour les formulaires const directions = Array.from(new Set(teams.map((team) => team.direction))); return (
{/* Header */}

Gestion des Teams

Créez, modifiez et supprimez les équipes de votre organisation

Créer une nouvelle équipe
setTeamFormData({ ...teamFormData, name: e.target.value }) } placeholder="Ex: Équipe Frontend, Équipe Backend" />
{/* Filtres et contrôles */} {/* Vue arborescente des Teams */} 0} emptyState={

{searchTerm ? "Aucune équipe trouvée" : "Aucune équipe"}

{searchTerm ? "Essayez de modifier vos critères de recherche" : "Commencez par créer votre première équipe"}

} > {Object.entries(filteredTeamsByDirection).map( ([direction, directionTeams], index) => (
toggleDirection(direction)} icon={} itemCount={directionTeams.length} itemLabel="équipe" showSeparator={index > 0} onDelete={() => handleDeleteDirection(direction)} canDelete={true} isDirection={true} /> {/* Liste des teams de la direction */} {expandedDirections.has(direction) && (
{directionTeams.map((team, teamIndex) => { const stats = getTeamStats(team.id); return ( } title={team.name} badges={ stats ? [ { text: `${stats.totalMembers} membres`, variant: "outline", }, ] : [] } onEdit={() => handleEditTeam(team)} onDelete={() => handleDeleteTeam(team.id)} canDelete={!stats || stats.totalMembers === 0} showSeparator={teamIndex > 0} additionalInfo={ stats ? ( ) : (

Aucune donnée disponible

) } /> ); })}
)}
) )}
{/* Dialog d'édition */} Modifier l'équipe
setTeamFormData({ ...teamFormData, name: e.target.value }) } placeholder="Ex: Équipe Frontend, Équipe Backend" />
); }