diff --git a/src/private/categories/AddOrEditCategoryForm.jsx b/src/private/categories/AddOrEditCategoryForm.jsx
index 2a9cacf..c6938b3 100644
--- a/src/private/categories/AddOrEditCategoryForm.jsx
+++ b/src/private/categories/AddOrEditCategoryForm.jsx
@@ -38,6 +38,7 @@ export default function AddOrEditCategoryForm({ onAdd, initialData, onCancel })
const [form, setForm] = useState({
_Id: '',
id: '',
+ tenantId: '',
tagName: '',
typeId: '',
parentTagId: [],
@@ -45,6 +46,10 @@ export default function AddOrEditCategoryForm({ onAdd, initialData, onCancel })
displayOrder: 0,
icon: '',
status: 'Active',
+ createdAt: null,
+ createdBy: null,
+ updatedAt: null,
+ updatedBy: null,
});
// cargar tipos y tags para selects
@@ -68,6 +73,7 @@ export default function AddOrEditCategoryForm({ onAdd, initialData, onCancel })
setForm({
_Id,
id,
+ tenantId: initialData.tenantId || extractTenantId(token) || '',
tagName: initialData.tagName || initialData.name || '',
typeId: initialData.typeId || '',
parentTagId: Array.isArray(initialData.parentTagId) ? initialData.parentTagId : [],
@@ -75,11 +81,16 @@ export default function AddOrEditCategoryForm({ onAdd, initialData, onCancel })
displayOrder: Number(initialData.displayOrder ?? 0),
icon: initialData.icon || '',
status: initialData.status || 'Active',
+ createdAt: initialData.createdAt ?? null,
+ createdBy: initialData.createdBy ?? null,
+ updatedAt: initialData.updatedAt ?? null,
+ updatedBy: initialData.updatedBy ?? null,
});
} else {
setForm({
_Id: '',
id: '',
+ tenantId: extractTenantId(token) || '',
tagName: '',
typeId: '',
parentTagId: [],
@@ -87,6 +98,10 @@ export default function AddOrEditCategoryForm({ onAdd, initialData, onCancel })
displayOrder: 0,
icon: '',
status: 'Active',
+ createdAt: null,
+ createdBy: null,
+ updatedAt: null,
+ updatedBy: null,
});
}
}, [initialData]);
@@ -140,12 +155,44 @@ export default function AddOrEditCategoryForm({ onAdd, initialData, onCancel })
}
};
+ const handleDelete = async () => {
+ try {
+ // Try to use Mongo _Id (24-hex); if not present, fall back to GUID `id`.
+ const hex = typeof form._Id === 'string' && /^[0-9a-f]{24}$/i.test(form._Id) ? form._Id : null;
+ const idToUse = hex || form.id;
+ if (!idToUse) throw new Error('Missing id to delete');
+ await api.changeStatus({ id: idToUse, status: 'Inactive' });
+ onAdd?.();
+ } catch (e) {
+ console.error('Delete category failed:', e);
+ alert(e.message || 'Delete failed');
+ }
+ };
+
return (
{form._Id ? 'Edit Category' : 'Add Category'}
+ {/* IDs (read-only) */}
+ {form._Id || form.id ? (
+
+
+
+
+ ) : null}
+
+ {/* Tenant (read-only; comes from token or existing record) */}
+
+
Inactive
-
-
-
+ {form._Id || form.id ? (
+
+
+
+
+
+
+ ) : null}
+
+
+ { (form._Id || form.id) ? (
+
+ ) : }
+
+
+
+
);
diff --git a/src/private/categories/Categories.jsx b/src/private/categories/Categories.jsx
index 5f023c5..a774237 100644
--- a/src/private/categories/Categories.jsx
+++ b/src/private/categories/Categories.jsx
@@ -2,8 +2,8 @@ import { useEffect, useMemo, useRef, useState } from 'react';
import { Box, Button, Dialog, DialogContent, DialogTitle, IconButton, Typography,
ToggleButton, ToggleButtonGroup } from '@mui/material';
import { DataGrid } from '@mui/x-data-grid';
-import EditIcon from '@mui/icons-material/Edit';
-import DeleteIcon from '@mui/icons-material/Delete';
+import EditRoundedIcon from '@mui/icons-material/EditRounded';
+import DeleteRoundedIcon from '@mui/icons-material/DeleteRounded';
import AddOrEditCategoryForm from './AddOrEditCategoryForm';
import CategoriesApi from '../../api/CategoriesApi';
import { useAuth } from '../../context/AuthContext';
@@ -14,7 +14,7 @@ export default function Categories() {
const api = useMemo(() => new CategoriesApi(token), [token]);
const [rows, setRows] = useState([]);
- const [statusFilter, setStatusFilter] = useState('Active'); // <- por defecto Active
+ const [statusFilter, setStatusFilter] = useState('All'); // <- por defecto All
const [open, setOpen] = useState(false);
const [editingCategory, setEditingCategory] = useState(null);
const [confirmOpen, setConfirmOpen] = useState(false);
@@ -31,13 +31,8 @@ export default function Categories() {
const loadData = async () => {
try {
const data = await api.getAll();
- const safeRows = (Array.isArray(data) ? data : [])
- .filter(Boolean)
- .map((r, idx) => ({
- ...r,
- __rid: r?._id || r?._Id || r?.id || r?.Id || `tmp-${idx}`,
- }));
- setRows(safeRows);
+ const list = Array.isArray(data) ? data : [];
+ setRows(list);
} catch (e) {
console.error('Failed to load categories:', e);
setRows([]);
@@ -110,48 +105,79 @@ export default function Categories() {
}, [rows, statusFilter]);
const columns = [
- {
- field: 'tagName',
- headerName: 'Name',
- flex: 1,
- minWidth: 200,
- valueGetter: (p) => p?.row?.tagName ?? p?.row?.name ?? '',
- },
- {
- field: 'slug',
- headerName: 'Slug',
- width: 180,
- valueGetter: (p) => p?.row?.slug ?? '',
- },
- {
- field: 'displayOrder',
- headerName: 'Display',
- width: 120,
- valueGetter: (p) => Number(p?.row?.displayOrder ?? 0),
- },
- {
- field: 'status',
- headerName: 'Status',
- width: 140,
- valueGetter: (p) => p?.row?.status ?? 'Active',
- },
{
field: 'actions',
headerName: '',
- width: 120,
+ width: 130,
sortable: false,
filterable: false,
- renderCell: (params) => {
- const r = params?.row;
- if (!r) return null;
- return (
-
- handleEditClick(params)}>
- handleDeleteClick(r)}>
-
- );
+ disableExport: true,
+ renderCell: (params) => (
+
+ handleEditClick(params)}
+ >
+
+
+ handleDeleteClick(params?.row)}
+ >
+
+
+
+ ),
+ },
+ { field: 'tenantId', headerName: 'tenantId', width: 180 },
+ { field: 'tagName', headerName: 'tagName', width: 200 },
+ { field: 'typeId', headerName: 'typeId', width: 260 },
+ {
+ field: 'parentTagId',
+ headerName: 'parentTagId',
+ width: 220,
+ valueGetter: (params) => Array.isArray(params.value) ? params.value.join(', ') : (params.value ?? '—'),
+ },
+ { field: 'slug', headerName: 'slug', width: 180 },
+ { field: 'displayOrder', headerName: 'displayOrder', width: 140, type: 'number' },
+ { field: 'icon', headerName: 'icon', width: 160 },
+ { field: '_id', headerName: '_id', width: 260 },
+ { field: 'id', headerName: 'id', width: 280 },
+ {
+ field: 'createdAt',
+ headerName: 'createdAt',
+ width: 200,
+ valueFormatter: (p) => {
+ const v = p?.value;
+ return v ? new Date(v).toLocaleString() : '—';
},
},
+ { field: 'createdBy', headerName: 'createdBy', width: 180 },
+ {
+ field: 'updatedAt',
+ headerName: 'updatedAt',
+ width: 200,
+ valueFormatter: (p) => {
+ const v = p?.value;
+ return v ? new Date(v).toLocaleString() : '—';
+ },
+ },
+ { field: 'updatedBy', headerName: 'updatedBy', width: 180 },
+ { field: 'status', headerName: 'status', width: 140 },
];
return (
@@ -177,15 +203,29 @@ export default function Categories() {
- r?.__rid}
- />
+
+ r?._id || r?.id}
+ sx={{
+ minWidth: 1400,
+ '& .MuiDataGrid-cell, & .MuiDataGrid-columnHeader': {
+ display: 'flex',
+ alignItems: 'center',
+ },
+ }}
+ slots={{
+ noRowsOverlay: () => (
+ No categories found. Try switching the status filter to "All".
+ ),
+ }}
+ />
+