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". + ), + }} + /> + { setOpen(false); setEditingCategory(null); }} fullWidth> {editingCategory ? 'Edit Category' : 'Add Category'}