chore: load TagType and materials, show in the gridview and the edit

This commit is contained in:
Rodolfo Ruiz
2025-09-04 21:16:00 -06:00
parent d699af9d75
commit aa62b06c23
2 changed files with 102 additions and 36 deletions

View File

@@ -1,4 +1,3 @@
// src/private/categories/AddOrEditCategoryForm.jsx
import { useEffect, useMemo, useState } from 'react';
import { Box, Button, Paper, TextField, Typography, MenuItem, Chip } from '@mui/material';
import { useAuth } from '../../context/AuthContext';
@@ -18,16 +17,15 @@ function extractTenantId(token) {
const payload = jwtDecode(token);
const t = payload?.tenant;
if (Array.isArray(t)) {
// prefer a 24-hex string if present
const hex = t.find(x => typeof x === 'string' && /^[0-9a-f]{24}$/i.test(x));
return hex || (typeof t[0] === 'string' ? t[0] : '');
}
if (typeof t === 'string') return t;
} catch {}
} catch { }
return '';
}
export default function AddOrEditCategoryForm({ onAdd, initialData, onCancel }) {
export default function AddOrEditCategoryForm({ onAdd, initialData, onCancel, materials: materialsProp = [], initialMaterialNames = [] }) {
const { user } = useAuth();
const token = user?.thalosToken || localStorage.getItem('thalosToken');
const api = useMemo(() => new CategoriesApi(token), [token]);
@@ -35,6 +33,15 @@ export default function AddOrEditCategoryForm({ onAdd, initialData, onCancel })
const [types, setTypes] = useState([]);
const [allTags, setAllTags] = useState([]);
const tagLabelById = useMemo(() => {
const map = {};
for (const t of allTags) {
const key = t._id || t.id;
map[key] = t.tagName || t.name || key;
}
return map;
}, [allTags]);
const [form, setForm] = useState({
_Id: '',
id: '',
@@ -56,15 +63,58 @@ export default function AddOrEditCategoryForm({ onAdd, initialData, onCancel })
useEffect(() => {
(async () => {
try {
const [t, tags] = await Promise.all([api.getAllTypes(), api.getAll()]);
setTypes(Array.isArray(t) ? t : []);
// Always try to load all tags (for materials, lookups, etc.)
const tags = typeof api.getAll === 'function' ? await api.getAll() : [];
// Try multiple method names for types; if none exist, derive from tags
let typesResp = [];
if (typeof api.getAllTypes === 'function') {
typesResp = await api.getAllTypes();
} else if (typeof api.getTypes === 'function') {
typesResp = await api.getTypes();
} else if (Array.isArray(tags)) {
// Derive a minimal "types" list from existing tag.typeId values
const uniqueTypeIds = [...new Set(tags.map(t => t?.typeId).filter(Boolean))];
typesResp = uniqueTypeIds.map(id => ({ id, typeName: id, level: null }));
console.warn('CategoriesApi has no getAllTypes/getTypes; derived types from tag.typeId.');
}
setTypes(Array.isArray(typesResp) ? typesResp : []);
setAllTags(Array.isArray(tags) ? tags : []);
} catch (e) {
console.error('Failed to load tag types or tags', e);
setTypes([]);
setAllTags([]);
}
})();
}, [api]);
// When editing: if we received material names from the grid, map them to IDs once allTags are loaded.
useEffect(() => {
if (!Array.isArray(initialMaterialNames) || initialMaterialNames.length === 0) return;
// If parentTagId already has values (ids), do not override.
if (Array.isArray(form.parentTagId) && form.parentTagId.length > 0) return;
if (!Array.isArray(allTags) || allTags.length === 0) return;
// Build a case-insensitive name -> id map
const nameToId = new Map(
allTags.map(t => {
const id = t._id || t.id;
const label = (t.tagName || t.name || '').toLowerCase();
return [label, id];
})
);
const ids = initialMaterialNames
.map(n => (typeof n === 'string' ? n.toLowerCase() : ''))
.map(lower => nameToId.get(lower))
.filter(Boolean);
if (ids.length > 0) {
setForm(prev => ({ ...prev, parentTagId: ids }));
}
}, [initialMaterialNames, allTags]);
// set inicial
useEffect(() => {
if (initialData) {
@@ -106,6 +156,9 @@ export default function AddOrEditCategoryForm({ onAdd, initialData, onCancel })
}
}, [initialData]);
const isEdit = Boolean(form._Id || form.id);
const isAdd = !isEdit;
const setVal = (name, value) => setForm(p => ({ ...p, [name]: value }));
const handleChange = (e) => {
@@ -180,23 +233,16 @@ export default function AddOrEditCategoryForm({ onAdd, initialData, onCancel })
{form._Id ? 'Edit Category' : 'Add Category'}
</Typography>
{/* IDs (read-only) */}
{form._Id || form.id ? (
<Box sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr', md: '1fr 1fr' }, gap: 2, mb: 2 }}>
<TextField label="_Id" value={form._Id} InputProps={{ readOnly: true }} fullWidth />
<TextField label="id" value={form.id} InputProps={{ readOnly: true }} fullWidth />
</Box>
) : null}
{/* Tenant (read-only; comes from token or existing record) */}
<TextField
name="tenantId"
label="Tenant Id"
value={form.tenantId}
fullWidth
sx={{ mb: 2 }}
InputProps={{ readOnly: true }}
/>
{isAdd && (
<TextField
name="tenantId"
label="Tenant Id"
value={form.tenantId}
fullWidth
sx={{ mb: 2 }}
InputProps={{ readOnly: true }}
/>
)}
<TextField
name="tagName"
@@ -227,25 +273,35 @@ export default function AddOrEditCategoryForm({ onAdd, initialData, onCancel })
<TextField
name="parentTagId"
label="Parent tags"
label="Material"
value={form.parentTagId}
onChange={(e) => {
// For MUI Select multiple, e.target.value is an array of selected IDs
const val = e.target.value;
setVal('parentTagId', typeof val === 'string' ? val.split(',').map(s => s.trim()).filter(Boolean) : val);
setVal('parentTagId', Array.isArray(val) ? val : []);
}}
select
SelectProps={{ multiple: true, renderValue: (selected) => (
<Box sx={{ display: 'flex', gap: 0.5, flexWrap: 'wrap' }}>
{selected.map(v => <Chip key={v} label={v} size="small" />)}
</Box>
)}}
SelectProps={{
multiple: true,
renderValue: (selected) => (
<Box sx={{ display: 'flex', gap: 0.5, flexWrap: 'wrap' }}>
{selected.map((id) => (
<Chip key={id} label={tagLabelById[id] || id} size="small" />
))}
</Box>
),
}}
fullWidth
sx={{ mb: 2 }}
>
{allTags.map(t => {
{allTags.map((t) => {
const value = t._id || t.id;
const label = t.tagName || t.name || value;
return <MenuItem key={value} value={value}>{label}</MenuItem>;
return (
<MenuItem key={value} value={value}>
{label}
</MenuItem>
);
})}
</TextField>
@@ -301,9 +357,9 @@ export default function AddOrEditCategoryForm({ onAdd, initialData, onCancel })
) : null}
<Box display="flex" justifyContent="space-between" gap={1} mt={3}>
{ (form._Id || form.id) ? (
{(form._Id || form.id) ? (
<Button color="error" onClick={handleDelete}>Delete</Button>
) : <span /> }
) : <span />}
<Box sx={{ display: 'flex', gap: 1 }}>
<Button onClick={onCancel} className="button-transparent">Cancel</Button>
<Button variant="contained" onClick={handleSubmit} className="button-gold">Save</Button>

View File

@@ -1,6 +1,8 @@
import { useEffect, useMemo, useRef, useState } from 'react';
import { Box, Button, Dialog, DialogContent, DialogTitle, IconButton, Typography,
ToggleButton, ToggleButtonGroup } from '@mui/material';
import {
Box, Button, Dialog, DialogContent, DialogTitle, IconButton, Typography,
ToggleButton, ToggleButtonGroup
} from '@mui/material';
import { DataGrid } from '@mui/x-data-grid';
import EditRoundedIcon from '@mui/icons-material/EditRounded';
import DeleteRoundedIcon from '@mui/icons-material/DeleteRounded';
@@ -14,6 +16,7 @@ export default function Categories() {
const api = useMemo(() => new CategoriesApi(token), [token]);
const [rows, setRows] = useState([]);
const [allTags, setAllTags] = useState([]);
const [statusFilter, setStatusFilter] = useState('All'); // <- por defecto All
const [open, setOpen] = useState(false);
const [editingCategory, setEditingCategory] = useState(null);
@@ -35,6 +38,8 @@ export default function Categories() {
const data = await api.getAll();
const list = Array.isArray(data) ? data : [];
setAllTags(list);
// Build a map of parentId -> array of child tagNames
const parentToChildren = {};
for (const item of list) {
@@ -76,6 +81,9 @@ export default function Categories() {
displayOrder: Number(r.displayOrder ?? 0),
icon: r.icon || '',
status: r.status ?? 'Active',
materialNames: typeof r.material === 'string'
? r.material.split(',').map(s => s.trim()).filter(Boolean)
: Array.isArray(r.material) ? r.material : [],
});
setOpen(true);
};
@@ -264,6 +272,8 @@ export default function Categories() {
<DialogContent>
<AddOrEditCategoryForm
initialData={editingCategory}
allTags={allTags}
initialMaterialNames={editingCategory?.materialNames || []}
onAdd={handleFormDone}
onCancel={() => { setOpen(false); setEditingCategory(null); }}
/>