From aa62b06c230235233696d60e9cbf2378a7957345 Mon Sep 17 00:00:00 2001 From: Rodolfo Ruiz Date: Thu, 4 Sep 2025 21:16:00 -0600 Subject: [PATCH] chore: load TagType and materials, show in the gridview and the edit --- .../categories/AddOrEditCategoryForm.jsx | 124 +++++++++++++----- src/private/categories/Categories.jsx | 14 +- 2 files changed, 102 insertions(+), 36 deletions(-) diff --git a/src/private/categories/AddOrEditCategoryForm.jsx b/src/private/categories/AddOrEditCategoryForm.jsx index 5e6d9c2..a6acfd4 100644 --- a/src/private/categories/AddOrEditCategoryForm.jsx +++ b/src/private/categories/AddOrEditCategoryForm.jsx @@ -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'} - {/* IDs (read-only) */} - {form._Id || form.id ? ( - - - - - ) : null} - - {/* Tenant (read-only; comes from token or existing record) */} - + {isAdd && ( + + )} { + // 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) => ( - - {selected.map(v => )} - - )}} + SelectProps={{ + multiple: true, + renderValue: (selected) => ( + + {selected.map((id) => ( + + ))} + + ), + }} fullWidth sx={{ mb: 2 }} > - {allTags.map(t => { + {allTags.map((t) => { const value = t._id || t.id; const label = t.tagName || t.name || value; - return {label}; + return ( + + {label} + + ); })} @@ -301,9 +357,9 @@ export default function AddOrEditCategoryForm({ onAdd, initialData, onCancel }) ) : null} - { (form._Id || form.id) ? ( + {(form._Id || form.id) ? ( - ) : } + ) : } diff --git a/src/private/categories/Categories.jsx b/src/private/categories/Categories.jsx index fac41bc..b7e809e 100644 --- a/src/private/categories/Categories.jsx +++ b/src/private/categories/Categories.jsx @@ -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() { { setOpen(false); setEditingCategory(null); }} />