refactor: managements pages simplification
This commit is contained in:
20
hooks/use-form-dialog.ts
Normal file
20
hooks/use-form-dialog.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { useState, useCallback } from "react";
|
||||
|
||||
export function useFormDialog() {
|
||||
const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);
|
||||
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
|
||||
|
||||
const openCreateDialog = useCallback(() => setIsCreateDialogOpen(true), []);
|
||||
const closeCreateDialog = useCallback(() => setIsCreateDialogOpen(false), []);
|
||||
const openEditDialog = useCallback(() => setIsEditDialogOpen(true), []);
|
||||
const closeEditDialog = useCallback(() => setIsEditDialogOpen(false), []);
|
||||
|
||||
return {
|
||||
isCreateDialogOpen,
|
||||
isEditDialogOpen,
|
||||
openCreateDialog,
|
||||
closeCreateDialog,
|
||||
openEditDialog,
|
||||
closeEditDialog,
|
||||
};
|
||||
}
|
||||
89
hooks/use-tree-view.ts
Normal file
89
hooks/use-tree-view.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { useState, useEffect, useMemo, useCallback } from "react";
|
||||
|
||||
interface UseTreeViewOptions<T> {
|
||||
data: T[];
|
||||
searchFields: (keyof T)[];
|
||||
groupBy: (item: T) => string;
|
||||
searchTerm: string;
|
||||
onSearchChange: (term: string) => void;
|
||||
}
|
||||
|
||||
export function useTreeView<T>({
|
||||
data,
|
||||
searchFields,
|
||||
groupBy,
|
||||
searchTerm,
|
||||
onSearchChange,
|
||||
}: UseTreeViewOptions<T>) {
|
||||
// État pour les catégories ouvertes/fermées
|
||||
const [expandedCategories, setExpandedCategories] = useState<Set<string>>(new Set());
|
||||
|
||||
// Grouper les données par catégorie et filtrer en fonction de la recherche
|
||||
const filteredDataByCategory = useMemo(() => {
|
||||
// Grouper les données par catégorie
|
||||
const dataByCategory = data.reduce((acc, item) => {
|
||||
const categoryKey = groupBy(item);
|
||||
if (!acc[categoryKey]) {
|
||||
acc[categoryKey] = [];
|
||||
}
|
||||
acc[categoryKey].push(item);
|
||||
return acc;
|
||||
}, {} as Record<string, T[]>);
|
||||
|
||||
// Filtrer les données en fonction de la recherche
|
||||
return Object.entries(dataByCategory).reduce((acc, [category, categoryItems]) => {
|
||||
const filteredItems = categoryItems.filter((item) => {
|
||||
const matchesSearch = searchFields.some((field) => {
|
||||
const value = item[field];
|
||||
if (typeof value === 'string') {
|
||||
return value.toLowerCase().includes(searchTerm.toLowerCase());
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return matchesSearch;
|
||||
});
|
||||
|
||||
if (filteredItems.length > 0) {
|
||||
acc[category] = filteredItems;
|
||||
}
|
||||
return acc;
|
||||
}, {} as Record<string, T[]>);
|
||||
}, [data, searchFields, groupBy, searchTerm]);
|
||||
|
||||
// Fonctions pour gérer l'expansion des catégories
|
||||
const toggleCategory = useCallback((category: string) => {
|
||||
setExpandedCategories((prev) => {
|
||||
const newExpanded = new Set(prev);
|
||||
if (newExpanded.has(category)) {
|
||||
newExpanded.delete(category);
|
||||
} else {
|
||||
newExpanded.add(category);
|
||||
}
|
||||
return newExpanded;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const expandAll = useCallback(() => {
|
||||
setExpandedCategories(new Set(Object.keys(filteredDataByCategory)));
|
||||
}, [filteredDataByCategory]);
|
||||
|
||||
const collapseAll = useCallback(() => {
|
||||
setExpandedCategories(new Set());
|
||||
}, []);
|
||||
|
||||
// Ouvrir automatiquement les catégories qui contiennent des résultats lors de la recherche
|
||||
useEffect(() => {
|
||||
if (searchTerm.trim()) {
|
||||
const categoriesWithResults = Object.keys(filteredDataByCategory);
|
||||
setExpandedCategories(new Set(categoriesWithResults));
|
||||
}
|
||||
}, [searchTerm, filteredDataByCategory]);
|
||||
|
||||
return {
|
||||
filteredDataByCategory,
|
||||
expandedCategories,
|
||||
toggleCategory,
|
||||
expandAll,
|
||||
collapseAll,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user