diff options
| author | Mohamed Bassem <me@mbassem.com> | 2024-12-30 11:27:32 +0000 |
|---|---|---|
| committer | Mohamed Bassem <me@mbassem.com> | 2024-12-30 11:31:35 +0000 |
| commit | 179f00b15525b024b6823088ef8fb94b7106b4f0 (patch) | |
| tree | d64257778930965ed076ff9a081411470343fb3c /apps | |
| parent | aff4e60952321d06dc4cf517ff3b15206aaaebba (diff) | |
| download | karakeep-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.tsx | 5 | ||||
| -rw-r--r-- | apps/web/app/admin/layout.tsx | 40 | ||||
| -rw-r--r-- | apps/web/app/admin/overview/page.tsx | 5 | ||||
| -rw-r--r-- | apps/web/app/admin/page.tsx | 6 | ||||
| -rw-r--r-- | apps/web/app/admin/users/page.tsx | 5 | ||||
| -rw-r--r-- | apps/web/app/dashboard/admin/page.tsx | 26 | ||||
| -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.tsx | 21 | ||||
| -rw-r--r-- | apps/web/components/admin/sidebar/Sidebar.tsx | 36 | ||||
| -rw-r--r-- | apps/web/components/admin/sidebar/items.tsx | 31 | ||||
| -rw-r--r-- | apps/web/components/dashboard/header/ProfileOptions.tsx | 4 |
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")} |
