aboutsummaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorMohamed Bassem <me@mbassem.com>2024-12-30 11:27:32 +0000
committerMohamed Bassem <me@mbassem.com>2024-12-30 11:31:35 +0000
commit179f00b15525b024b6823088ef8fb94b7106b4f0 (patch)
treed64257778930965ed076ff9a081411470343fb3c /apps
parentaff4e60952321d06dc4cf517ff3b15206aaaebba (diff)
downloadkarakeep-179f00b15525b024b6823088ef8fb94b7106b4f0.tar.zst
feat: Change the admin page to be tabbed similar to that of the settings page
Diffstat (limited to 'apps')
-rw-r--r--apps/web/app/admin/actions/page.tsx5
-rw-r--r--apps/web/app/admin/layout.tsx40
-rw-r--r--apps/web/app/admin/overview/page.tsx5
-rw-r--r--apps/web/app/admin/page.tsx6
-rw-r--r--apps/web/app/admin/users/page.tsx5
-rw-r--r--apps/web/app/dashboard/admin/page.tsx26
-rw-r--r--apps/web/components/admin/AddUserDialog.tsx (renamed from apps/web/components/dashboard/admin/AddUserDialog.tsx)0
-rw-r--r--apps/web/components/admin/AdminActions.tsx (renamed from apps/web/components/dashboard/admin/AdminActions.tsx)2
-rw-r--r--apps/web/components/admin/AdminCard.tsx (renamed from apps/web/components/dashboard/admin/AdminCard.tsx)0
-rw-r--r--apps/web/components/admin/AdminNotices.tsx (renamed from apps/web/components/dashboard/admin/AdminNotices.tsx)0
-rw-r--r--apps/web/components/admin/ChangeRoleDialog.tsx (renamed from apps/web/components/dashboard/admin/ChangeRoleDialog.tsx)0
-rw-r--r--apps/web/components/admin/ResetPasswordDialog.tsx (renamed from apps/web/components/dashboard/admin/ResetPasswordDialog.tsx)0
-rw-r--r--apps/web/components/admin/ServerStats.tsx (renamed from apps/web/components/dashboard/admin/ServerStats.tsx)4
-rw-r--r--apps/web/components/admin/UserList.tsx (renamed from apps/web/components/dashboard/admin/UserList.tsx)4
-rw-r--r--apps/web/components/admin/sidebar/MobileSidebar.tsx21
-rw-r--r--apps/web/components/admin/sidebar/Sidebar.tsx36
-rw-r--r--apps/web/components/admin/sidebar/items.tsx31
-rw-r--r--apps/web/components/dashboard/header/ProfileOptions.tsx4
18 files changed, 156 insertions, 33 deletions
diff --git a/apps/web/app/admin/actions/page.tsx b/apps/web/app/admin/actions/page.tsx
new file mode 100644
index 00000000..51f7e5d4
--- /dev/null
+++ b/apps/web/app/admin/actions/page.tsx
@@ -0,0 +1,5 @@
+import AdminActions from "@/components/admin/AdminActions";
+
+export default function AdminActionsPage() {
+ return <AdminActions />;
+}
diff --git a/apps/web/app/admin/layout.tsx b/apps/web/app/admin/layout.tsx
new file mode 100644
index 00000000..0d876736
--- /dev/null
+++ b/apps/web/app/admin/layout.tsx
@@ -0,0 +1,40 @@
+import { redirect } from "next/navigation";
+import { AdminCard } from "@/components/admin/AdminCard";
+import { AdminNotices } from "@/components/admin/AdminNotices";
+import MobileAdminSidebar from "@/components/admin/sidebar/MobileSidebar";
+import AdminSidebar from "@/components/admin/sidebar/Sidebar";
+import Header from "@/components/dashboard/header/Header";
+import { Separator } from "@/components/ui/separator";
+import { getServerAuthSession } from "@/server/auth";
+
+export default async function AdminLayout({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) {
+ const session = await getServerAuthSession();
+ if (!session || session.user.role !== "admin") {
+ redirect("/");
+ }
+
+ return (
+ <div>
+ <Header />
+ <div className="flex min-h-[calc(100vh-64px)] w-screen flex-col sm:h-[calc(100vh-64px)] sm:flex-row">
+ <div className="hidden flex-none sm:flex">
+ <AdminSidebar />
+ </div>
+ <main className="flex-1 bg-muted sm:overflow-y-auto">
+ <div className="block w-full sm:hidden">
+ <MobileAdminSidebar />
+ <Separator />
+ </div>
+ <div className="min-h-30 container flex flex-col gap-1 p-4">
+ <AdminNotices />
+ <AdminCard>{children}</AdminCard>
+ </div>
+ </main>
+ </div>
+ </div>
+ );
+}
diff --git a/apps/web/app/admin/overview/page.tsx b/apps/web/app/admin/overview/page.tsx
new file mode 100644
index 00000000..226fb9d5
--- /dev/null
+++ b/apps/web/app/admin/overview/page.tsx
@@ -0,0 +1,5 @@
+import ServerStats from "@/components/admin/ServerStats";
+
+export default function AdminOverviewPage() {
+ return <ServerStats />;
+}
diff --git a/apps/web/app/admin/page.tsx b/apps/web/app/admin/page.tsx
new file mode 100644
index 00000000..7fed8185
--- /dev/null
+++ b/apps/web/app/admin/page.tsx
@@ -0,0 +1,6 @@
+import { redirect } from "next/navigation";
+
+export default function AdminHomepage() {
+ redirect("/admin/overview");
+ return null;
+}
diff --git a/apps/web/app/admin/users/page.tsx b/apps/web/app/admin/users/page.tsx
new file mode 100644
index 00000000..be5cfe81
--- /dev/null
+++ b/apps/web/app/admin/users/page.tsx
@@ -0,0 +1,5 @@
+import UserList from "@/components/admin/UserList";
+
+export default function AdminUsersPage() {
+ return <UserList />;
+}
diff --git a/apps/web/app/dashboard/admin/page.tsx b/apps/web/app/dashboard/admin/page.tsx
deleted file mode 100644
index cf97698b..00000000
--- a/apps/web/app/dashboard/admin/page.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import { redirect } from "next/navigation";
-import AdminActions from "@/components/dashboard/admin/AdminActions";
-import { AdminCard } from "@/components/dashboard/admin/AdminCard";
-import { AdminNotices } from "@/components/dashboard/admin/AdminNotices";
-import ServerStats from "@/components/dashboard/admin/ServerStats";
-import UserList from "@/components/dashboard/admin/UserList";
-import { getServerAuthSession } from "@/server/auth";
-
-export default async function AdminPage() {
- const session = await getServerAuthSession();
- if (!session || session.user.role !== "admin") {
- redirect("/");
- }
- return (
- <div className="flex flex-col gap-4">
- <AdminNotices />
- <AdminCard>
- <ServerStats />
- <AdminActions />
- </AdminCard>
- <AdminCard>
- <UserList />
- </AdminCard>
- </div>
- );
-}
diff --git a/apps/web/components/dashboard/admin/AddUserDialog.tsx b/apps/web/components/admin/AddUserDialog.tsx
index a13c6b88..a13c6b88 100644
--- a/apps/web/components/dashboard/admin/AddUserDialog.tsx
+++ b/apps/web/components/admin/AddUserDialog.tsx
diff --git a/apps/web/components/dashboard/admin/AdminActions.tsx b/apps/web/components/admin/AdminActions.tsx
index 3b95045c..34b3d63a 100644
--- a/apps/web/components/dashboard/admin/AdminActions.tsx
+++ b/apps/web/components/admin/AdminActions.tsx
@@ -71,7 +71,7 @@ export default function AdminActions() {
return (
<div>
- <div className="mb-2 mt-8 text-xl font-medium">{t("common.actions")}</div>
+ <div className="mb-2 text-xl font-medium">{t("common.actions")}</div>
<div className="flex flex-col gap-2 sm:w-1/2">
<ActionButton
variant="destructive"
diff --git a/apps/web/components/dashboard/admin/AdminCard.tsx b/apps/web/components/admin/AdminCard.tsx
index 3a52b5e5..3a52b5e5 100644
--- a/apps/web/components/dashboard/admin/AdminCard.tsx
+++ b/apps/web/components/admin/AdminCard.tsx
diff --git a/apps/web/components/dashboard/admin/AdminNotices.tsx b/apps/web/components/admin/AdminNotices.tsx
index 4977736f..4977736f 100644
--- a/apps/web/components/dashboard/admin/AdminNotices.tsx
+++ b/apps/web/components/admin/AdminNotices.tsx
diff --git a/apps/web/components/dashboard/admin/ChangeRoleDialog.tsx b/apps/web/components/admin/ChangeRoleDialog.tsx
index 26ad5dce..26ad5dce 100644
--- a/apps/web/components/dashboard/admin/ChangeRoleDialog.tsx
+++ b/apps/web/components/admin/ChangeRoleDialog.tsx
diff --git a/apps/web/components/dashboard/admin/ResetPasswordDialog.tsx b/apps/web/components/admin/ResetPasswordDialog.tsx
index 32183d1a..32183d1a 100644
--- a/apps/web/components/dashboard/admin/ResetPasswordDialog.tsx
+++ b/apps/web/components/admin/ResetPasswordDialog.tsx
diff --git a/apps/web/components/dashboard/admin/ServerStats.tsx b/apps/web/components/admin/ServerStats.tsx
index da69390b..1f0c7e9d 100644
--- a/apps/web/components/dashboard/admin/ServerStats.tsx
+++ b/apps/web/components/admin/ServerStats.tsx
@@ -73,7 +73,7 @@ export default function ServerStats() {
}
return (
- <>
+ <div className="flex flex-col gap-4">
<div className="mb-2 text-xl font-medium">
{t("admin.server_stats.server_stats")}
</div>
@@ -143,6 +143,6 @@ export default function ServerStats() {
</TableBody>
</Table>
</div>
- </>
+ </div>
);
}
diff --git a/apps/web/components/dashboard/admin/UserList.tsx b/apps/web/components/admin/UserList.tsx
index 8c788ef4..3dfcaad1 100644
--- a/apps/web/components/dashboard/admin/UserList.tsx
+++ b/apps/web/components/admin/UserList.tsx
@@ -55,7 +55,7 @@ export default function UsersSection() {
}
return (
- <>
+ <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>
@@ -125,6 +125,6 @@ export default function UsersSection() {
))}
</TableBody>
</Table>
- </>
+ </div>
);
}
diff --git a/apps/web/components/admin/sidebar/MobileSidebar.tsx b/apps/web/components/admin/sidebar/MobileSidebar.tsx
new file mode 100644
index 00000000..416b944c
--- /dev/null
+++ b/apps/web/components/admin/sidebar/MobileSidebar.tsx
@@ -0,0 +1,21 @@
+import MobileSidebarItem from "@/components/shared/sidebar/ModileSidebarItem";
+import { useTranslation } from "@/lib/i18n/server";
+
+import { adminSidebarItems } from "./items";
+
+export default async function MobileSidebar() {
+ const { t } = await useTranslation();
+ return (
+ <aside className="w-full">
+ <ul className="flex justify-between space-x-2 border-b-black px-5 py-2 pt-5">
+ {adminSidebarItems(t).map((item) => (
+ <MobileSidebarItem
+ key={item.name}
+ logo={item.icon}
+ path={item.path}
+ />
+ ))}
+ </ul>
+ </aside>
+ );
+}
diff --git a/apps/web/components/admin/sidebar/Sidebar.tsx b/apps/web/components/admin/sidebar/Sidebar.tsx
new file mode 100644
index 00000000..8a5d615a
--- /dev/null
+++ b/apps/web/components/admin/sidebar/Sidebar.tsx
@@ -0,0 +1,36 @@
+import { redirect } from "next/navigation";
+import SidebarItem from "@/components/shared/sidebar/SidebarItem";
+import { useTranslation } from "@/lib/i18n/server";
+import { getServerAuthSession } from "@/server/auth";
+
+import serverConfig from "@hoarder/shared/config";
+
+import { adminSidebarItems } from "./items";
+
+export default async function Sidebar() {
+ const { t } = await useTranslation();
+ const session = await getServerAuthSession();
+ if (!session) {
+ redirect("/");
+ }
+
+ return (
+ <aside className="flex h-[calc(100vh-64px)] w-60 flex-col gap-5 border-r p-4 ">
+ <div>
+ <ul className="space-y-2 text-sm font-medium">
+ {adminSidebarItems(t).map((item) => (
+ <SidebarItem
+ key={item.name}
+ logo={item.icon}
+ name={item.name}
+ path={item.path}
+ />
+ ))}
+ </ul>
+ </div>
+ <div className="mt-auto flex items-center border-t pt-2 text-sm text-gray-400">
+ Hoarder v{serverConfig.serverVersion}
+ </div>
+ </aside>
+ );
+}
diff --git a/apps/web/components/admin/sidebar/items.tsx b/apps/web/components/admin/sidebar/items.tsx
new file mode 100644
index 00000000..78dfee34
--- /dev/null
+++ b/apps/web/components/admin/sidebar/items.tsx
@@ -0,0 +1,31 @@
+import { TFunction } from "i18next";
+import { Activity, ArrowLeft, Settings, Users } from "lucide-react";
+
+export const adminSidebarItems = (
+ t: TFunction,
+): {
+ name: string;
+ icon: JSX.Element;
+ path: string;
+}[] => [
+ {
+ name: t("settings.back_to_app"),
+ icon: <ArrowLeft size={18} />,
+ path: "/dashboard/bookmarks",
+ },
+ {
+ name: t("admin.server_stats.server_stats"),
+ icon: <Activity size={18} />,
+ path: "/admin/overview",
+ },
+ {
+ name: t("admin.users_list.users_list"),
+ icon: <Users size={18} />,
+ path: "/admin/users",
+ },
+ {
+ name: t("common.actions"),
+ icon: <Settings size={18} />,
+ path: "/admin/actions",
+ },
+];
diff --git a/apps/web/components/dashboard/header/ProfileOptions.tsx b/apps/web/components/dashboard/header/ProfileOptions.tsx
index fc18e9d2..3d125606 100644
--- a/apps/web/components/dashboard/header/ProfileOptions.tsx
+++ b/apps/web/components/dashboard/header/ProfileOptions.tsx
@@ -16,7 +16,7 @@ import { LogOut, Moon, Paintbrush, Settings, Shield, Sun } from "lucide-react";
import { signOut, useSession } from "next-auth/react";
import { useTheme } from "next-themes";
-import { AdminNoticeBadge } from "../admin/AdminNotices";
+import { AdminNoticeBadge } from "../../admin/AdminNotices";
function DarkModeToggle() {
const { t } = useTranslation();
@@ -74,7 +74,7 @@ export default function SidebarProfileOptions() {
</DropdownMenuItem>
{session.user.role == "admin" && (
<DropdownMenuItem asChild>
- <Link href="/dashboard/admin" className="flex justify-between">
+ <Link href="/admin" className="flex justify-between">
<div className="items-cente flex gap-2">
<Shield className="size-4" />
{t("admin.admin_settings")}