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 DeleteRoundedIcon from '@mui/icons-material/DeleteRounded';
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';
const columnsBase = [
{ field: 'username', headerName: 'Username', flex: 1 },
{ field: 'fullName', headerName: 'Full Name', flex: 2 },
{ field: 'email', headerName: 'Email', flex: 2 },
{ field: 'role', headerName: 'Role', flex: 1 },
{ field: 'email', headerName: 'Email', width: 260 },
{ field: 'name', headerName: 'Name', width: 140 },
{ field: 'middleName', headerName: 'Middle Name', width: 140 },
{ 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: 'createdAt',
headerName: 'Created At',
width: 160,
width: 180,
valueFormatter: (params) => {
const date = params?.value;
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',
headerName: 'Updated At',
width: 160,
width: 180,
valueFormatter: (params) => {
const date = params?.value;
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() {
const { user } = useAuth();
const thalosToken = user?.thalosToken || localStorage.getItem('thalosToken');
const apiRef = useRef(null);
const [rows, setRows] = useState([]);
const [open, setOpen] = useState(false);
const [editingData, setEditingData] = useState(null);
@@ -46,6 +73,12 @@ export default function UserManagement() {
const hasLoaded = useRef(false);
useEffect(() => {
if (thalosToken) {
apiRef.current = new UserApi(thalosToken);
}
}, [thalosToken]);
useEffect(() => {
if (!hasLoaded.current) {
loadData();
@@ -54,18 +87,20 @@ export default function UserManagement() {
}, []);
const handleEditClick = (params) => {
if (!params || !params.row) return;
setEditingData(params.row);
setOpen(true);
};
const handleDeleteClick = (row) => {
if (!row) return;
setRowToDelete(row);
setConfirmOpen(true);
};
const handleConfirmDelete = async () => {
try {
await deleteExternalData(rowToDelete._Id);
await deleteExternalData(rowToDelete?._id);
await loadData();
} catch (error) {
console.error('Delete failed:', error);
@@ -77,24 +112,24 @@ export default function UserManagement() {
const loadData = async () => {
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 : [];
setRows(safeData);
} catch (error) {
console.error('Error loading data:', error);
handleError(error, 'Failed to load data');
handleError(error, 'Failed to load users');
setRows([]);
}
};
const columns = [
...columnsBase,
{
field: 'actions',
headerName: '',
width: 130,
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
size="small"
sx={{
@@ -117,13 +152,14 @@ export default function UserManagement() {
borderRadius: 2,
p: 1,
}}
onClick={() => handleDeleteClick(params.row)}
onClick={() => handleDeleteClick(params?.row)}
>
<DeleteRoundedIcon fontSize="small" />
</IconButton>
</Box>
)
}
},
...columnsBase,
];
return (
@@ -152,7 +188,7 @@ export default function UserManagement() {
<DialogTitle>Confirm Delete</DialogTitle>
<DialogContent>
<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>
<Box mt={2} display="flex" justifyContent="flex-end" gap={1}>
<Button onClick={() => setConfirmOpen(false)} className='button-transparent'>Cancel</Button>
@@ -161,14 +197,30 @@ export default function UserManagement() {
</DialogContent>
</Dialog>
<Box mt={2}>
<Box mt={2} sx={{ width: '100%', overflowX: 'auto' }}>
<Box sx={{ width: '100%', overflowX: 'auto' }}>
<DataGrid
rows={rows}
columns={columns}
pageSize={5}
rowsPerPageOptions={[5]}
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}>
<Button variant="contained" onClick={() => setOpen(true)} className="button-gold">