Added editable user fields
All checks were successful
Deploy Frontend / deploy (push) Successful in 23s
All checks were successful
Deploy Frontend / deploy (push) Successful in 23s
This commit is contained in:
@@ -13,6 +13,7 @@ interface UserDTO {
|
||||
email: string;
|
||||
role: string;
|
||||
clientName: string;
|
||||
clientId?: number;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
// src/components/admin/UserTableSection.tsx
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import {
|
||||
Typography, Table, TableBody, TableCell, TableContainer, TableHead,
|
||||
TableRow, Paper, Box, Button, Dialog, DialogTitle, DialogContent, DialogActions
|
||||
TableRow, Paper, Box, Button, Dialog, DialogTitle, DialogContent, DialogActions,
|
||||
TextField, Select, MenuItem, FormControl, InputLabel, IconButton
|
||||
} from '@mui/material';
|
||||
import EditIcon from '@mui/icons-material/Edit';
|
||||
import SaveIcon from '@mui/icons-material/Save';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
import UserEnableToggle from './UserEnableToggle';
|
||||
import AddUserForm from './forms/AddUserForm';
|
||||
import AddClientForm from './forms/AddClientForm';
|
||||
import InviteUserForm from './forms/InviteUserForm';
|
||||
import api from '@/lib/axios';
|
||||
|
||||
interface UserDTO {
|
||||
id: number;
|
||||
@@ -20,15 +25,97 @@ interface UserDTO {
|
||||
email: string;
|
||||
role: string;
|
||||
clientName: string;
|
||||
clientId?: number;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
interface ClientDTO {
|
||||
clientId: number;
|
||||
clientIdentifier: string;
|
||||
clientName: string;
|
||||
}
|
||||
|
||||
export default function UserTableSection({ initialUsers }: { initialUsers: UserDTO[] }) {
|
||||
const [users, setUsers] = useState<UserDTO[]>(initialUsers);
|
||||
const [openUserDialog, setOpenUserDialog] = useState(false);
|
||||
const [openClientDialog, setOpenClientDialog] = useState(false);
|
||||
const [openInviteUserDialog, setOpenInviteUserDialog] = useState(false);
|
||||
|
||||
// Edit mode state
|
||||
const [editingUserId, setEditingUserId] = useState<number | null>(null);
|
||||
const [editFormData, setEditFormData] = useState<Partial<UserDTO>>({});
|
||||
const [clients, setClients] = useState<ClientDTO[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
// Fetch clients for dropdown
|
||||
useEffect(() => {
|
||||
const fetchClients = async () => {
|
||||
try {
|
||||
const res = await api.get('/auth/clients');
|
||||
setClients(res.data);
|
||||
} catch (err) {
|
||||
console.error('Failed to fetch clients:', err);
|
||||
}
|
||||
};
|
||||
fetchClients();
|
||||
}, []);
|
||||
|
||||
const handleEdit = (user: UserDTO) => {
|
||||
setEditingUserId(user.id);
|
||||
setEditFormData({
|
||||
username: user.username,
|
||||
displayName: user.displayName,
|
||||
firstName: user.firstName,
|
||||
lastName: user.lastName,
|
||||
email: user.email,
|
||||
role: user.role,
|
||||
clientName: user.clientName,
|
||||
clientId: user.clientId
|
||||
});
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
setEditingUserId(null);
|
||||
setEditFormData({});
|
||||
};
|
||||
|
||||
const handleSave = async (userId: number) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
// Find the selected client
|
||||
const selectedClient = clients.find(c => c.clientId === editFormData.clientId);
|
||||
|
||||
await api.put(`/admin/users/${userId}`, {
|
||||
username: editFormData.username,
|
||||
displayName: editFormData.displayName,
|
||||
firstName: editFormData.firstName,
|
||||
lastName: editFormData.lastName,
|
||||
email: editFormData.email,
|
||||
role: editFormData.role,
|
||||
clientId: editFormData.clientId
|
||||
});
|
||||
|
||||
// Update local state
|
||||
setUsers(users.map(user =>
|
||||
user.id === userId
|
||||
? {
|
||||
...user,
|
||||
...editFormData,
|
||||
clientName: selectedClient?.clientName || user.clientName
|
||||
}
|
||||
: user
|
||||
));
|
||||
|
||||
setEditingUserId(null);
|
||||
setEditFormData({});
|
||||
} catch (err) {
|
||||
console.error('Failed to update user:', err);
|
||||
alert('Failed to update user. Please try again.');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box sx={{ p: 4 }}>
|
||||
<Typography variant="h5" gutterBottom>User Management</Typography>
|
||||
@@ -57,23 +144,143 @@ export default function UserTableSection({ initialUsers }: { initialUsers: UserD
|
||||
<TableCell>Role</TableCell>
|
||||
<TableCell>Client</TableCell>
|
||||
<TableCell>Status</TableCell>
|
||||
<TableCell>Actions</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{users.map((user) => (
|
||||
<TableRow key={user.id}>
|
||||
<TableCell>{user.username}</TableCell>
|
||||
<TableCell>{user.displayName}</TableCell>
|
||||
<TableCell>{user.firstName}</TableCell>
|
||||
<TableCell>{user.lastName}</TableCell>
|
||||
<TableCell>{user.email}</TableCell>
|
||||
<TableCell>{user.role}</TableCell>
|
||||
<TableCell>{user.clientName}</TableCell>
|
||||
<TableCell>
|
||||
<UserEnableToggle userId={user.id} initialEnabled={user.enabled} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
{users.map((user) => {
|
||||
const isEditing = editingUserId === user.id;
|
||||
return (
|
||||
<TableRow key={user.id}>
|
||||
<TableCell>
|
||||
{isEditing ? (
|
||||
<TextField
|
||||
size="small"
|
||||
value={editFormData.username || ''}
|
||||
onChange={(e) => setEditFormData({ ...editFormData, username: e.target.value })}
|
||||
fullWidth
|
||||
/>
|
||||
) : (
|
||||
user.username
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{isEditing ? (
|
||||
<TextField
|
||||
size="small"
|
||||
value={editFormData.displayName || ''}
|
||||
onChange={(e) => setEditFormData({ ...editFormData, displayName: e.target.value })}
|
||||
fullWidth
|
||||
/>
|
||||
) : (
|
||||
user.displayName
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{isEditing ? (
|
||||
<TextField
|
||||
size="small"
|
||||
value={editFormData.firstName || ''}
|
||||
onChange={(e) => setEditFormData({ ...editFormData, firstName: e.target.value })}
|
||||
fullWidth
|
||||
/>
|
||||
) : (
|
||||
user.firstName
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{isEditing ? (
|
||||
<TextField
|
||||
size="small"
|
||||
value={editFormData.lastName || ''}
|
||||
onChange={(e) => setEditFormData({ ...editFormData, lastName: e.target.value })}
|
||||
fullWidth
|
||||
/>
|
||||
) : (
|
||||
user.lastName
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{isEditing ? (
|
||||
<TextField
|
||||
size="small"
|
||||
value={editFormData.email || ''}
|
||||
onChange={(e) => setEditFormData({ ...editFormData, email: e.target.value })}
|
||||
fullWidth
|
||||
/>
|
||||
) : (
|
||||
user.email
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{isEditing ? (
|
||||
<FormControl fullWidth size="small">
|
||||
<Select
|
||||
value={editFormData.role || ''}
|
||||
onChange={(e) => setEditFormData({ ...editFormData, role: e.target.value })}
|
||||
>
|
||||
<MenuItem value="USER">USER</MenuItem>
|
||||
<MenuItem value="ADMIN">ADMIN</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
) : (
|
||||
user.role
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{isEditing ? (
|
||||
<FormControl fullWidth size="small">
|
||||
<Select
|
||||
value={editFormData.clientId || ''}
|
||||
onChange={(e) => setEditFormData({ ...editFormData, clientId: Number(e.target.value) })}
|
||||
>
|
||||
{clients.map(client => (
|
||||
<MenuItem key={client.clientId} value={client.clientId}>
|
||||
{client.clientName}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
) : (
|
||||
user.clientName
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<UserEnableToggle userId={user.id} initialEnabled={user.enabled} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{isEditing ? (
|
||||
<Box sx={{ display: 'flex', gap: 1 }}>
|
||||
<IconButton
|
||||
color="primary"
|
||||
onClick={() => handleSave(user.id)}
|
||||
disabled={loading}
|
||||
size="small"
|
||||
>
|
||||
<SaveIcon />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
color="default"
|
||||
onClick={handleCancel}
|
||||
disabled={loading}
|
||||
size="small"
|
||||
>
|
||||
<CancelIcon />
|
||||
</IconButton>
|
||||
</Box>
|
||||
) : (
|
||||
<IconButton
|
||||
color="primary"
|
||||
onClick={() => handleEdit(user)}
|
||||
size="small"
|
||||
>
|
||||
<EditIcon />
|
||||
</IconButton>
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
|
||||
Reference in New Issue
Block a user