import { useState, useEffect } from "react"; import { useQuery, useMutation } from "@tanstack/react-query"; import Sidebar from "@/components/sidebar"; import TopBar from "@/components/topbar"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog"; import { Badge } from "@/components/ui/badge"; import { Checkbox } from "@/components/ui/checkbox"; import { useToast } from "@/hooks/use-toast"; import { apiRequest, queryClient } from "@/lib/queryClient"; import { Users, UserPlus, Pencil, Trash2, Shield, User as UserIcon, Settings } from "lucide-react"; type UserData = { id: string; username: string; role: "admin" | "user"; }; type SocialPage = { id: string; pageName: string; platform: string; userId: string; }; type UserPagePermission = { id: string; userId: string; pageId: string; }; export default function UsersAdminMobile() { const [sidebarOpen, setSidebarOpen] = useState(false); const { toast } = useToast(); const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); const [role, setRole] = useState<"admin" | "user">("user"); const [editDialogOpen, setEditDialogOpen] = useState(false); const [editingUser, setEditingUser] = useState(null); const [editUsername, setEditUsername] = useState(""); const [editPassword, setEditPassword] = useState(""); const [editRole, setEditRole] = useState<"admin" | "user">("user"); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [userToDelete, setUserToDelete] = useState(null); const [permissionsDialogOpen, setPermissionsDialogOpen] = useState(false); const [permissionsUser, setPermissionsUser] = useState(null); const [selectedPageIds, setSelectedPageIds] = useState([]); const { data: users, isLoading } = useQuery({ queryKey: ["/api/users"], }); const { data: allPages } = useQuery({ queryKey: ["/api/pages"], }); const { data: userPermissions } = useQuery({ queryKey: ["/api/users", permissionsUser?.id, "page-permissions"], enabled: !!permissionsUser && permissionsDialogOpen, }); const createUserMutation = useMutation({ mutationFn: async (userData: { username: string; password: string; role: string }) => { const res = await apiRequest("POST", "/api/users", userData); return await res.json(); }, onSuccess: (data) => { toast({ title: "Utilisateur créé", description: `L'utilisateur ${data.username} a été créé avec succès`, }); setUsername(""); setPassword(""); setRole("user"); queryClient.invalidateQueries({ queryKey: ["/api/users"] }); }, onError: (error: any) => { toast({ variant: "destructive", title: "Erreur", description: error.message || "Erreur lors de la création de l'utilisateur", }); }, }); const updateUserMutation = useMutation({ mutationFn: async ({ id, data }: { id: string; data: any }) => { const res = await apiRequest("PATCH", `/api/users/${id}`, data); return await res.json(); }, onSuccess: (data) => { toast({ title: "Utilisateur modifié", description: `L'utilisateur ${data.username} a été modifié avec succès`, }); setEditDialogOpen(false); setEditingUser(null); queryClient.invalidateQueries({ queryKey: ["/api/users"] }); }, onError: (error: any) => { toast({ variant: "destructive", title: "Erreur", description: error.message || "Erreur lors de la modification de l'utilisateur", }); }, }); const deleteUserMutation = useMutation({ mutationFn: async (id: string) => { const res = await apiRequest("DELETE", `/api/users/${id}`, {}); return await res.json(); }, onSuccess: () => { toast({ title: "Utilisateur supprimé", description: "L'utilisateur a été supprimé avec succès", }); setDeleteDialogOpen(false); setUserToDelete(null); queryClient.invalidateQueries({ queryKey: ["/api/users"] }); }, onError: (error: any) => { toast({ variant: "destructive", title: "Erreur", description: error.message || "Erreur lors de la suppression de l'utilisateur", }); }, }); const updatePermissionsMutation = useMutation({ mutationFn: async ({ userId, pageIds }: { userId: string; pageIds: string[] }) => { const res = await apiRequest("POST", `/api/users/${userId}/page-permissions`, { pageIds }); return await res.json(); }, onSuccess: () => { toast({ title: "Permissions mises à jour", description: "Les permissions de l'utilisateur ont été mises à jour avec succès", }); setPermissionsDialogOpen(false); setPermissionsUser(null); setSelectedPageIds([]); queryClient.invalidateQueries({ queryKey: ["/api/users"] }); }, onError: (error: any) => { toast({ variant: "destructive", title: "Erreur", description: error.message || "Erreur lors de la mise à jour des permissions", }); }, }); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (!username || !password) { toast({ variant: "destructive", title: "Erreur", description: "Veuillez remplir tous les champs", }); return; } if (password.length < 4) { toast({ variant: "destructive", title: "Erreur", description: "Le mot de passe doit contenir au moins 4 caractères", }); return; } createUserMutation.mutate({ username, password, role }); }; const handleEditClick = (user: UserData) => { setEditingUser(user); setEditUsername(user.username); setEditPassword(""); setEditRole(user.role); setEditDialogOpen(true); }; const handleEditSubmit = () => { if (!editingUser) return; const updateData: any = {}; if (editUsername !== editingUser.username) { updateData.username = editUsername; } if (editPassword) { updateData.password = editPassword; } if (editRole !== editingUser.role) { updateData.role = editRole; } if (Object.keys(updateData).length === 0) { toast({ variant: "destructive", title: "Erreur", description: "Aucune modification détectée", }); return; } updateUserMutation.mutate({ id: editingUser.id, data: updateData }); }; const handleDeleteClick = (user: UserData) => { setUserToDelete(user); setDeleteDialogOpen(true); }; const handleDeleteConfirm = () => { if (userToDelete) { deleteUserMutation.mutate(userToDelete.id); } }; const handlePermissionsClick = (user: UserData) => { setPermissionsUser(user); setPermissionsDialogOpen(true); }; useEffect(() => { if (userPermissions) { setSelectedPageIds(userPermissions.map(p => p.pageId)); } }, [userPermissions]); const handlePermissionsSubmit = () => { if (permissionsUser) { updatePermissionsMutation.mutate({ userId: permissionsUser.id, pageIds: selectedPageIds, }); } }; const togglePagePermission = (pageId: string) => { setSelectedPageIds(prev => { if (prev.includes(pageId)) { return prev.filter(id => id !== pageId); } else { return [...prev, pageId]; } }); }; return (
{sidebarOpen && (
setSidebarOpen(false)} /> )}
setSidebarOpen(false)} />
setSidebarOpen(!sidebarOpen)} /> {/* MOBILE: Single column layout */}

Gestion des utilisateurs

Créez et gérez les utilisateurs de l'application

{/* Formulaire de création */} Créer un utilisateur Ajouter un nouvel utilisateur
setUsername(e.target.value)} required className="min-h-[48px]" data-testid="input-new-username" />
setPassword(e.target.value)} required className="min-h-[48px]" data-testid="input-new-password" />

Minimum 4 caractères

{/* Liste des utilisateurs */} Liste des utilisateurs {users?.length || 0} utilisateur(s) enregistré(s) {isLoading ? (

Chargement...

) : users && users.length > 0 ? (
{users.map((user) => (
{user.role === "admin" ? ( ) : ( )}
{user.username}
{user.role === "admin" ? "Administrateur" : "Utilisateur"}
{user.role === "user" && ( )}
))}
) : (

Aucun utilisateur trouvé

)}
{/* Dialog de modification */} Modifier l'utilisateur Modifiez les informations de l'utilisateur. Laissez le mot de passe vide pour ne pas le changer.
setEditUsername(e.target.value)} className="min-h-[48px]" data-testid="input-edit-username" />
setEditPassword(e.target.value)} className="min-h-[48px]" data-testid="input-edit-password" />
{/* Dialog de confirmation de suppression */} Confirmer la suppression Êtes-vous sûr de vouloir supprimer l'utilisateur {userToDelete?.username} ? Cette action est irréversible. {deleteUserMutation.isPending ? "Suppression..." : "Supprimer"} Annuler {/* Dialog de gestion des permissions */} Gérer les permissions Sélectionnez les pages auxquelles l'utilisateur {permissionsUser?.username} peut accéder
{allPages && allPages.length > 0 ? (
{allPages.map((page) => (
togglePagePermission(page.id)} className="w-5 h-5" data-testid={`checkbox-page-${page.id}`} />
))}
) : (
Aucune page disponible
)}
); }