From 3c3d86855c649c85f49c47f688039057ffec4a10 Mon Sep 17 00:00:00 2001
From: Mohamed Bassem <me@mbassem.com>
Date: Mon, 29 Dec 2025 08:56:45 +0000
Subject: refactor: add suspense boundary in sidebar layout

---
 apps/web/components/admin/UserList.tsx | 218 ++++++++++++++++-----------------
 1 file changed, 103 insertions(+), 115 deletions(-)

(limited to 'apps/web/components/admin/UserList.tsx')

diff --git a/apps/web/components/admin/UserList.tsx b/apps/web/components/admin/UserList.tsx
index 3a382a3b..91467f94 100644
--- a/apps/web/components/admin/UserList.tsx
+++ b/apps/web/components/admin/UserList.tsx
@@ -3,7 +3,6 @@
 import { ActionButton } from "@/components/ui/action-button";
 import { ButtonWithTooltip } from "@/components/ui/button";
 import { toast } from "@/components/ui/sonner";
-import LoadingSpinner from "@/components/ui/spinner";
 import {
   Table,
   TableBody,
@@ -20,7 +19,6 @@ import { useSession } from "next-auth/react";
 import ActionConfirmingDialog from "../ui/action-confirming-dialog";
 import AddUserDialog from "./AddUserDialog";
 import { AdminCard } from "./AdminCard";
-import InvitesList from "./InvitesList";
 import ResetPasswordDialog from "./ResetPasswordDialog";
 import UpdateUserDialog from "./UpdateUserDialog";
 
@@ -35,8 +33,8 @@ 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 [{ users }] = api.users.list.useSuspenseQuery();
+  const [userStats] = api.admin.userStats.useSuspenseQuery();
   const { mutateAsync: deleteUser, isPending: isDeletionPending } =
     api.users.delete.useMutation({
       onSuccess: () => {
@@ -53,120 +51,110 @@ export default function UsersSection() {
       },
     });
 
-  if (!users || !userStats) {
-    return <LoadingSpinner />;
-  }
-
   return (
-    <div className="flex flex-col gap-4">
-      <AdminCard>
-        <div className="flex flex-col gap-4">
-          <div className="mb-2 flex items-center justify-between text-xl font-medium">
-            <span>{t("admin.users_list.users_list")}</span>
-            <AddUserDialog>
-              <ButtonWithTooltip tooltip="Create User" variant="outline">
-                <UserPlus size={16} />
-              </ButtonWithTooltip>
-            </AddUserDialog>
-          </div>
+    <AdminCard>
+      <div className="flex flex-col gap-4">
+        <div className="mb-2 flex items-center justify-between text-xl font-medium">
+          <span>{t("admin.users_list.users_list")}</span>
+          <AddUserDialog>
+            <ButtonWithTooltip tooltip="Create User" variant="outline">
+              <UserPlus size={16} />
+            </ButtonWithTooltip>
+          </AddUserDialog>
+        </div>
 
-          <Table>
-            <TableHeader className="bg-gray-200">
-              <TableRow>
-                <TableHead>{t("common.name")}</TableHead>
-                <TableHead>{t("common.email")}</TableHead>
-                <TableHead>{t("admin.users_list.num_bookmarks")}</TableHead>
-                <TableHead>{t("admin.users_list.asset_sizes")}</TableHead>
-                <TableHead>{t("common.role")}</TableHead>
-                <TableHead>{t("admin.users_list.local_user")}</TableHead>
-                <TableHead>{t("common.actions")}</TableHead>
-              </TableRow>
-            </TableHeader>
-            <TableBody>
-              {users.users.map((u) => (
-                <TableRow key={u.id}>
-                  <TableCell className="py-1">{u.name}</TableCell>
-                  <TableCell className="py-1">{u.email}</TableCell>
-                  <TableCell className="py-1">
-                    {userStats[u.id].numBookmarks} /{" "}
-                    {u.bookmarkQuota ?? t("admin.users_list.unlimited")}
-                  </TableCell>
-                  <TableCell className="py-1">
-                    {toHumanReadableSize(userStats[u.id].assetSizes)} /{" "}
-                    {u.storageQuota
-                      ? toHumanReadableSize(u.storageQuota)
-                      : t("admin.users_list.unlimited")}
-                  </TableCell>
-                  <TableCell className="py-1">
-                    {u.role && t(`common.roles.${u.role}`)}
-                  </TableCell>
-                  <TableCell className="py-1">
-                    {u.localUser ? <Check /> : <X />}
-                  </TableCell>
-                  <TableCell className="flex gap-1 py-1">
-                    <ActionConfirmingDialog
-                      title={t("admin.users_list.delete_user")}
-                      description={t(
-                        "admin.users_list.delete_user_confirm_description",
-                        {
-                          name: u.name ?? "this user",
-                        },
-                      )}
-                      actionButton={(setDialogOpen) => (
-                        <ActionButton
-                          variant="destructive"
-                          loading={isDeletionPending}
-                          onClick={async () => {
-                            await deleteUser({ userId: u.id });
-                            setDialogOpen(false);
-                          }}
-                        >
-                          Delete
-                        </ActionButton>
-                      )}
-                    >
-                      <ButtonWithTooltip
-                        tooltip={t("admin.users_list.delete_user")}
-                        variant="outline"
-                        disabled={session!.user.id == u.id}
-                      >
-                        <Trash size={16} color="red" />
-                      </ButtonWithTooltip>
-                    </ActionConfirmingDialog>
-                    <ResetPasswordDialog userId={u.id}>
-                      <ButtonWithTooltip
-                        tooltip={t("admin.users_list.reset_password")}
-                        variant="outline"
-                        disabled={session!.user.id == u.id || !u.localUser}
+        <Table>
+          <TableHeader className="bg-gray-200">
+            <TableRow>
+              <TableHead>{t("common.name")}</TableHead>
+              <TableHead>{t("common.email")}</TableHead>
+              <TableHead>{t("admin.users_list.num_bookmarks")}</TableHead>
+              <TableHead>{t("admin.users_list.asset_sizes")}</TableHead>
+              <TableHead>{t("common.role")}</TableHead>
+              <TableHead>{t("admin.users_list.local_user")}</TableHead>
+              <TableHead>{t("common.actions")}</TableHead>
+            </TableRow>
+          </TableHeader>
+          <TableBody>
+            {users.map((u) => (
+              <TableRow key={u.id}>
+                <TableCell className="py-1">{u.name}</TableCell>
+                <TableCell className="py-1">{u.email}</TableCell>
+                <TableCell className="py-1">
+                  {userStats[u.id].numBookmarks} /{" "}
+                  {u.bookmarkQuota ?? t("admin.users_list.unlimited")}
+                </TableCell>
+                <TableCell className="py-1">
+                  {toHumanReadableSize(userStats[u.id].assetSizes)} /{" "}
+                  {u.storageQuota
+                    ? toHumanReadableSize(u.storageQuota)
+                    : t("admin.users_list.unlimited")}
+                </TableCell>
+                <TableCell className="py-1">
+                  {u.role && t(`common.roles.${u.role}`)}
+                </TableCell>
+                <TableCell className="py-1">
+                  {u.localUser ? <Check /> : <X />}
+                </TableCell>
+                <TableCell className="flex gap-1 py-1">
+                  <ActionConfirmingDialog
+                    title={t("admin.users_list.delete_user")}
+                    description={t(
+                      "admin.users_list.delete_user_confirm_description",
+                      {
+                        name: u.name ?? "this user",
+                      },
+                    )}
+                    actionButton={(setDialogOpen) => (
+                      <ActionButton
+                        variant="destructive"
+                        loading={isDeletionPending}
+                        onClick={async () => {
+                          await deleteUser({ userId: u.id });
+                          setDialogOpen(false);
+                        }}
                       >
-                        <KeyRound size={16} color="red" />
-                      </ButtonWithTooltip>
-                    </ResetPasswordDialog>
-                    <UpdateUserDialog
-                      userId={u.id}
-                      currentRole={u.role!}
-                      currentQuota={u.bookmarkQuota}
-                      currentStorageQuota={u.storageQuota}
+                        Delete
+                      </ActionButton>
+                    )}
+                  >
+                    <ButtonWithTooltip
+                      tooltip={t("admin.users_list.delete_user")}
+                      variant="outline"
+                      disabled={session!.user.id == u.id}
                     >
-                      <ButtonWithTooltip
-                        tooltip="Edit User"
-                        variant="outline"
-                        disabled={session!.user.id == u.id}
-                      >
-                        <Pencil size={16} color="red" />
-                      </ButtonWithTooltip>
-                    </UpdateUserDialog>
-                  </TableCell>
-                </TableRow>
-              ))}
-            </TableBody>
-          </Table>
-        </div>
-      </AdminCard>
-
-      <AdminCard>
-        <InvitesList />
-      </AdminCard>
-    </div>
+                      <Trash size={16} color="red" />
+                    </ButtonWithTooltip>
+                  </ActionConfirmingDialog>
+                  <ResetPasswordDialog userId={u.id}>
+                    <ButtonWithTooltip
+                      tooltip={t("admin.users_list.reset_password")}
+                      variant="outline"
+                      disabled={session!.user.id == u.id || !u.localUser}
+                    >
+                      <KeyRound size={16} color="red" />
+                    </ButtonWithTooltip>
+                  </ResetPasswordDialog>
+                  <UpdateUserDialog
+                    userId={u.id}
+                    currentRole={u.role!}
+                    currentQuota={u.bookmarkQuota}
+                    currentStorageQuota={u.storageQuota}
+                  >
+                    <ButtonWithTooltip
+                      tooltip="Edit User"
+                      variant="outline"
+                      disabled={session!.user.id == u.id}
+                    >
+                      <Pencil size={16} color="red" />
+                    </ButtonWithTooltip>
+                  </UpdateUserDialog>
+                </TableCell>
+              </TableRow>
+            ))}
+          </TableBody>
+        </Table>
+      </div>
+    </AdminCard>
   );
 }
-- 
cgit v1.2.3-70-g09d2

