From 7643c9b90da8c14420fe7ea7ab7b9c03e5cdf5f0 Mon Sep 17 00:00:00 2001 From: Trezy Date: Sat, 14 Feb 2026 11:01:24 -0600 Subject: [PATCH] feat: add dashboard navigation with sidebar layout --- web/src/app/(dashboard)/layout.tsx | 39 ++++++++++++ web/src/app/(dashboard)/page.tsx | 86 +++++++++++++++++++++++++++ web/src/app/page.tsx | 7 --- web/src/components/app-sidebar.tsx | 95 ++++++++++++++++++++++++++++++ web/src/components/site-header.tsx | 19 ++++++ 5 files changed, 239 insertions(+), 7 deletions(-) create mode 100644 web/src/app/(dashboard)/layout.tsx create mode 100644 web/src/app/(dashboard)/page.tsx delete mode 100644 web/src/app/page.tsx create mode 100644 web/src/components/app-sidebar.tsx create mode 100644 web/src/components/site-header.tsx diff --git a/web/src/app/(dashboard)/layout.tsx b/web/src/app/(dashboard)/layout.tsx new file mode 100644 index 0000000..da3ae01 --- /dev/null +++ b/web/src/app/(dashboard)/layout.tsx @@ -0,0 +1,39 @@ +"use client" + +import { useEffect } from "react" +import { useRouter } from "next/navigation" + +import { useAuth } from "@/lib/auth-context" +import { AppSidebar } from "@/components/app-sidebar" +import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar" + +export default function DashboardLayout({ + children, +}: { + children: React.ReactNode +}) { + const { token } = useAuth() + const router = useRouter() + + useEffect(() => { + if (!token) { + router.replace("/login") + } + }, [token, router]) + + if (!token) return null + + return ( + + + {children} + + ) +} diff --git a/web/src/app/(dashboard)/page.tsx b/web/src/app/(dashboard)/page.tsx new file mode 100644 index 0000000..4d0b030 --- /dev/null +++ b/web/src/app/(dashboard)/page.tsx @@ -0,0 +1,86 @@ +"use client" + +import { useEffect, useState } from "react" + +import { useAuth } from "@/lib/auth-context" +import { getStats, type StatsResponse } from "@/lib/api" +import { SiteHeader } from "@/components/site-header" +import { + Card, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card" +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table" + +export default function DashboardPage() { + const { token } = useAuth() + const [stats, setStats] = useState(null) + const [error, setError] = useState(null) + + useEffect(() => { + if (!token) return + getStats(token).then(setStats).catch((e) => setError(e.message)) + }, [token]) + + return ( + <> + +
+ {error && ( +

{error}

+ )} +
+ + + Total Records + + {stats ? stats.total_records.toLocaleString() : "--"} + + + + + + Collections + + {stats ? stats.collections.length : "--"} + + + +
+ + {stats && stats.collections.length > 0 && ( +
+ + + + Collection + Records + + + + {stats.collections.map((col) => ( + + + {col.collection} + + + {col.count.toLocaleString()} + + + ))} + +
+
+ )} +
+ + ) +} diff --git a/web/src/app/page.tsx b/web/src/app/page.tsx deleted file mode 100644 index 5fca611..0000000 --- a/web/src/app/page.tsx +++ /dev/null @@ -1,7 +0,0 @@ -export default function Home() { - return ( -
-

HappyView Admin

-
- ) -} diff --git a/web/src/components/app-sidebar.tsx b/web/src/components/app-sidebar.tsx new file mode 100644 index 0000000..3bb4c57 --- /dev/null +++ b/web/src/components/app-sidebar.tsx @@ -0,0 +1,95 @@ +"use client" + +import { + IconDashboard, + IconFileDescription, + IconWorld, + IconDatabase, + IconUsers, + IconLogout, +} from "@tabler/icons-react" +import Link from "next/link" +import { usePathname } from "next/navigation" + +import { useAuth } from "@/lib/auth-context" +import { + Sidebar, + SidebarContent, + SidebarFooter, + SidebarGroup, + SidebarGroupContent, + SidebarHeader, + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, +} from "@/components/ui/sidebar" + +const navItems = [ + { title: "Dashboard", url: "/", icon: IconDashboard }, + { title: "Lexicons", url: "/lexicons", icon: IconFileDescription }, + { title: "Network Lexicons", url: "/network-lexicons", icon: IconWorld }, + { title: "Backfill", url: "/backfill", icon: IconDatabase }, + { title: "Admins", url: "/admins", icon: IconUsers }, +] + +export function AppSidebar({ + ...props +}: React.ComponentProps) { + const pathname = usePathname() + const { logout } = useAuth() + + return ( + + + + + + + HappyView + + + + + + + + + + {navItems.map((item) => ( + + + + + {item.title} + + + + ))} + + + + + + + + + + Log out + + + + + + ) +} diff --git a/web/src/components/site-header.tsx b/web/src/components/site-header.tsx new file mode 100644 index 0000000..46a63a8 --- /dev/null +++ b/web/src/components/site-header.tsx @@ -0,0 +1,19 @@ +"use client" + +import { Separator } from "@/components/ui/separator" +import { SidebarTrigger } from "@/components/ui/sidebar" + +export function SiteHeader({ title }: { title: string }) { + return ( +
+
+ + +

{title}

+
+
+ ) +} -- 2.54.0