Fase 2: Gestión de Atributos Dinámicos (Back & Front EAV Definition)
This commit is contained in:
@@ -108,6 +108,43 @@ export default function CategoryManager() {
|
||||
setSelectedCategoryOps(catOps);
|
||||
};
|
||||
|
||||
const handleConfigureAttributes = async (category: Category) => {
|
||||
setConfiguringCategory(category);
|
||||
setIsAttrModalOpen(true);
|
||||
loadAttributes(category.id);
|
||||
};
|
||||
|
||||
const loadAttributes = async (categoryId: number) => {
|
||||
const attrs = await attributeService.getByCategoryId(categoryId);
|
||||
setAttributes(attrs);
|
||||
};
|
||||
|
||||
const handleCreateAttribute = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (!configuringCategory || !newAttrData.name) return;
|
||||
|
||||
try {
|
||||
await attributeService.create({
|
||||
...newAttrData,
|
||||
categoryId: configuringCategory.id
|
||||
});
|
||||
setNewAttrData({ name: '', dataType: 'text', required: false });
|
||||
loadAttributes(configuringCategory.id);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteAttribute = async (id: number) => {
|
||||
if (!confirm('Eliminar atributo?')) return;
|
||||
try {
|
||||
await attributeService.delete(id);
|
||||
if (configuringCategory) loadAttributes(configuringCategory.id);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
const toggleOperation = async (opId: number, isChecked: boolean) => {
|
||||
if (!configuringCategory) return;
|
||||
|
||||
@@ -154,6 +191,15 @@ export default function CategoryManager() {
|
||||
<span className="flex-1">{node.name}</span>
|
||||
|
||||
<div className="flex gap-2 opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
{/* Attributes Button */}
|
||||
<button
|
||||
onClick={() => handleConfigureAttributes(node)}
|
||||
className="p-1 text-orange-600 hover:bg-orange-100 rounded"
|
||||
title="Atributos Dinámicos"
|
||||
>
|
||||
<LayoutList size={16} />
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() => handleConfigureOps(node)}
|
||||
className="p-1 text-purple-600 hover:bg-purple-100 rounded"
|
||||
|
||||
18
frontend/admin-panel/src/services/attributeService.ts
Normal file
18
frontend/admin-panel/src/services/attributeService.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import api from './api';
|
||||
import { AttributeDefinition } from '../types/AttributeDefinition';
|
||||
|
||||
export const attributeService = {
|
||||
getByCategoryId: async (categoryId: number): Promise<AttributeDefinition[]> => {
|
||||
const response = await api.get<AttributeDefinition[]>(`/attributedefinitions/category/${categoryId}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
create: async (attribute: Partial<AttributeDefinition>): Promise<AttributeDefinition> => {
|
||||
const response = await api.post<AttributeDefinition>('/attributedefinitions', attribute);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
delete: async (id: number): Promise<void> => {
|
||||
await api.delete(`/attributedefinitions/${id}`);
|
||||
}
|
||||
};
|
||||
7
frontend/admin-panel/src/types/AttributeDefinition.ts
Normal file
7
frontend/admin-panel/src/types/AttributeDefinition.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export interface AttributeDefinition {
|
||||
id: number;
|
||||
categoryId: number;
|
||||
name: string;
|
||||
dataType: 'text' | 'number' | 'boolean' | 'date';
|
||||
required: boolean;
|
||||
}
|
||||
Reference in New Issue
Block a user