diff --git a/components/admin/index.ts b/components/admin/index.ts index 85204b6..7fd7641 100644 --- a/components/admin/index.ts +++ b/components/admin/index.ts @@ -13,6 +13,3 @@ export * from "./team-detail"; // Composants utilitaires export * from "./utils"; - -// Gestion des utilisateurs -export { UsersManagement } from "./users-management"; diff --git a/components/admin/layout/manage-content-tabs.tsx b/components/admin/layout/manage-content-tabs.tsx index f548d10..41f8a8a 100644 --- a/components/admin/layout/manage-content-tabs.tsx +++ b/components/admin/layout/manage-content-tabs.tsx @@ -6,7 +6,7 @@ import { Team, SkillCategory } from "@/lib/types"; import { TeamStats, DirectionStats } from "@/services/admin-service"; import { SkillsManagement } from "../management/pages/skills-management"; import { TeamsManagement } from "../management/pages/teams-management"; -import { UsersManagement } from "../users-management"; +import { UsersManagement } from "../management/pages/users-management"; interface ManageContentTabsProps { teams: Team[]; diff --git a/components/admin/management/pages/index.ts b/components/admin/management/pages/index.ts index 5a86504..4488e85 100644 --- a/components/admin/management/pages/index.ts +++ b/components/admin/management/pages/index.ts @@ -1,3 +1,4 @@ // Composants de pages de gestion export { SkillsManagement } from "./skills-management"; export { TeamsManagement } from "./teams-management"; +export { UsersManagement } from "./users-management"; diff --git a/components/admin/users-management.tsx b/components/admin/management/pages/users-management.tsx similarity index 100% rename from components/admin/users-management.tsx rename to components/admin/management/pages/users-management.tsx diff --git a/components/admin/skills-management.tsx b/components/admin/skills-management.tsx deleted file mode 100644 index 9a160a2..0000000 --- a/components/admin/skills-management.tsx +++ /dev/null @@ -1,596 +0,0 @@ -"use client"; - -import { useState, useEffect, useMemo } from "react"; -import { - Plus, - Edit, - Trash2, - Code2, - Search, - Folder, - FolderOpen, - ChevronRight, - ChevronDown, - Palette, - Database, - Cloud, - Shield, - Smartphone, - Layers, -} from "lucide-react"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Card, CardContent, CardHeader, CardTitle } 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 { Textarea } from "@/components/ui/textarea"; -import { useToast } from "@/hooks/use-toast"; -import { SkillCategory, Team } from "@/lib/types"; -import { - AdminManagementService, - Skill, -} from "@/services/admin-management-service"; -import { TechIcon } from "@/components/icons/tech-icon"; -import { - TreeViewContainer, - TreeCategoryHeader, - TreeItemRow, - TreeSearchControls, -} from "@/components/admin"; - -interface SkillsManagementProps { - skillCategories: SkillCategory[]; - teams: Team[]; -} - -interface SkillFormData { - name: string; - categoryId: string; - description: string; - icon: string; -} - -export function SkillsManagement({ - skillCategories, - teams, -}: SkillsManagementProps) { - const [searchTerm, setSearchTerm] = useState(""); - const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false); - const [isEditDialogOpen, setIsEditDialogOpen] = useState(false); - const [editingSkill, setEditingSkill] = useState(null); - const [skillFormData, setSkillFormData] = useState({ - name: "", - categoryId: "", - description: "", - icon: "", - }); - const { toast } = useToast(); - - // État des skills - const [skills, setSkills] = useState([]); - const [isLoading, setIsLoading] = useState(true); - - // État pour les catégories ouvertes/fermées - const [expandedCategories, setExpandedCategories] = useState>( - new Set() - ); - - // Grouper les skills par catégorie et filtrer en fonction de la recherche - const filteredSkillsByCategory = useMemo(() => { - // Grouper les skills par catégorie - const skillsByCategory = skills.reduce((acc, skill) => { - if (!acc[skill.category]) { - acc[skill.category] = []; - } - acc[skill.category].push(skill); - return acc; - }, {} as Record); - - // Filtrer les skills en fonction de la recherche - return Object.entries(skillsByCategory).reduce( - (acc, [category, categorySkills]) => { - const filteredSkills = categorySkills.filter((skill) => { - const matchesSearch = - skill.name.toLowerCase().includes(searchTerm.toLowerCase()) || - (skill.description && - skill.description - .toLowerCase() - .includes(searchTerm.toLowerCase())); - return matchesSearch; - }); - - if (filteredSkills.length > 0) { - acc[category] = filteredSkills; - } - return acc; - }, - {} as Record - ); - }, [skills, searchTerm]); - - // Fonctions pour gérer l'expansion des catégories - const toggleCategory = useMemo( - () => (category: string) => { - setExpandedCategories((prev) => { - const newExpanded = new Set(prev); - if (newExpanded.has(category)) { - newExpanded.delete(category); - } else { - newExpanded.add(category); - } - return newExpanded; - }); - }, - [] - ); - - const expandAll = useMemo( - () => () => { - setExpandedCategories(new Set(Object.keys(filteredSkillsByCategory))); - }, - [filteredSkillsByCategory] - ); - - const collapseAll = useMemo( - () => () => { - setExpandedCategories(new Set()); - }, - [] - ); - - // Charger les skills depuis l'API - const fetchSkills = async () => { - try { - setIsLoading(true); - const skillsData = await AdminManagementService.getSkills(); - setSkills(skillsData); - } catch (error) { - console.error("Error fetching skills:", error); - toast({ - title: "Erreur", - description: "Impossible de charger les skills", - variant: "destructive", - }); - } finally { - setIsLoading(false); - } - }; - - // Charger les skills au montage du composant - useEffect(() => { - fetchSkills(); - }, []); - - // Ouvrir automatiquement les catégories qui contiennent des résultats lors de la recherche - useEffect(() => { - if (searchTerm.trim()) { - const categoriesWithResults = Object.keys(filteredSkillsByCategory); - setExpandedCategories(new Set(categoriesWithResults)); - } else { - // Si pas de recherche, fermer toutes les catégories - setExpandedCategories(new Set()); - } - }, [searchTerm, filteredSkillsByCategory]); - - const handleCreateSkill = async () => { - if (!skillFormData.name || !skillFormData.categoryId) { - toast({ - title: "Erreur", - description: "Veuillez remplir tous les champs obligatoires", - variant: "destructive", - }); - return; - } - - try { - const categoryIndex = parseInt(skillFormData.categoryId); - const category = skillCategories[categoryIndex]; - - const skillData = { - ...skillFormData, - category: category.category, - }; - - const newSkill = await AdminManagementService.createSkill(skillData); - setSkills([...skills, newSkill]); - setSkillFormData({ name: "", categoryId: "", description: "", icon: "" }); - setIsCreateDialogOpen(false); - - toast({ - title: "Succès", - description: "Skill créée avec succès", - }); - } catch (error: any) { - toast({ - title: "Erreur", - description: error.message || "Erreur lors de la création de la skill", - variant: "destructive", - }); - } - }; - - const handleEditSkill = (skill: any) => { - setEditingSkill(skill); - const categoryIndex = skillCategories.findIndex( - (cat) => cat.category === skill.category - ); - setSkillFormData({ - name: skill.name, - categoryId: categoryIndex !== -1 ? categoryIndex.toString() : "", - description: skill.description, - icon: skill.icon, - }); - setIsEditDialogOpen(true); - }; - - const handleUpdateSkill = async () => { - if (!editingSkill || !skillFormData.name || !skillFormData.categoryId) { - toast({ - title: "Erreur", - description: "Veuillez remplir tous les champs obligatoires", - variant: "destructive", - }); - return; - } - - try { - const categoryIndex = parseInt(skillFormData.categoryId); - const category = skillCategories[categoryIndex]; - - const skillData = { - id: editingSkill.id, - ...skillFormData, - category: category.category, - usageCount: editingSkill.usageCount, - }; - - const updatedSkill = await AdminManagementService.updateSkill(skillData); - - const updatedSkills = skills.map((skill) => - skill.id === editingSkill.id ? updatedSkill : skill - ); - - setSkills(updatedSkills); - setIsEditDialogOpen(false); - setEditingSkill(null); - setSkillFormData({ name: "", categoryId: "", description: "", icon: "" }); - - toast({ - title: "Succès", - description: "Skill mise à jour avec succès", - }); - } catch (error: any) { - toast({ - title: "Erreur", - description: - error.message || "Erreur lors de la mise à jour de la skill", - variant: "destructive", - }); - } - }; - - const handleDeleteSkill = async (skillId: string) => { - if ( - confirm( - "Êtes-vous sûr de vouloir supprimer cette skill ? Cette action est irréversible." - ) - ) { - try { - await AdminManagementService.deleteSkill(skillId); - setSkills(skills.filter((s) => s.id !== skillId)); - toast({ - title: "Succès", - description: "Skill supprimée avec succès", - }); - } catch (error: any) { - toast({ - title: "Erreur", - description: - error.message || "Erreur lors de la suppression de la skill", - variant: "destructive", - }); - } - } - }; - - const resetForm = () => { - setSkillFormData({ name: "", categoryId: "", description: "", icon: "" }); - }; - - // Fonction pour obtenir l'icône de la catégorie - const getCategoryIcon = (category: string) => { - const categoryName = category.toLowerCase(); - if (categoryName.includes("frontend") || categoryName.includes("front")) - return Code2; - if (categoryName.includes("backend") || categoryName.includes("back")) - return Layers; - if ( - categoryName.includes("design") || - categoryName.includes("ui") || - categoryName.includes("ux") - ) - return Palette; - if (categoryName.includes("data") || categoryName.includes("database")) - return Database; - if (categoryName.includes("cloud") || categoryName.includes("devops")) - return Cloud; - if (categoryName.includes("security") || categoryName.includes("securité")) - return Shield; - if ( - categoryName.includes("mobile") || - categoryName.includes("android") || - categoryName.includes("ios") - ) - return Smartphone; - return Code2; // Par défaut - }; - - return ( -
- {/* Header */} -
-
-

Gestion des Skills

-

- Créez, modifiez et supprimez les skills de votre organisation -

-
- - - - - - - Créer une nouvelle skill - -
-
- - - setSkillFormData({ ...skillFormData, name: e.target.value }) - } - placeholder="Ex: React, Node.js, PostgreSQL" - /> -
-
- - -
-
- -