From 179f00b15525b024b6823088ef8fb94b7106b4f0 Mon Sep 17 00:00:00 2001 From: Mohamed Bassem Date: Mon, 30 Dec 2024 11:27:32 +0000 Subject: feat: Change the admin page to be tabbed similar to that of the settings page --- apps/web/components/admin/UserList.tsx | 130 +++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 apps/web/components/admin/UserList.tsx (limited to 'apps/web/components/admin/UserList.tsx') diff --git a/apps/web/components/admin/UserList.tsx b/apps/web/components/admin/UserList.tsx new file mode 100644 index 00000000..3dfcaad1 --- /dev/null +++ b/apps/web/components/admin/UserList.tsx @@ -0,0 +1,130 @@ +"use client"; + +import { ActionButtonWithTooltip } from "@/components/ui/action-button"; +import { ButtonWithTooltip } from "@/components/ui/button"; +import LoadingSpinner from "@/components/ui/spinner"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { toast } from "@/components/ui/use-toast"; +import { useTranslation } from "@/lib/i18n/client"; +import { api } from "@/lib/trpc"; +import { Check, KeyRound, Pencil, Trash, UserPlus, X } from "lucide-react"; +import { useSession } from "next-auth/react"; + +import AddUserDialog from "./AddUserDialog"; +import ChangeRoleDialog from "./ChangeRoleDialog"; +import ResetPasswordDialog from "./ResetPasswordDialog"; + +function toHumanReadableSize(size: number) { + const sizes = ["Bytes", "KB", "MB", "GB", "TB"]; + if (size === 0) return "0 Bytes"; + const i = Math.floor(Math.log(size) / Math.log(1024)); + return (size / Math.pow(1024, i)).toFixed(2) + " " + sizes[i]; +} + +export default function UsersSection() { + const { t } = useTranslation(); + const { data: session } = useSession(); + const invalidateUserList = api.useUtils().users.list.invalidate; + const { data: users } = api.users.list.useQuery(); + const { data: userStats } = api.admin.userStats.useQuery(); + const { mutate: deleteUser, isPending: isDeletionPending } = + api.users.delete.useMutation({ + onSuccess: () => { + toast({ + description: "User deleted", + }); + invalidateUserList(); + }, + onError: (e) => { + toast({ + variant: "destructive", + description: `Something went wrong: ${e.message}`, + }); + }, + }); + + if (!users || !userStats) { + return ; + } + + return ( +
+
+ {t("admin.users_list.users_list")} + + + + + +
+ + + + {t("common.name")} + {t("common.email")} + {t("admin.users_list.num_bookmarks")} + {t("admin.users_list.asset_sizes")} + {t("common.role")} + {t("admin.users_list.local_user")} + {t("common.actions")} + + + {users.users.map((u) => ( + + {u.name} + {u.email} + + {userStats[u.id].numBookmarks} + + + {toHumanReadableSize(userStats[u.id].assetSizes)} + + + {u.role && t(`common.roles.${u.role}`)} + + + {u.localUser ? : } + + + deleteUser({ userId: u.id })} + loading={isDeletionPending} + disabled={session!.user.id == u.id} + > + + + + + + + + + + + + + + + ))} + +
+
+ ); +} -- cgit v1.2.3-70-g09d2