Files
SIG-CM/frontend/counter-panel/src/utils/categoryTreeUtils.ts
2025-12-23 15:12:57 -03:00

92 lines
2.4 KiB
TypeScript

import { type Category } from '../types/Category';
// Interfaz para la categoría "Aplanada" y enriquecida para UI
export interface FlatCategory {
id: number;
name: string;
level: number;
parentId: number | null;
path: string; // "Vehículos > Autos"
isSelectable: boolean; // True si no tiene hijos (es hoja)
hasChildren: boolean;
}
// Interfaz auxiliar para el árbol
interface CategoryNode extends Category {
children: CategoryNode[];
}
/**
* Convierte una lista plana de BD en un árbol recursivo
*/
export const buildTree = (categories: Category[]): CategoryNode[] => {
const map = new Map<number, CategoryNode>();
const roots: CategoryNode[] = [];
// 1. Inicializar nodos
categories.forEach(cat => {
map.set(cat.id, { ...cat, children: [] });
});
// 2. Construir relaciones
categories.forEach(cat => {
const node = map.get(cat.id);
if (node) {
if (cat.parentId && map.has(cat.parentId)) {
map.get(cat.parentId)!.children.push(node);
} else {
roots.push(node);
}
}
});
return roots;
};
/**
* Aplana el árbol para usarlo en Selects/Autocompletes
* Calcula breadcrumbs y deshabilita padres
*/
export const flattenCategoriesForSelect = (
nodes: CategoryNode[],
level = 0,
parentPath = ""
): FlatCategory[] => {
let result: FlatCategory[] = [];
// Ordenar alfabéticamente para facilitar búsqueda visual
const sortedNodes = [...nodes].sort((a, b) => a.name.localeCompare(b.name));
for (const node of sortedNodes) {
const currentPath = parentPath ? `${parentPath} > ${node.name}` : node.name;
const hasChildren = node.children && node.children.length > 0;
// Agregamos el nodo actual
result.push({
id: node.id,
name: node.name,
level: level,
parentId: node.parentId || null,
path: currentPath,
hasChildren: hasChildren,
// REGLA DE ORO: Solo seleccionable si NO tiene hijos
isSelectable: !hasChildren
});
// Recursión para los hijos
if (hasChildren) {
const childrenFlat = flattenCategoriesForSelect(node.children, level + 1, currentPath);
result = [...result, ...childrenFlat];
}
}
return result;
};
/**
* Función Helper que hace todo el proceso desde la respuesta de la API
*/
export const processCategories = (rawCategories: Category[]): FlatCategory[] => {
const tree = buildTree(rawCategories);
return flattenCategoriesForSelect(tree);
};