chore: load TagType and materials, show in the gridview and the edit
This commit is contained in:
		| @@ -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,7 +17,6 @@ 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] : ''); | ||||
|     } | ||||
| @@ -27,7 +25,7 @@ function extractTenantId(token) { | ||||
|   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,15 +233,7 @@ 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) */} | ||||
|       {isAdd && ( | ||||
|         <TextField | ||||
|           name="tenantId" | ||||
|           label="Tenant Id" | ||||
| @@ -197,6 +242,7 @@ export default function AddOrEditCategoryForm({ onAdd, initialData, onCancel }) | ||||
|           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) => ( | ||||
|         SelectProps={{ | ||||
|           multiple: true, | ||||
|           renderValue: (selected) => ( | ||||
|             <Box sx={{ display: 'flex', gap: 0.5, flexWrap: 'wrap' }}> | ||||
|             {selected.map(v => <Chip key={v} label={v} size="small" />)} | ||||
|               {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> | ||||
|  | ||||
|   | ||||
| @@ -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); }} | ||||
|           /> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Rodolfo Ruiz
					Rodolfo Ruiz