import { useState } from "react" import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query" import { useNavigate } from "react-router-dom" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Badge } from "@/components/ui/badge" import { Label } from "@/components/ui/label" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog" import { Search, Download, Eye, UserPlus, Trash2, Key, Upload } from "lucide-react" import { userService } from "@/services" import { toast } from "sonner" import { format } from "date-fns" import type { ApiError } from "@/types/error.types" interface User { id: string email: string firstName: string lastName: string role: string isActive: boolean createdAt: string } export default function UsersPage() { const navigate = useNavigate() const queryClient = useQueryClient() const [page, setPage] = useState(1) const [limit] = useState(20) const [search, setSearch] = useState("") const [roleFilter, setRoleFilter] = useState("all") const [statusFilter, setStatusFilter] = useState("all") const [selectedUser, setSelectedUser] = useState(null) const [deleteDialogOpen, setDeleteDialogOpen] = useState(false) const [resetPasswordDialogOpen, setResetPasswordDialogOpen] = useState(false) const [importDialogOpen, setImportDialogOpen] = useState(false) const [importFile, setImportFile] = useState(null) const { data: usersData, isLoading } = useQuery({ queryKey: ['admin', 'users', page, limit, search, roleFilter, statusFilter], queryFn: async () => { const params: Record = { page, limit } if (search) params.search = search if (roleFilter !== 'all') params.role = roleFilter if (statusFilter !== 'all') params.isActive = statusFilter === 'active' return await userService.getUsers(params) }, }) const deleteUserMutation = useMutation({ mutationFn: ({ id, hard }: { id: string; hard: boolean }) => userService.deleteUser(id, hard), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['admin', 'users'] }) toast.success("User deleted successfully") setDeleteDialogOpen(false) }, onError: (error) => { const apiError = error as ApiError toast.error(apiError.response?.data?.message || "Failed to delete user") }, }) const resetPasswordMutation = useMutation({ mutationFn: (id: string) => userService.resetPassword(id), onSuccess: (data) => { toast.success(`Password reset. Temporary password: ${data.temporaryPassword}`) setResetPasswordDialogOpen(false) }, onError: (error) => { const apiError = error as ApiError toast.error(apiError.response?.data?.message || "Failed to reset password") }, }) const importUsersMutation = useMutation({ mutationFn: (file: File) => userService.importUsers(file), onSuccess: (data) => { queryClient.invalidateQueries({ queryKey: ['admin', 'users'] }) toast.success(`Imported ${data.imported} users. ${data.failed} failed.`) setImportDialogOpen(false) setImportFile(null) }, onError: (error) => { const apiError = error as ApiError toast.error(apiError.response?.data?.message || "Failed to import users") }, }) const handleExport = async () => { try { const blob = await userService.exportUsers('csv') const url = window.URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = `users-${new Date().toISOString()}.csv` a.click() toast.success("Users exported successfully") } catch (error) { const apiError = error as ApiError toast.error(apiError.response?.data?.message || "Failed to export users") } } const handleDelete = () => { if (selectedUser) { deleteUserMutation.mutate({ id: selectedUser.id, hard: false }) } } const handleResetPassword = () => { if (selectedUser) { resetPasswordMutation.mutate(selectedUser.id) } } const handleImport = () => { if (importFile) { importUsersMutation.mutate(importFile) } } const handleFileChange = (e: React.ChangeEvent) => { const file = e.target.files?.[0] if (file) { setImportFile(file) } } const getRoleBadgeVariant = (role: string) => { switch (role) { case 'ADMIN': return 'destructive' case 'USER': return 'default' case 'VIEWER': return 'secondary' default: return 'outline' } } return (

Users Management

All Users
setSearch(e.target.value)} />
{isLoading ? (
Loading users...
) : ( <> Email Name Role Status Created At Actions {usersData?.data?.map((user: User) => ( {user.email} {user.firstName} {user.lastName} {user.role} {user.isActive ? 'Active' : 'Inactive'} {format(new Date(user.createdAt), 'MMM dd, yyyy')}
))}
{usersData?.data?.length === 0 && (
No users found
)} {usersData && usersData.total > limit && (
Showing {(page - 1) * limit + 1} to {Math.min(page * limit, usersData.total)} of {usersData.total} users
)} )}
{/* Delete Dialog */} Delete User Are you sure you want to delete {selectedUser?.email}? This action cannot be undone. {/* Reset Password Dialog */} Reset Password Reset password for {selectedUser?.email}? A temporary password will be generated. {/* Import Users Dialog */} Import Users Upload a CSV file with user data. The file should contain columns: email, firstName, lastName, role (optional).
{importFile && (

Selected: {importFile.name}

)}
) }