diff --git a/components/admin/management/index.ts b/components/admin/management/index.ts index 1cf9a19..95cea69 100644 --- a/components/admin/management/index.ts +++ b/components/admin/management/index.ts @@ -4,3 +4,6 @@ export { TreeCategoryHeader } from "./tree-category-header"; export { TreeItemRow } from "./tree-item-row"; export { TreeSearchControls } from "./tree-search-controls"; export { TeamMetrics } from "./team-metrics"; + +// Composant de base pour les pages de gestion +export { TreeViewPage } from "./tree-view-page"; diff --git a/components/admin/management/pages/skills-management.tsx b/components/admin/management/pages/skills-management.tsx index 9a160a2..c5af58f 100644 --- a/components/admin/management/pages/skills-management.tsx +++ b/components/admin/management/pages/skills-management.tsx @@ -1,16 +1,11 @@ "use client"; -import { useState, useEffect, useMemo } from "react"; +import { useState, useEffect } from "react"; import { Plus, Edit, Trash2, Code2, - Search, - Folder, - FolderOpen, - ChevronRight, - ChevronDown, Palette, Database, Cloud, @@ -20,15 +15,6 @@ import { } 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, @@ -38,6 +24,13 @@ import { SelectValue, } from "@/components/ui/select"; import { Textarea } from "@/components/ui/textarea"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; import { useToast } from "@/hooks/use-toast"; import { SkillCategory, Team } from "@/lib/types"; import { @@ -46,11 +39,12 @@ import { } from "@/services/admin-management-service"; import { TechIcon } from "@/components/icons/tech-icon"; import { - TreeViewContainer, TreeCategoryHeader, TreeItemRow, - TreeSearchControls, } from "@/components/admin"; +import { TreeViewPage } from "../tree-view-page"; +import { useTreeView } from "@/hooks/use-tree-view"; +import { useFormDialog } from "@/hooks/use-form-dialog"; interface SkillsManagementProps { skillCategories: SkillCategory[]; @@ -69,8 +63,6 @@ export function SkillsManagement({ 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: "", @@ -79,78 +71,26 @@ export function SkillsManagement({ icon: "", }); const { toast } = useToast(); + const { isCreateDialogOpen, isEditDialogOpen, openCreateDialog, closeCreateDialog, openEditDialog, closeEditDialog } = useFormDialog(); // É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()); - }, - [] - ); + // Utilisation du hook factorisé + const { + filteredDataByCategory: filteredSkillsByCategory, + expandedCategories, + toggleCategory, + expandAll, + collapseAll, + } = useTreeView({ + data: skills, + searchFields: ['name', 'description'], + groupBy: (skill) => skill.category, + searchTerm, + onSearchChange: setSearchTerm, + }); // Charger les skills depuis l'API const fetchSkills = async () => { @@ -175,17 +115,6 @@ export function SkillsManagement({ 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({ @@ -208,7 +137,7 @@ export function SkillsManagement({ const newSkill = await AdminManagementService.createSkill(skillData); setSkills([...skills, newSkill]); setSkillFormData({ name: "", categoryId: "", description: "", icon: "" }); - setIsCreateDialogOpen(false); + closeCreateDialog(); toast({ title: "Succès", @@ -234,7 +163,7 @@ export function SkillsManagement({ description: skill.description, icon: skill.icon, }); - setIsEditDialogOpen(true); + openEditDialog(); }; const handleUpdateSkill = async () => { @@ -265,7 +194,7 @@ export function SkillsManagement({ ); setSkills(updatedSkills); - setIsEditDialogOpen(false); + closeEditDialog(); setEditingSkill(null); setSkillFormData({ name: "", categoryId: "", description: "", icon: "" }); @@ -339,126 +268,119 @@ export function SkillsManagement({ 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" + /> +
+
+ + +
+
+ +