chore: add data to gridview

This commit is contained in:
Rodolfo Ruiz
2025-08-30 19:40:13 -06:00
parent 1f11c47484
commit 55cb3fb34f

View File

@@ -5,38 +5,65 @@ import { Typography, Button, Dialog, DialogTitle, DialogContent, IconButton, Box
import EditRoundedIcon from '@mui/icons-material/EditRounded'; import EditRoundedIcon from '@mui/icons-material/EditRounded';
import DeleteRoundedIcon from '@mui/icons-material/DeleteRounded'; import DeleteRoundedIcon from '@mui/icons-material/DeleteRounded';
import AddOrEditUserForm from './AddOrEditUserForm'; import AddOrEditUserForm from './AddOrEditUserForm';
import { getExternalData, deleteExternalData } from '../../api/mongo/actions'; import UserApi from '../../api/userApi';
import { useAuth } from '../../context/AuthContext';
import { deleteExternalData } from '../../api/mongo/actions';
import useApiToast from '../../hooks/useApiToast'; import useApiToast from '../../hooks/useApiToast';
const columnsBase = [ const columnsBase = [
{ field: 'username', headerName: 'Username', flex: 1 }, { field: 'email', headerName: 'Email', width: 260 },
{ field: 'fullName', headerName: 'Full Name', flex: 2 }, { field: 'name', headerName: 'Name', width: 140 },
{ field: 'email', headerName: 'Email', flex: 2 }, { field: 'middleName', headerName: 'Middle Name', width: 140 },
{ field: 'role', headerName: 'Role', flex: 1 }, { field: 'lastName', headerName: 'Last Name', width: 160 },
{ field: 'displayName', headerName: 'Display Name', width: 180, valueGetter: (params) => params?.row?.displayName ?? '—' },
{ field: 'tenantId', headerName: 'Tenant Id', width: 240, valueGetter: (params) => params?.row?.tenantId ?? '—' },
{ field: 'roleId', headerName: 'Role Id', width: 240, valueGetter: (params) => params?.row?.roleId ?? '—' },
{
field: 'lastLogIn',
headerName: 'Last Login',
width: 180,
valueFormatter: (params) => {
const date = params?.value;
return date ? new Date(date).toLocaleString() : '—';
}
},
{
field: 'lastLogOut',
headerName: 'Last Logout',
width: 180,
valueFormatter: (params) => {
const date = params?.value;
return date ? new Date(date).toLocaleString() : '—';
}
},
{ field: 'status', headerName: 'Status', width: 120 }, { field: 'status', headerName: 'Status', width: 120 },
{ {
field: 'createdAt', field: 'createdAt',
headerName: 'Created At', headerName: 'Created At',
width: 160, width: 180,
valueFormatter: (params) => { valueFormatter: (params) => {
const date = params?.value; const date = params?.value;
return date ? new Date(date).toLocaleString() : '—'; return date ? new Date(date).toLocaleString() : '—';
} }
}, },
{ field: 'createdBy', headerName: 'Created By', flex: 1 }, { field: 'createdBy', headerName: 'Created By', width: 160, valueGetter: (p) => p?.row?.createdBy ?? '—' },
{ {
field: 'updatedAt', field: 'updatedAt',
headerName: 'Updated At', headerName: 'Updated At',
width: 160, width: 180,
valueFormatter: (params) => { valueFormatter: (params) => {
const date = params?.value; const date = params?.value;
return date ? new Date(date).toLocaleString() : '—'; return date ? new Date(date).toLocaleString() : '—';
} }
}, },
{ field: 'updatedBy', headerName: 'Updated By', flex: 1 }, { field: 'updatedBy', headerName: 'Updated By', width: 160, valueGetter: (p) => p?.row?.updatedBy ?? '—' },
]; ];
export default function UserManagement() { export default function UserManagement() {
const { user } = useAuth();
const thalosToken = user?.thalosToken || localStorage.getItem('thalosToken');
const apiRef = useRef(null);
const [rows, setRows] = useState([]); const [rows, setRows] = useState([]);
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [editingData, setEditingData] = useState(null); const [editingData, setEditingData] = useState(null);
@@ -46,6 +73,12 @@ export default function UserManagement() {
const hasLoaded = useRef(false); const hasLoaded = useRef(false);
useEffect(() => {
if (thalosToken) {
apiRef.current = new UserApi(thalosToken);
}
}, [thalosToken]);
useEffect(() => { useEffect(() => {
if (!hasLoaded.current) { if (!hasLoaded.current) {
loadData(); loadData();
@@ -54,18 +87,20 @@ export default function UserManagement() {
}, []); }, []);
const handleEditClick = (params) => { const handleEditClick = (params) => {
if (!params || !params.row) return;
setEditingData(params.row); setEditingData(params.row);
setOpen(true); setOpen(true);
}; };
const handleDeleteClick = (row) => { const handleDeleteClick = (row) => {
if (!row) return;
setRowToDelete(row); setRowToDelete(row);
setConfirmOpen(true); setConfirmOpen(true);
}; };
const handleConfirmDelete = async () => { const handleConfirmDelete = async () => {
try { try {
await deleteExternalData(rowToDelete._Id); await deleteExternalData(rowToDelete?._id);
await loadData(); await loadData();
} catch (error) { } catch (error) {
console.error('Delete failed:', error); console.error('Delete failed:', error);
@@ -77,24 +112,24 @@ export default function UserManagement() {
const loadData = async () => { const loadData = async () => {
try { try {
const data = await getExternalData(); if (!apiRef.current) throw new Error('Missing Thalos token or API not initialized');
const data = await apiRef.current.getAllUsers();
const safeData = Array.isArray(data) ? data : []; const safeData = Array.isArray(data) ? data : [];
setRows(safeData); setRows(safeData);
} catch (error) { } catch (error) {
console.error('Error loading data:', error); console.error('Error loading data:', error);
handleError(error, 'Failed to load data'); handleError(error, 'Failed to load users');
setRows([]); setRows([]);
} }
}; };
const columns = [ const columns = [
...columnsBase,
{ {
field: 'actions', field: 'actions',
headerName: '', headerName: '',
width: 130, width: 130,
renderCell: (params) => ( renderCell: (params) => (
<Box display="flex" alignItems="center" justifyContent="flex-end" height="100%" gap={2}> <Box display="flex" alignItems="center" justifyContent="flex-start" height="100%" gap={1}>
<IconButton <IconButton
size="small" size="small"
sx={{ sx={{
@@ -117,13 +152,14 @@ export default function UserManagement() {
borderRadius: 2, borderRadius: 2,
p: 1, p: 1,
}} }}
onClick={() => handleDeleteClick(params.row)} onClick={() => handleDeleteClick(params?.row)}
> >
<DeleteRoundedIcon fontSize="small" /> <DeleteRoundedIcon fontSize="small" />
</IconButton> </IconButton>
</Box> </Box>
) )
} },
...columnsBase,
]; ];
return ( return (
@@ -152,7 +188,7 @@ export default function UserManagement() {
<DialogTitle>Confirm Delete</DialogTitle> <DialogTitle>Confirm Delete</DialogTitle>
<DialogContent> <DialogContent>
<Typography> <Typography>
Are you sure you want to delete <strong>{rowToDelete?.username}</strong>? Are you sure you want to delete <strong>{rowToDelete?.email || rowToDelete?.name}</strong>?
</Typography> </Typography>
<Box mt={2} display="flex" justifyContent="flex-end" gap={1}> <Box mt={2} display="flex" justifyContent="flex-end" gap={1}>
<Button onClick={() => setConfirmOpen(false)} className='button-transparent'>Cancel</Button> <Button onClick={() => setConfirmOpen(false)} className='button-transparent'>Cancel</Button>
@@ -161,14 +197,30 @@ export default function UserManagement() {
</DialogContent> </DialogContent>
</Dialog> </Dialog>
<Box mt={2}> <Box mt={2} sx={{ width: '100%', overflowX: 'auto' }}>
<Box sx={{ width: '100%', overflowX: 'auto' }}>
<DataGrid <DataGrid
rows={rows} rows={rows}
columns={columns} columns={columns}
pageSize={5} pageSize={5}
rowsPerPageOptions={[5]} rowsPerPageOptions={[5]}
getRowSpacing={() => ({ top: 4, bottom: 4 })} getRowSpacing={() => ({ top: 4, bottom: 4 })}
getRowId={(row) => row._id || row.id || row.email}
autoHeight
disableColumnMenu
getRowHeight={() => 'auto'}
sx={{
'& .MuiDataGrid-cell': {
display: 'flex',
alignItems: 'center', // vertical centering
},
'& .MuiDataGrid-columnHeader': {
display: 'flex',
alignItems: 'center', // vertical centering headers too
}
}}
/> />
</Box>
<Box display="flex" justifyContent="flex-end" mt={2}> <Box display="flex" justifyContent="flex-end" mt={2}>
<Button variant="contained" onClick={() => setOpen(true)} className="button-gold"> <Button variant="contained" onClick={() => setOpen(true)} className="button-gold">