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