fixed admin icon and added admin routing if logged in

This commit is contained in:
2025-06-30 20:32:40 -04:00
parent b478d9797d
commit b2ada8d81e
4 changed files with 103 additions and 13 deletions

View File

@@ -1,6 +1,7 @@
"use client"; "use client";
import { useState, ReactNode } from 'react'; import { useState, ReactNode } from 'react';
import { usePathname } from 'next/navigation'; import { usePathname } from 'next/navigation';
import { useSession } from 'next-auth/react';
import { import {
Dialog, Dialog,
DialogBackdrop, DialogBackdrop,
@@ -32,8 +33,8 @@ const navigation = [
// { name: 'Settings', href: '/admin/settings', icon: Cog6ToothIcon }, // optional/future // { name: 'Settings', href: '/admin/settings', icon: Cog6ToothIcon }, // optional/future
]; ];
const userNavigation = [ const userNavigation = [
{ name: 'Your profile', href: '#' }, { name: 'Your profile', href: '/account/profile' },
{ name: 'Sign out', href: '#' }, { name: 'Sign out', href: '/api/auth/signout' },
]; ];
function classNames(...classes: string[]) { function classNames(...classes: string[]) {
@@ -43,6 +44,40 @@ function classNames(...classes: string[]) {
export default function AdminNavbar({ children }: { children: ReactNode }) { export default function AdminNavbar({ children }: { children: ReactNode }) {
const [sidebarOpen, setSidebarOpen] = useState(false); const [sidebarOpen, setSidebarOpen] = useState(false);
const pathname = usePathname(); const pathname = usePathname();
const { data: session } = useSession();
// Get user display name
const getUserDisplayName = () => {
if (!session?.user) return 'Admin User';
const user = session.user as any;
if (user.first_name && user.last_name) {
return `${user.first_name} ${user.last_name}`;
}
if (user.name) {
return user.name;
}
if (user.email) {
return user.email.split('@')[0]; // Use email prefix as fallback
}
return 'Admin User';
};
const getUserInitials = () => {
if (!session?.user) return 'A';
const user = session.user as any;
if (user.first_name && user.last_name) {
return `${user.first_name[0]}${user.last_name[0]}`.toUpperCase();
}
if (user.name) {
return user.name.split(' ').map((n: string) => n[0]).join('').toUpperCase().slice(0, 2);
}
if (user.email) {
return user.email[0].toUpperCase();
}
return 'A';
};
return ( return (
<> <>
@@ -203,6 +238,15 @@ export default function AdminNavbar({ children }: { children: ReactNode }) {
className="pointer-events-none col-start-1 row-start-1 size-5 self-center text-gray-400" className="pointer-events-none col-start-1 row-start-1 size-5 self-center text-gray-400"
/> />
</form> </form>
{/* Back to Site Button */}
<a
href="/"
className="inline-flex items-center px-3 py-2 text-sm font-medium text-gray-700 bg-gray-100 rounded-md hover:bg-gray-200 transition-colors"
>
<HomeIcon className="w-4 h-4 mr-2" />
Back to Site
</a>
<div className="flex items-center gap-x-4 lg:gap-x-6"> <div className="flex items-center gap-x-4 lg:gap-x-6">
<button type="button" className="-m-2.5 p-2.5 text-gray-400 hover:text-gray-500"> <button type="button" className="-m-2.5 p-2.5 text-gray-400 hover:text-gray-500">
<span className="sr-only">View notifications</span> <span className="sr-only">View notifications</span>
@@ -217,27 +261,32 @@ export default function AdminNavbar({ children }: { children: ReactNode }) {
<MenuButton className="relative flex items-center"> <MenuButton className="relative flex items-center">
<span className="absolute -inset-1.5" /> <span className="absolute -inset-1.5" />
<span className="sr-only">Open user menu</span> <span className="sr-only">Open user menu</span>
<img <div className="size-8 rounded-full bg-indigo-600 flex items-center justify-center">
alt="" <span className="text-sm font-medium text-white">
src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" {getUserInitials()}
className="size-8 rounded-full bg-gray-50" </span>
/> </div>
<span className="hidden lg:flex lg:items-center"> <span className="hidden lg:flex lg:items-center">
<span aria-hidden="true" className="ml-4 text-sm/6 font-semibold text-gray-900"> <span aria-hidden="true" className="ml-4 text-sm/6 font-semibold text-gray-900">
Tom Cook {getUserDisplayName()}
</span> </span>
<ChevronDownIcon aria-hidden="true" className="ml-2 size-5 text-gray-400" /> <ChevronDownIcon aria-hidden="true" className="ml-2 size-5 text-gray-400" />
</span> </span>
</MenuButton> </MenuButton>
<MenuItems <MenuItems
transition transition
className="absolute right-0 z-10 mt-2.5 w-32 origin-top-right rounded-md bg-white py-2 shadow-lg ring-1 ring-gray-900/5 transition focus:outline-none data-[closed]:scale-95 data-[closed]:transform data-[closed]:opacity-0 data-[enter]:duration-100 data-[leave]:duration-75 data-[enter]:ease-out data-[leave]:ease-in" className="absolute right-0 z-10 mt-2.5 w-48 origin-top-right rounded-md bg-white py-2 shadow-lg ring-1 ring-gray-900/5 transition focus:outline-none data-[closed]:scale-95 data-[closed]:transform data-[closed]:opacity-0 data-[enter]:duration-100 data-[leave]:duration-75 data-[enter]:ease-out data-[leave]:ease-in"
> >
{session?.user && (
<div className="px-3 py-2 text-xs text-gray-500 border-b border-gray-100">
{session.user.email}
</div>
)}
{userNavigation.map((item) => ( {userNavigation.map((item) => (
<MenuItem key={item.name}> <MenuItem key={item.name}>
<a <a
href={item.href} href={item.href}
className="block px-3 py-1 text-sm/6 text-gray-900 data-[focus]:bg-gray-50 data-[focus]:outline-none" className="block px-3 py-2 text-sm text-gray-900 data-[focus]:bg-gray-50 data-[focus]:outline-none hover:bg-gray-50"
> >
{item.name} {item.name}
</a> </a>

View File

@@ -0,0 +1,11 @@
'use client';
import { SessionProvider } from 'next-auth/react';
export default function AdminProviders({ children }: { children: React.ReactNode }) {
return (
<SessionProvider>
{children}
</SessionProvider>
);
}

View File

@@ -1,9 +1,12 @@
import AdminNavbar from './AdminNavbar'; import AdminNavbar from './AdminNavbar';
import AdminProviders from './AdminProviders';
export default async function AdminLayout({ children }: { children: React.ReactNode }) { export default async function AdminLayout({ children }: { children: React.ReactNode }) {
return ( return (
<AdminProviders>
<AdminNavbar> <AdminNavbar>
{children} {children}
</AdminNavbar> </AdminNavbar>
</AdminProviders>
); );
} }

View File

@@ -6,6 +6,7 @@ import ThemeSwitcher from './ThemeSwitcher';
import { MagnifyingGlassIcon } from '@heroicons/react/24/outline'; import { MagnifyingGlassIcon } from '@heroicons/react/24/outline';
import { useSession, signIn, signOut } from 'next-auth/react'; import { useSession, signIn, signOut } from 'next-auth/react';
import { useState, ReactNode } from 'react'; import { useState, ReactNode } from 'react';
import { ShieldCheckIcon } from '@heroicons/react/24/outline';
interface MenuItem { interface MenuItem {
label: string; label: string;
@@ -37,6 +38,14 @@ export default function Navbar() {
onClick: () => setMenuOpen(false), onClick: () => setMenuOpen(false),
} }
: undefined, : undefined,
// Admin link for admin users
session?.user && (session.user as any)?.isAdmin
? {
label: 'Admin Dashboard',
href: '/admin',
onClick: () => setMenuOpen(false),
}
: undefined,
session?.user session?.user
? { ? {
label: 'Sign Out', label: 'Sign Out',
@@ -64,6 +73,24 @@ export default function Navbar() {
return ( return (
<> <>
{/* Admin Banner - Moved to top */}
{session?.user && (session.user as any)?.isAdmin && (
<div className="w-full bg-gradient-to-r from-purple-600 to-indigo-600 text-white py-2 px-4 sm:px-8 relative z-30">
<div className="max-w-7xl mx-auto flex items-center justify-between">
<div className="flex items-center space-x-2">
<ShieldCheckIcon className="h-4 w-4" />
<span className="text-sm font-medium">Admin Panel</span>
</div>
<Link
href="/admin"
className="text-sm hover:text-purple-200 transition-colors underline underline-offset-2"
>
Go to Admin Dashboard
</Link>
</div>
</div>
)}
{/* Top Bar */} {/* Top Bar */}
<div className="w-full bg-[#4B6516] text-white h-10 flex items-center justify-between px-4 sm:px-8 relative z-20"> <div className="w-full bg-[#4B6516] text-white h-10 flex items-center justify-between px-4 sm:px-8 relative z-20">
<Link href="/" className="font-bold text-lg tracking-tight hover:underline focus:underline">Pew Builder</Link> <Link href="/" className="font-bold text-lg tracking-tight hover:underline focus:underline">Pew Builder</Link>