equipe ui
This commit is contained in:
parent
7c3239996c
commit
bc02fdfb98
@ -497,17 +497,16 @@ export default function EmailSidebar({
|
||||
type="button"
|
||||
className="ml-1 text-gray-400 hover:text-gray-600 cursor-pointer flex items-center justify-center h-5 w-5"
|
||||
tabIndex={-1}
|
||||
onClick={e => e.stopPropagation()}
|
||||
aria-label="Account options"
|
||||
>
|
||||
<span style={{ fontSize: '18px', lineHeight: 1 }}>⋮</span>
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem onClick={e => { e.stopPropagation(); onEditAccount(account); }}>
|
||||
<DropdownMenuItem onClick={() => onEditAccount(account)}>
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={e => { e.stopPropagation(); onDeleteAccount(account); }}>
|
||||
<DropdownMenuItem onClick={() => onDeleteAccount(account)}>
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
@ -53,6 +53,41 @@ interface GroupsTableProps {
|
||||
userRole?: string[];
|
||||
}
|
||||
|
||||
// DialogWrapper component to better handle dialog state
|
||||
function DialogWrapper({
|
||||
open,
|
||||
onOpenChange,
|
||||
onAfterClose,
|
||||
triggerComponent,
|
||||
children,
|
||||
className
|
||||
}: {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
onAfterClose?: () => void;
|
||||
triggerComponent?: React.ReactNode;
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}) {
|
||||
const handleOpenChange = useCallback((open: boolean) => {
|
||||
onOpenChange(open);
|
||||
|
||||
if (!open && onAfterClose) {
|
||||
// Use a longer timeout to ensure all animations are complete
|
||||
setTimeout(onAfterClose, 300);
|
||||
}
|
||||
}, [onOpenChange, onAfterClose]);
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={handleOpenChange}>
|
||||
{triggerComponent && <DialogTrigger asChild>{triggerComponent}</DialogTrigger>}
|
||||
<DialogContent className={className}>
|
||||
{children}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
export function GroupsTable({ userRole = [] }: GroupsTableProps) {
|
||||
const [groups, setGroups] = useState<Group[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
@ -340,6 +375,22 @@ export function GroupsTable({ userRole = [] }: GroupsTableProps) {
|
||||
}
|
||||
};
|
||||
|
||||
// Reset callbacks
|
||||
const resetNewGroupForm = useCallback(() => {
|
||||
setNewGroupName("");
|
||||
}, []);
|
||||
|
||||
const resetModifyGroupForm = useCallback(() => {
|
||||
setSelectedGroup(null);
|
||||
setModifiedGroupName("");
|
||||
}, []);
|
||||
|
||||
const resetMembersForm = useCallback(() => {
|
||||
setSelectedGroup(null);
|
||||
setGroupMembers([]);
|
||||
setAvailableUsers([]);
|
||||
}, []);
|
||||
|
||||
if (loading) return <div className="text-center p-4">Loading...</div>;
|
||||
|
||||
return (
|
||||
@ -352,21 +403,17 @@ export function GroupsTable({ userRole = [] }: GroupsTableProps) {
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
className="max-w-xs bg-white text-gray-900 border-gray-300"
|
||||
/>
|
||||
<Dialog open={newGroupDialog} onOpenChange={(open) => {
|
||||
setNewGroupDialog(open);
|
||||
if (!open) {
|
||||
// Reset state when dialog closes
|
||||
setTimeout(() => {
|
||||
setNewGroupName("");
|
||||
}, 100);
|
||||
}
|
||||
}}>
|
||||
<DialogTrigger asChild>
|
||||
<DialogWrapper
|
||||
open={newGroupDialog}
|
||||
onOpenChange={setNewGroupDialog}
|
||||
onAfterClose={resetNewGroupForm}
|
||||
triggerComponent={
|
||||
<Button className="bg-blue-600 hover:bg-blue-700 text-white">
|
||||
<Plus className="mr-2 h-4 w-4" /> Ajouter un groupe
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="bg-white text-black border border-gray-300">
|
||||
}
|
||||
className="bg-white text-black border border-gray-300"
|
||||
>
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-gray-900">Nouveau Groupe</DialogTitle>
|
||||
</DialogHeader>
|
||||
@ -388,8 +435,7 @@ export function GroupsTable({ userRole = [] }: GroupsTableProps) {
|
||||
Créer le groupe
|
||||
</Button>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</DialogWrapper>
|
||||
</div>
|
||||
|
||||
<Table className="bg-white border border-gray-300 rounded-md">
|
||||
@ -455,20 +501,12 @@ export function GroupsTable({ userRole = [] }: GroupsTableProps) {
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
<Dialog
|
||||
<DialogWrapper
|
||||
open={modifyGroupDialog}
|
||||
onOpenChange={(open) => {
|
||||
setModifyGroupDialog(open);
|
||||
if (!open) {
|
||||
// Reset state when dialog closes
|
||||
setTimeout(() => {
|
||||
setSelectedGroup(null);
|
||||
setModifiedGroupName("");
|
||||
}, 100);
|
||||
}
|
||||
}}
|
||||
onOpenChange={setModifyGroupDialog}
|
||||
onAfterClose={resetModifyGroupForm}
|
||||
className="bg-white text-black border border-gray-300"
|
||||
>
|
||||
<DialogContent className="bg-white text-black border border-gray-300">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-gray-900">Modifier le groupe</DialogTitle>
|
||||
</DialogHeader>
|
||||
@ -490,24 +528,14 @@ export function GroupsTable({ userRole = [] }: GroupsTableProps) {
|
||||
Mettre à jour
|
||||
</Button>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</DialogWrapper>
|
||||
|
||||
<Dialog
|
||||
<DialogWrapper
|
||||
open={manageMembersDialog}
|
||||
onOpenChange={(open) => {
|
||||
setManageMembersDialog(open);
|
||||
if (!open) {
|
||||
// Reset state when dialog closes
|
||||
setTimeout(() => {
|
||||
setSelectedGroup(null);
|
||||
setGroupMembers([]);
|
||||
setAvailableUsers([]);
|
||||
}, 100);
|
||||
}
|
||||
}}
|
||||
onOpenChange={setManageMembersDialog}
|
||||
onAfterClose={resetMembersForm}
|
||||
className="sm:max-w-[600px] max-h-[90vh] overflow-y-auto bg-white text-black border border-gray-300"
|
||||
>
|
||||
<DialogContent className="sm:max-w-[600px] max-h-[90vh] overflow-y-auto bg-white text-black border border-gray-300">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-gray-900">
|
||||
Gérer les membres - {selectedGroup?.name}
|
||||
@ -577,8 +605,7 @@ export function GroupsTable({ userRole = [] }: GroupsTableProps) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</DialogWrapper>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -41,9 +41,17 @@ const DialogContent = React.forwardRef<
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-white p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||
className
|
||||
)}
|
||||
onPointerDownOutside={(e) => {
|
||||
// Allow clicks outside to propagate normally
|
||||
e.preventDefault();
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
||||
<X className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</DialogPrimitive.Close>
|
||||
</DialogPrimitive.Content>
|
||||
</DialogPortal>
|
||||
))
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect, useMemo } from "react";
|
||||
import { useState, useEffect, useMemo, useCallback } from "react";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
@ -65,6 +65,41 @@ interface UsersTableProps {
|
||||
|
||||
const ITEMS_PER_PAGE = 10;
|
||||
|
||||
// DialogWrapper component to better handle dialog state
|
||||
function DialogWrapper({
|
||||
open,
|
||||
onOpenChange,
|
||||
onAfterClose,
|
||||
triggerComponent,
|
||||
children,
|
||||
className
|
||||
}: {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
onAfterClose?: () => void;
|
||||
triggerComponent?: React.ReactNode;
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}) {
|
||||
const handleOpenChange = useCallback((open: boolean) => {
|
||||
onOpenChange(open);
|
||||
|
||||
if (!open && onAfterClose) {
|
||||
// Use a longer timeout to ensure all animations are complete
|
||||
setTimeout(onAfterClose, 300);
|
||||
}
|
||||
}, [onOpenChange, onAfterClose]);
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={handleOpenChange}>
|
||||
{triggerComponent && <DialogTrigger asChild>{triggerComponent}</DialogTrigger>}
|
||||
<DialogContent className={className}>
|
||||
{children}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
export function UsersTable({ userRole = [] }: UsersTableProps) {
|
||||
const { data: session, status } = useSession();
|
||||
const [users, setUsers] = useState<User[]>([]);
|
||||
@ -403,6 +438,37 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
|
||||
currentPage * ITEMS_PER_PAGE
|
||||
);
|
||||
|
||||
// Define reset function callbacks
|
||||
const resetNewUserForm = useCallback(() => {
|
||||
setFormData({
|
||||
username: "",
|
||||
lastName: "",
|
||||
firstName: "",
|
||||
email: "",
|
||||
password: "",
|
||||
roles: [],
|
||||
enabled: true,
|
||||
});
|
||||
}, []);
|
||||
|
||||
const resetEditForm = useCallback(() => {
|
||||
setFormData({
|
||||
username: "",
|
||||
lastName: "",
|
||||
firstName: "",
|
||||
email: "",
|
||||
password: "",
|
||||
roles: [],
|
||||
enabled: true,
|
||||
});
|
||||
setSelectedUser(null);
|
||||
}, []);
|
||||
|
||||
const resetRolesForm = useCallback(() => {
|
||||
setFormData(prev => ({ ...prev, roles: [] }));
|
||||
setSelectedUser(null);
|
||||
}, []);
|
||||
|
||||
if (!session) return null;
|
||||
if (loading) return <div className="text-center p-4">Loading...</div>;
|
||||
|
||||
@ -416,28 +482,17 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
className="max-w-sm bg-white text-gray-900 border-gray-300"
|
||||
/>
|
||||
<Dialog open={newUserDialog} onOpenChange={(open) => {
|
||||
setNewUserDialog(open);
|
||||
if (!open) {
|
||||
setTimeout(() => {
|
||||
setFormData({
|
||||
username: "",
|
||||
lastName: "",
|
||||
firstName: "",
|
||||
email: "",
|
||||
password: "",
|
||||
roles: [],
|
||||
enabled: true,
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
}}>
|
||||
<DialogTrigger asChild>
|
||||
<DialogWrapper
|
||||
open={newUserDialog}
|
||||
onOpenChange={setNewUserDialog}
|
||||
onAfterClose={resetNewUserForm}
|
||||
triggerComponent={
|
||||
<Button className="bg-blue-600 hover:bg-blue-700 text-white">
|
||||
Ajouter un utilisateur
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-h-[85vh] overflow-y-auto bg-white text-black border border-gray-300">
|
||||
}
|
||||
className="max-h-[85vh] overflow-y-auto bg-white text-black border border-gray-300"
|
||||
>
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-gray-900">Nouvel Utilisateur</DialogTitle>
|
||||
</DialogHeader>
|
||||
@ -523,8 +578,7 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
|
||||
</div>
|
||||
<Button type="submit" className="w-full bg-blue-600 hover:bg-blue-700 text-white">Créer Utilisateur</Button>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</DialogWrapper>
|
||||
</div>
|
||||
|
||||
<Table className="bg-white border border-gray-300 rounded-md">
|
||||
@ -564,10 +618,6 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="h-8 w-8 p-0"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
@ -628,24 +678,12 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
<Dialog open={editUserDialog} onOpenChange={(open) => {
|
||||
if (!open) {
|
||||
setTimeout(() => {
|
||||
setFormData({
|
||||
username: "",
|
||||
lastName: "",
|
||||
firstName: "",
|
||||
email: "",
|
||||
password: "",
|
||||
roles: [],
|
||||
enabled: true,
|
||||
});
|
||||
setSelectedUser(null);
|
||||
}, 100);
|
||||
}
|
||||
setEditUserDialog(open);
|
||||
}}>
|
||||
<DialogContent className="bg-white text-black border border-gray-300">
|
||||
<DialogWrapper
|
||||
open={editUserDialog}
|
||||
onOpenChange={setEditUserDialog}
|
||||
onAfterClose={resetEditForm}
|
||||
className="bg-white text-black border border-gray-300"
|
||||
>
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-gray-900">Modifier l'utilisateur</DialogTitle>
|
||||
</DialogHeader>
|
||||
@ -705,19 +743,14 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</DialogWrapper>
|
||||
|
||||
<Dialog open={manageRolesDialog} onOpenChange={(open) => {
|
||||
if (!open) {
|
||||
setTimeout(() => {
|
||||
setFormData(prev => ({ ...prev, roles: [] }));
|
||||
setSelectedUser(null);
|
||||
}, 100);
|
||||
}
|
||||
setManageRolesDialog(open);
|
||||
}}>
|
||||
<DialogContent className="bg-white text-black border border-gray-300">
|
||||
<DialogWrapper
|
||||
open={manageRolesDialog}
|
||||
onOpenChange={setManageRolesDialog}
|
||||
onAfterClose={resetRolesForm}
|
||||
className="bg-white text-black border border-gray-300"
|
||||
>
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-gray-900">Gérer les rôles pour {selectedUser?.username}</DialogTitle>
|
||||
</DialogHeader>
|
||||
@ -767,8 +800,7 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</DialogWrapper>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user