Files
Michilis 76210db03d first commit
Made-with: Cursor
2026-04-01 02:46:53 +00:00

122 lines
4.2 KiB
TypeScript

"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useAuth } from "@/hooks/useAuth";
import { cn } from "@/lib/utils";
import {
LayoutDashboard,
Calendar,
FileText,
Shield,
Tag,
Users,
Radio,
Settings,
Wrench,
LogOut,
ArrowLeft,
Inbox,
ImageIcon,
HelpCircle,
} from "lucide-react";
const navItems = [
{ href: "/admin/overview", label: "Overview", icon: LayoutDashboard, adminOnly: false },
{ href: "/admin/events", label: "Events", icon: Calendar, adminOnly: false },
{ href: "/admin/gallery", label: "Gallery", icon: ImageIcon, adminOnly: false },
{ href: "/admin/blog", label: "Blog", icon: FileText, adminOnly: false },
{ href: "/admin/faq", label: "FAQ", icon: HelpCircle, adminOnly: false },
{ href: "/admin/submissions", label: "Submissions", icon: Inbox, adminOnly: false },
{ href: "/admin/moderation", label: "Moderation", icon: Shield, adminOnly: false },
{ href: "/admin/categories", label: "Categories", icon: Tag, adminOnly: false },
{ href: "/admin/users", label: "Users", icon: Users, adminOnly: true },
{ href: "/admin/relays", label: "Relays", icon: Radio, adminOnly: true },
{ href: "/admin/settings", label: "Settings", icon: Settings, adminOnly: true },
{ href: "/admin/nostr", label: "Nostr Tools", icon: Wrench, adminOnly: true },
];
export function AdminSidebar() {
const pathname = usePathname();
const { user, logout, isAdmin } = useAuth();
const shortPubkey = user?.pubkey
? `${user.pubkey.slice(0, 8)}...${user.pubkey.slice(-8)}`
: "";
return (
<aside className="w-64 bg-surface-container-lowest min-h-screen p-6 flex flex-col shrink-0">
<div className="mb-8">
<Link href="/" className="text-primary-container font-bold text-xl">
BBE Admin
</Link>
</div>
{!user ? (
<div className="flex-1 flex items-center justify-center">
<p className="text-on-surface/40 text-sm text-center">
Please log in to access the dashboard.
</p>
</div>
) : (
<>
<div className="mb-6">
<p className="text-on-surface/70 text-sm font-mono truncate">{shortPubkey}</p>
<span
className={cn(
"inline-block mt-1 rounded-full px-3 py-1 text-xs font-bold",
user.role === "ADMIN"
? "bg-primary-container/20 text-primary"
: "bg-secondary-container text-on-secondary-container"
)}
>
{user.role}
</span>
</div>
<nav className="flex-1 space-y-1">
{navItems
.filter((item) => !item.adminOnly || isAdmin)
.map((item) => {
const Icon = item.icon;
const active = pathname === item.href;
return (
<Link
key={item.href}
href={item.href}
className={cn(
"flex items-center gap-3 px-4 py-3 rounded-lg transition-colors",
active
? "bg-surface-container-high text-primary"
: "text-on-surface/70 hover:text-on-surface hover:bg-surface-container"
)}
>
<Icon size={20} />
<span>{item.label}</span>
</Link>
);
})}
</nav>
<div className="mt-auto space-y-2 pt-6">
<button
onClick={logout}
className="flex items-center gap-3 px-4 py-3 rounded-lg transition-colors text-on-surface/70 hover:text-on-surface hover:bg-surface-container w-full"
>
<LogOut size={20} />
<span>Logout</span>
</button>
<Link
href="/"
className="flex items-center gap-3 px-4 py-3 rounded-lg transition-colors text-on-surface/70 hover:text-on-surface hover:bg-surface-container"
>
<ArrowLeft size={20} />
<span>Back to site</span>
</Link>
</div>
</>
)}
</aside>
);
}