feat: Replace individual action icons with dropdown menu in users table
Some checks failed
ParentFlow CI/CD Pipeline / Backend Tests (push) Has been cancelled
ParentFlow CI/CD Pipeline / Frontend Tests (push) Has been cancelled
ParentFlow CI/CD Pipeline / Security Scanning (push) Has been cancelled
ParentFlow CI/CD Pipeline / Build Docker Images (map[context:maternal-app/maternal-app-backend dockerfile:Dockerfile.production name:backend]) (push) Has been cancelled
ParentFlow CI/CD Pipeline / Build Docker Images (map[context:maternal-web dockerfile:Dockerfile.production name:frontend]) (push) Has been cancelled
ParentFlow CI/CD Pipeline / Deploy to Development (push) Has been cancelled
ParentFlow CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / Lint and Test (push) Has been cancelled
CI/CD Pipeline / E2E Tests (push) Has been cancelled
CI/CD Pipeline / Build Application (push) Has been cancelled

Improved UX by consolidating user actions into a single dropdown menu:
- Added MoreVert icon button to open actions menu
- Menu includes: View Details, Edit User, Activate/Deactivate, Delete User
- Delete action shown in error color for visual distinction
- Cleaner table layout with single action button per row

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Andrei
2025-10-07 16:03:35 +00:00
parent ab23e978a2
commit e4dbf30dbb

View File

@@ -27,6 +27,10 @@ import {
Grid,
Switch,
FormControlLabel,
Menu,
MenuItem,
ListItemIcon,
ListItemText,
} from '@mui/material';
import {
Search,
@@ -36,6 +40,7 @@ import {
PersonAdd,
Block,
CheckCircle,
MoreVert,
} from '@mui/icons-material';
import AdminLayout from '@/components/AdminLayout';
import apiClient from '@/lib/api-client';
@@ -68,6 +73,8 @@ export default function UsersPage() {
const [selectedUser, setSelectedUser] = useState<User | null>(null);
const [viewDialogOpen, setViewDialogOpen] = useState(false);
const [editDialogOpen, setEditDialogOpen] = useState(false);
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const [menuUser, setMenuUser] = useState<User | null>(null);
useEffect(() => {
fetchUsers();
@@ -92,14 +99,26 @@ export default function UsersPage() {
}
};
const handleOpenMenu = (event: React.MouseEvent<HTMLElement>, user: User) => {
setAnchorEl(event.currentTarget);
setMenuUser(user);
};
const handleCloseMenu = () => {
setAnchorEl(null);
setMenuUser(null);
};
const handleViewUser = (user: User) => {
setSelectedUser(user);
setViewDialogOpen(true);
handleCloseMenu();
};
const handleEditUser = (user: User) => {
setSelectedUser(user);
setEditDialogOpen(true);
handleCloseMenu();
};
const handleToggleUserStatus = async (user: User) => {
@@ -108,6 +127,7 @@ export default function UsersPage() {
emailVerified: !user.emailVerified,
});
fetchUsers();
handleCloseMenu();
} catch (error) {
console.error('Failed to update user status:', error);
}
@@ -118,6 +138,7 @@ export default function UsersPage() {
try {
await apiClient.delete(`/admin/users/${userId}`);
fetchUsers();
handleCloseMenu();
} catch (error) {
console.error('Failed to delete user:', error);
}
@@ -270,32 +291,10 @@ export default function UsersPage() {
<TableCell align="right">
<IconButton
size="small"
onClick={() => handleViewUser(user)}
title="View"
onClick={(e) => handleOpenMenu(e, user)}
title="Actions"
>
<Visibility />
</IconButton>
<IconButton
size="small"
onClick={() => handleEditUser(user)}
title="Edit"
>
<Edit />
</IconButton>
<IconButton
size="small"
onClick={() => handleToggleUserStatus(user)}
title={user.emailVerified ? 'Deactivate' : 'Activate'}
>
{user.emailVerified ? <Block /> : <CheckCircle />}
</IconButton>
<IconButton
size="small"
onClick={() => handleDeleteUser(user.id)}
title="Delete"
color="error"
>
<Delete />
<MoreVert />
</IconButton>
</TableCell>
</TableRow>
@@ -316,6 +315,43 @@ export default function UsersPage() {
/>
</TableContainer>
{/* Actions Menu */}
<Menu
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClose={handleCloseMenu}
>
<MenuItem onClick={() => menuUser && handleViewUser(menuUser)}>
<ListItemIcon>
<Visibility fontSize="small" />
</ListItemIcon>
<ListItemText>View Details</ListItemText>
</MenuItem>
<MenuItem onClick={() => menuUser && handleEditUser(menuUser)}>
<ListItemIcon>
<Edit fontSize="small" />
</ListItemIcon>
<ListItemText>Edit User</ListItemText>
</MenuItem>
<MenuItem onClick={() => menuUser && handleToggleUserStatus(menuUser)}>
<ListItemIcon>
{menuUser?.emailVerified ? <Block fontSize="small" /> : <CheckCircle fontSize="small" />}
</ListItemIcon>
<ListItemText>
{menuUser?.emailVerified ? 'Deactivate' : 'Activate'}
</ListItemText>
</MenuItem>
<MenuItem
onClick={() => menuUser && handleDeleteUser(menuUser.id)}
sx={{ color: 'error.main' }}
>
<ListItemIcon>
<Delete fontSize="small" color="error" />
</ListItemIcon>
<ListItemText>Delete User</ListItemText>
</MenuItem>
</Menu>
{/* View User Dialog */}
<Dialog
open={viewDialogOpen}