import { useMutation, useQuery } from "@tanstack/react-query"; import { Shield, ShieldAlert, UserMinus, UserCheck, Trash2, Search, AlertTriangle } from "lucide-react"; import { useState } from "react"; import { toast } from "sonner"; import { authClient } from "~/client/lib/auth-client"; import { Button } from "~/client/components/ui/button"; import { cn } from "~/client/lib/utils"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "~/client/components/ui/table"; import { Badge } from "~/client/components/ui/badge"; import { Input } from "~/client/components/ui/input"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "~/client/components/ui/dialog"; import { CreateUserDialog } from "./create-user-dialog"; import { getUserDeletionImpactOptions } from "~/client/api-client/@tanstack/react-query.gen"; export function UserManagement() { const { data: session } = authClient.useSession(); const currentUser = session?.user; const [search, setSearch] = useState(""); const [userToDelete, setUserToDelete] = useState(null); const [userToBan, setUserToBan] = useState<{ id: string; name: string; isBanned: boolean } | null>(null); const { data: deletionImpact, isLoading: isLoadingImpact } = useQuery({ ...getUserDeletionImpactOptions({ path: { userId: userToDelete ?? "" } }), enabled: Boolean(userToDelete), }); const { data, isLoading, refetch } = useQuery({ queryKey: ["admin-users"], queryFn: async () => { const { data, error } = await authClient.admin.listUsers({ query: { limit: 100 } }); if (error) throw error; return data; }, }); const setRoleMutation = useMutation({ mutationFn: async ({ userId, role }: { userId: string; role: "user" | "admin" }) => { const { error } = await authClient.admin.setRole({ userId, role }); if (error) throw error; }, onSuccess: () => { toast.success("User role updated successfully"); void refetch(); }, onError: (err: any) => { toast.error("Failed to update role", { description: err.message }); }, }); const toggleBanUserMutation = useMutation({ mutationFn: async ({ userId, ban }: { userId: string; ban: boolean }) => { const { error } = ban ? await authClient.admin.banUser({ userId }) : await authClient.admin.unbanUser({ userId }); if (error) throw error; }, onSuccess: () => { toast.success("User ban status updated successfully"); void refetch(); }, onMutate: () => { setUserToBan(null); }, onError: (err: any) => { toast.error("Failed to update ban status", { description: err.message }); }, }); const filteredUsers = data?.users.filter( (user) => user.name.toLowerCase().includes(search.toLowerCase()) || user.email.toLowerCase().includes(search.toLowerCase()) || (user as any).username?.toLowerCase().includes(search.toLowerCase()), ); const handleDeleteUser = async () => { if (!userToDelete) return; try { const { error } = await authClient.admin.removeUser({ userId: userToDelete }); if (error) throw error; toast.success("User deleted successfully"); setUserToDelete(null); void refetch(); } catch (err: any) { toast.error("Failed to delete user", { description: err.message }); } }; return (
setSearch(e.target.value)} />
void refetch()} />
User Role Status Actions Loading users... 0) })}> No users found. {filteredUsers?.map((user) => (
{user.name} {user.email}
{user.role} Banned Active
))}
!open && setUserToDelete(null)}> Are you absolutely sure? This action cannot be undone. This will permanently delete the user account and remove their data from our servers.

Important: Data Deletion

The following personal organizations and all their associated resources will be permanently deleted:

{deletionImpact?.organizations.map((org) => (

{org.name}

{org.resources.volumesCount} Volumes {org.resources.repositoriesCount} Repositories {org.resources.backupSchedulesCount} Backups
))}

Analyzing deletion impact...

!open && setUserToBan(null)}> {userToBan?.isBanned ? "Unban" : "Ban"} User Are you sure you want to {userToBan?.isBanned ? "unban" : "ban"} {userToBan?.name}? {userToBan?.isBanned ? " They will regain access to the system." : " They will be immediately signed out and lose access."}
); }