188 lines
7.2 KiB
TypeScript
188 lines
7.2 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import Link from "next/link";
|
|
import { usePathname } from "next/navigation";
|
|
import { useSession, signOut } from "next-auth/react";
|
|
import { NotificationBell } from "./NotificationBell";
|
|
|
|
export function Navbar() {
|
|
const pathname = usePathname();
|
|
const { data: session, status } = useSession();
|
|
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
|
|
|
const role = (session?.user as any)?.role || "GUEST";
|
|
const isEmployer = role === "EMPLOYER";
|
|
const isAdmin = role === "ADMIN";
|
|
|
|
// Build role-tailored navigation items
|
|
const navLinks: Array<{ href: string; label: string; badge?: string }> = [
|
|
{ href: "/jobs", label: "Search Directory" },
|
|
{ href: "/companies", label: "Companies" },
|
|
{ href: "/salary-insights", label: "Salaries" },
|
|
];
|
|
|
|
if (status === "authenticated") {
|
|
if (isEmployer) {
|
|
navLinks.push(
|
|
{ href: "/employer/jobs", label: "Listings" },
|
|
{ href: "/employer/jobs/new", label: "Post a Job", badge: "New" },
|
|
{ href: "/employer/ats", label: "Pipeline" },
|
|
{ href: "/employer/team", label: "Team" },
|
|
{ href: "/employer/candidates", label: "Talent" }
|
|
);
|
|
} else if (isAdmin) {
|
|
navLinks.push(
|
|
{ href: "/employer/jobs", label: "Jobs" },
|
|
{ href: "/employer/jobs/new", label: "Post Job" },
|
|
{ href: "/employer/ats", label: "ATS" },
|
|
{ href: "/admin", label: "Admin Console", badge: "Admin" }
|
|
);
|
|
} else {
|
|
// Job Seeker
|
|
navLinks.push(
|
|
{ href: "/saved-jobs", label: "Saved" },
|
|
{ href: "/applications", label: "Applications" },
|
|
{ href: "/resume", label: "Resume" },
|
|
{ href: "/alerts", label: "Alerts" },
|
|
{ href: "/profile", label: "Profile" }
|
|
);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<header className="bg-[#fbfbf9] border-b border-stone-200 sticky top-0 z-40">
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6">
|
|
<div className="flex justify-between h-13 items-center">
|
|
{/* Logo & Desktop Nav */}
|
|
<div className="flex items-center space-x-8">
|
|
<Link
|
|
href="/"
|
|
className="flex items-baseline space-x-2 text-stone-900 group"
|
|
aria-label="DirectWire Home"
|
|
>
|
|
<span className="font-serif-editorial text-2xl font-bold tracking-tight text-stone-900">
|
|
DirectWire
|
|
</span>
|
|
<span className="text-[10px] font-mono tracking-widest text-stone-400 uppercase">
|
|
/ beta
|
|
</span>
|
|
</Link>
|
|
|
|
<nav className="hidden md:flex items-center space-x-1 border-l border-stone-200 pl-6 h-6">
|
|
{navLinks.map((link) => {
|
|
const isActive =
|
|
link.href === "/"
|
|
? pathname === "/"
|
|
: pathname.startsWith(link.href);
|
|
return (
|
|
<Link
|
|
key={link.href}
|
|
href={link.href}
|
|
className={`px-2.5 py-1 text-xs transition-colors flex items-center space-x-1.5 ${
|
|
isActive
|
|
? "text-stone-950 font-semibold border-b-2 border-stone-900 -mb-[1px]"
|
|
: "text-stone-600 hover:text-stone-900"
|
|
}`}
|
|
>
|
|
<span>{link.label}</span>
|
|
{link.badge && (
|
|
<span className="text-[9px] px-1 py-0.2 bg-stone-100 text-stone-700 border border-stone-300 rounded font-mono">
|
|
{link.badge}
|
|
</span>
|
|
)}
|
|
</Link>
|
|
);
|
|
})}
|
|
</nav>
|
|
</div>
|
|
|
|
{/* User Session & Actions */}
|
|
<div className="flex items-center space-x-4 text-xs">
|
|
{status === "authenticated" && session?.user ? (
|
|
<div className="flex items-center space-x-3">
|
|
<NotificationBell />
|
|
<div className="hidden sm:flex items-center space-x-1.5 text-stone-700">
|
|
<span className="w-1.5 h-1.5 rounded-full bg-amber-600"></span>
|
|
<span className="font-medium">
|
|
{session.user.name || session.user.email}
|
|
</span>
|
|
<span className="text-[10px] text-stone-400 font-mono">
|
|
[{role}]
|
|
</span>
|
|
</div>
|
|
<button
|
|
onClick={() => signOut({ callbackUrl: "/login" })}
|
|
className="text-stone-500 hover:text-stone-900 transition-colors px-1 py-1 font-medium underline underline-offset-4"
|
|
>
|
|
Sign Out
|
|
</button>
|
|
</div>
|
|
) : (
|
|
<div className="flex items-center space-x-4">
|
|
<Link
|
|
href="/login"
|
|
className="text-stone-700 hover:text-stone-950 font-medium transition-colors"
|
|
>
|
|
Log In
|
|
</Link>
|
|
<Link
|
|
href="/register"
|
|
className="bg-stone-900 hover:bg-stone-800 text-stone-50 font-medium px-3.5 py-1.5 text-xs transition-colors border border-stone-900"
|
|
>
|
|
Get Started →
|
|
</Link>
|
|
</div>
|
|
)}
|
|
|
|
{/* Mobile Menu Toggle */}
|
|
<button
|
|
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
|
className="md:hidden p-1.5 text-stone-700 hover:text-stone-900 border border-stone-200"
|
|
aria-label={mobileMenuOpen ? "Close menu" : "Open menu"}
|
|
>
|
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
{mobileMenuOpen ? (
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M6 18L18 6M6 6l12 12" />
|
|
) : (
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M4 6h16M4 12h16M4 18h16" />
|
|
)}
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Mobile Dropdown */}
|
|
{mobileMenuOpen && (
|
|
<div className="md:hidden bg-[#fbfbf9] border-t border-b border-stone-200 px-4 py-3 space-y-1">
|
|
{navLinks.map((link) => {
|
|
const isActive =
|
|
link.href === "/"
|
|
? pathname === "/"
|
|
: pathname.startsWith(link.href);
|
|
return (
|
|
<Link
|
|
key={link.href}
|
|
href={link.href}
|
|
onClick={() => setMobileMenuOpen(false)}
|
|
className={`flex items-center justify-between px-3 py-2 text-xs transition-colors ${
|
|
isActive
|
|
? "bg-stone-200/70 text-stone-950 font-bold"
|
|
: "text-stone-700 hover:bg-stone-100"
|
|
}`}
|
|
>
|
|
<span>{link.label}</span>
|
|
{link.badge && (
|
|
<span className="text-[10px] px-1.5 py-0.5 border border-stone-300 font-mono">
|
|
{link.badge}
|
|
</span>
|
|
)}
|
|
</Link>
|
|
);
|
|
})}
|
|
</div>
|
|
)}
|
|
</header>
|
|
);
|
|
}
|