import { useState } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, DialogDescription } from "@/components/ui/dialog"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { Badge } from "@/components/ui/badge"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { useToast } from "@/hooks/use-toast"; import { apiRequest } from "@/lib/queryClient"; import { insertUserSchema, insertStoreSchema, type User, type Store } from "@shared/schema"; import { Users, Building2, Plus, Edit, Trash2, Settings } from "lucide-react"; import { z } from "zod"; const createUserSchema = insertUserSchema.extend({ confirmPassword: z.string(), }).refine((data) => data.password === data.confirmPassword, { message: "Les mots de passe ne correspondent pas", path: ["confirmPassword"], }); const editUserSchema = insertUserSchema.partial().extend({ id: z.number(), password: z.string().optional(), confirmPassword: z.string().optional(), }).refine((data) => { if (data.password || data.confirmPassword) { return data.password === data.confirmPassword; } return true; }, { message: "Les mots de passe ne correspondent pas", path: ["confirmPassword"], }); const editStoreSchema = insertStoreSchema.extend({ id: z.number(), }); type CreateUserData = z.infer; type EditUserData = z.infer; type EditStoreData = z.infer; export default function Administration() { const { toast } = useToast(); const queryClient = useQueryClient(); const [isUserDialogOpen, setIsUserDialogOpen] = useState(false); const [isStoreDialogOpen, setIsStoreDialogOpen] = useState(false); const [editingUser, setEditingUser] = useState(null); const [editingStore, setEditingStore] = useState(null); // Queries const { data: users = [], isLoading: usersLoading } = useQuery({ queryKey: ['/api/admin/users'], queryFn: async () => { const response = await apiRequest('/api/admin/users'); return response.json(); }, }); const { data: stores = [], isLoading: storesLoading } = useQuery({ queryKey: ['/api/admin/stores'], queryFn: async () => { const response = await apiRequest('/api/admin/stores'); return response.json(); }, }); // User mutations const createUserMutation = useMutation({ mutationFn: async (userData: CreateUserData) => { const { confirmPassword, ...data } = userData; const response = await apiRequest('/api/admin/users', { method: 'POST', body: JSON.stringify(data), }); return response.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['/api/admin/users'] }); setIsUserDialogOpen(false); userForm.reset(); toast({ title: "Utilisateur créé avec succès" }); }, onError: () => { toast({ title: "Erreur", description: "Impossible de créer l'utilisateur", variant: "destructive" }); }, }); const updateUserMutation = useMutation({ mutationFn: async (userData: EditUserData) => { const { id, confirmPassword, ...data } = userData; const response = await apiRequest(`/api/admin/users/${id}`, { method: 'PUT', body: JSON.stringify(data), }); return response.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['/api/admin/users'] }); setEditingUser(null); editUserForm.reset(); toast({ title: "Utilisateur modifié avec succès" }); }, onError: () => { toast({ title: "Erreur", description: "Impossible de modifier l'utilisateur", variant: "destructive" }); }, }); const deleteUserMutation = useMutation({ mutationFn: async (userId: number) => { await apiRequest(`/api/admin/users/${userId}`, { method: 'DELETE' }); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['/api/admin/users'] }); toast({ title: "Utilisateur supprimé avec succès" }); }, onError: () => { toast({ title: "Erreur", description: "Impossible de supprimer l'utilisateur", variant: "destructive" }); }, }); // Store mutations const createStoreMutation = useMutation({ mutationFn: async (storeData: z.infer) => { const response = await apiRequest('/api/admin/stores', { method: 'POST', body: JSON.stringify(storeData), }); return response.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['/api/admin/stores'] }); setIsStoreDialogOpen(false); storeForm.reset(); toast({ title: "Magasin créé avec succès" }); }, onError: () => { toast({ title: "Erreur", description: "Impossible de créer le magasin", variant: "destructive" }); }, }); const updateStoreMutation = useMutation({ mutationFn: async (storeData: EditStoreData) => { const { id, ...data } = storeData; const response = await apiRequest(`/api/admin/stores/${id}`, { method: 'PUT', body: JSON.stringify(data), }); return response.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['/api/admin/stores'] }); setEditingStore(null); editStoreForm.reset(); toast({ title: "Magasin modifié avec succès" }); }, onError: () => { toast({ title: "Erreur", description: "Impossible de modifier le magasin", variant: "destructive" }); }, }); const deleteStoreMutation = useMutation({ mutationFn: async (storeId: number) => { await apiRequest(`/api/admin/stores/${storeId}`, { method: 'DELETE' }); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['/api/admin/stores'] }); toast({ title: "Magasin supprimé avec succès" }); }, onError: () => { toast({ title: "Erreur", description: "Impossible de supprimer le magasin", variant: "destructive" }); }, }); // Forms const userForm = useForm({ resolver: zodResolver(createUserSchema), defaultValues: { username: "", password: "", confirmPassword: "", email: "", firstName: "", lastName: "", role: "employee", storeId: undefined, isActive: true, }, }); const editUserForm = useForm({ resolver: zodResolver(editUserSchema), }); const storeForm = useForm>({ resolver: zodResolver(insertStoreSchema), defaultValues: { name: "", address: "", phone: "", email: "", isActive: true, }, }); const editStoreForm = useForm({ resolver: zodResolver(editStoreSchema), }); // Handlers const onCreateUser = async (data: CreateUserData) => { await createUserMutation.mutateAsync(data); }; const onEditUser = async (data: EditUserData) => { await updateUserMutation.mutateAsync(data); }; const onCreateStore = async (data: z.infer) => { await createStoreMutation.mutateAsync(data); }; const onEditStore = async (data: EditStoreData) => { await updateStoreMutation.mutateAsync(data); }; const handleEditUser = (user: User) => { setEditingUser(user); editUserForm.reset({ id: user.id, username: user.username, email: user.email || "", firstName: user.firstName || "", lastName: user.lastName || "", role: user.role, storeId: user.storeId || undefined, isActive: user.isActive, password: "", confirmPassword: "", }); }; const handleEditStore = (store: Store) => { setEditingStore(store); editStoreForm.reset({ id: store.id, name: store.name, address: store.address || "", phone: store.phone || "", email: store.email || "", isActive: store.isActive, }); }; const handleDeleteUser = async (user: User) => { if (window.confirm(`Êtes-vous sûr de vouloir supprimer l'utilisateur "${user.username}" ?`)) { await deleteUserMutation.mutateAsync(user.id); } }; const handleDeleteStore = async (store: Store) => { if (window.confirm(`Êtes-vous sûr de vouloir supprimer le magasin "${store.name}" ?`)) { await deleteStoreMutation.mutateAsync(store.id); } }; const getRoleBadge = (role: string) => { const variants = { administrator: "destructive" as const, manager: "default" as const, employee: "secondary" as const, }; const labels = { administrator: "Administrateur", manager: "Manager", employee: "Employé", }; return ( {labels[role as keyof typeof labels] || role} ); }; return ( Administration Utilisateurs Magasins {/* Users Tab */}

Gestion des Utilisateurs

Créer un nouvel utilisateur Ajoutez un nouvel utilisateur au système
( Nom d'utilisateur * )} /> ( Email )} />
( Prénom )} /> ( Nom )} />
( Mot de passe * )} /> ( Confirmer le mot de passe * )} />
( Rôle * )} /> ( Magasin )} />
{usersLoading ? (
Chargement...
) : ( Utilisateur Email Rôle Magasin Statut Actions {users.map((user) => (
{user.username}
{(user.firstName || user.lastName) && (
{user.firstName} {user.lastName}
)}
{user.email || "-"} {getRoleBadge(user.role)} {stores.find(s => s.id === user.storeId)?.name || "-"} {user.isActive ? "Actif" : "Inactif"}
))}
)} {/* Edit User Dialog */} !open && setEditingUser(null)}> Modifier l'utilisateur Modifiez les informations de l'utilisateur {editingUser && (
( Nom d'utilisateur )} /> ( Email )} />
( Prénom )} /> ( Nom )} />
( Nouveau mot de passe (optionnel) )} /> ( Confirmer le mot de passe )} />
( Rôle )} /> ( Magasin )} />
)}
{/* Stores Tab */}

Gestion des Magasins

Créer un nouveau magasin Ajoutez un nouveau magasin au système
( Nom du magasin * )} /> ( Adresse )} />
( Téléphone )} /> ( Email )} />
{storesLoading ? (
Chargement...
) : ( Nom Adresse Téléphone Email Statut Actions {stores.map((store) => ( {store.name} {store.address || "-"} {store.phone || "-"} {store.email || "-"} {store.isActive ? "Actif" : "Inactif"}
))}
)} {/* Edit Store Dialog */} !open && setEditingStore(null)}> Modifier le magasin Modifiez les informations du magasin {editingStore && (
( Nom du magasin )} /> ( Adresse )} />
( Téléphone )} /> ( Email )} />
)}
); }