Spaces:
Sleeping
Sleeping
fix: Header nav - Settings, Admin, Login/Signup visibility with proper auth guards
Browse files- web/components/nav.tsx +17 -17
web/components/nav.tsx
CHANGED
|
@@ -55,7 +55,7 @@ export function Nav() {
|
|
| 55 |
window.location.href = "/";
|
| 56 |
}
|
| 57 |
|
| 58 |
-
// Public links
|
| 59 |
const mainLinks: NavLink[] = [
|
| 60 |
{ href: "/#features", label: "Features", icon: Sparkles },
|
| 61 |
{ href: "/#pricing", label: "Pricing", icon: CreditCard },
|
|
@@ -73,9 +73,9 @@ export function Nav() {
|
|
| 73 |
<span className="hidden sm:inline text-[10px] font-medium text-zinc-400 ml-1 border border-zinc-200 px-1.5 py-0.5 rounded">v4.0</span>
|
| 74 |
</Link>
|
| 75 |
|
| 76 |
-
{/*
|
| 77 |
<div className="hidden md:flex items-center gap-0.5">
|
| 78 |
-
{/* Public links
|
| 79 |
{mainLinks.map((l) => {
|
| 80 |
const isActive = pathname === l.href;
|
| 81 |
return (
|
|
@@ -88,7 +88,7 @@ export function Nav() {
|
|
| 88 |
);
|
| 89 |
})}
|
| 90 |
|
| 91 |
-
{/*
|
| 92 |
{!loaded && (
|
| 93 |
<>
|
| 94 |
<div className="w-px h-4 bg-zinc-200 mx-1.5" />
|
|
@@ -99,7 +99,7 @@ export function Nav() {
|
|
| 99 |
</>
|
| 100 |
)}
|
| 101 |
|
| 102 |
-
{/*
|
| 103 |
{loaded && isLoggedIn && (
|
| 104 |
<>
|
| 105 |
{/* Dashboard */}
|
|
@@ -113,7 +113,7 @@ export function Nav() {
|
|
| 113 |
Dashboard
|
| 114 |
</Link>
|
| 115 |
|
| 116 |
-
{/* Team
|
| 117 |
{hasTeam && (
|
| 118 |
<Link href="/dashboard-pages/team"
|
| 119 |
className={`flex items-center gap-1.5 px-2.5 py-1.5 text-[13px] rounded-md transition-colors ${
|
|
@@ -126,7 +126,7 @@ export function Nav() {
|
|
| 126 |
</Link>
|
| 127 |
)}
|
| 128 |
|
| 129 |
-
{/* Admin
|
| 130 |
{isAdmin && (
|
| 131 |
<Link href="/admin"
|
| 132 |
className={`flex items-center gap-1.5 px-2.5 py-1.5 text-[13px] rounded-md transition-colors ${
|
|
@@ -152,13 +152,13 @@ export function Nav() {
|
|
| 152 |
Settings
|
| 153 |
</Link>
|
| 154 |
|
| 155 |
-
{/* User indicator
|
| 156 |
<div className="relative group ml-1">
|
| 157 |
<button className="flex items-center gap-1.5 px-2.5 py-1.5 text-[13px] text-zinc-500 hover:text-zinc-900 rounded-md hover:bg-zinc-50 transition-colors">
|
| 158 |
<UserCircle className="w-3.5 h-3.5" />
|
| 159 |
<span className="max-w-[100px] truncate">{userEmail?.split("@")[0]}</span>
|
| 160 |
</button>
|
| 161 |
-
{/* Dropdown */}
|
| 162 |
<div className="absolute right-0 top-full mt-1 w-52 bg-white border border-zinc-200 rounded-xl shadow-lg opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-150 z-50">
|
| 163 |
<div className="px-3 py-2.5 border-b border-zinc-100">
|
| 164 |
<p className="text-xs text-zinc-400">Signed in as</p>
|
|
@@ -198,7 +198,7 @@ export function Nav() {
|
|
| 198 |
</>
|
| 199 |
)}
|
| 200 |
|
| 201 |
-
{/*
|
| 202 |
{loaded && !isLoggedIn && (
|
| 203 |
<>
|
| 204 |
<div className="w-px h-4 bg-zinc-200 mx-1.5" />
|
|
@@ -226,7 +226,7 @@ export function Nav() {
|
|
| 226 |
</button>
|
| 227 |
</div>
|
| 228 |
|
| 229 |
-
{/*
|
| 230 |
{open && (
|
| 231 |
<div className="md:hidden border-t border-zinc-100 bg-white px-5 py-3 space-y-0.5">
|
| 232 |
{/* Public links */}
|
|
@@ -244,7 +244,7 @@ export function Nav() {
|
|
| 244 |
);
|
| 245 |
})}
|
| 246 |
|
| 247 |
-
{/*
|
| 248 |
{!loaded && (
|
| 249 |
<>
|
| 250 |
<div className="h-px bg-zinc-100 my-1.5" />
|
|
@@ -255,12 +255,12 @@ export function Nav() {
|
|
| 255 |
</>
|
| 256 |
)}
|
| 257 |
|
| 258 |
-
{/*
|
| 259 |
{loaded && isLoggedIn && (
|
| 260 |
<>
|
| 261 |
<div className="h-px bg-zinc-100 my-1.5" />
|
| 262 |
|
| 263 |
-
{/* User info */}
|
| 264 |
<div className="px-3 py-2">
|
| 265 |
<p className="text-xs text-zinc-400">Signed in as</p>
|
| 266 |
<p className="text-sm text-zinc-700 font-medium truncate">{userEmail}</p>
|
|
@@ -284,7 +284,7 @@ export function Nav() {
|
|
| 284 |
<Settings className="w-4 h-4 text-zinc-400" /> Settings
|
| 285 |
</Link>
|
| 286 |
|
| 287 |
-
{/* Team */}
|
| 288 |
{hasTeam && (
|
| 289 |
<Link href="/dashboard-pages/team" onClick={() => setOpen(false)}
|
| 290 |
className={`flex items-center gap-2.5 px-3 py-2.5 text-sm rounded-md ${
|
|
@@ -296,7 +296,7 @@ export function Nav() {
|
|
| 296 |
</Link>
|
| 297 |
)}
|
| 298 |
|
| 299 |
-
{/* Admin */}
|
| 300 |
{isAdmin && (
|
| 301 |
<Link href="/admin" onClick={() => setOpen(false)}
|
| 302 |
className={`flex items-center gap-2.5 px-3 py-2.5 text-sm rounded-md ${
|
|
@@ -324,7 +324,7 @@ export function Nav() {
|
|
| 324 |
</>
|
| 325 |
)}
|
| 326 |
|
| 327 |
-
{/*
|
| 328 |
{loaded && !isLoggedIn && (
|
| 329 |
<>
|
| 330 |
<div className="h-px bg-zinc-100 my-1.5" />
|
|
|
|
| 55 |
window.location.href = "/";
|
| 56 |
}
|
| 57 |
|
| 58 |
+
// Public links - always visible
|
| 59 |
const mainLinks: NavLink[] = [
|
| 60 |
{ href: "/#features", label: "Features", icon: Sparkles },
|
| 61 |
{ href: "/#pricing", label: "Pricing", icon: CreditCard },
|
|
|
|
| 73 |
<span className="hidden sm:inline text-[10px] font-medium text-zinc-400 ml-1 border border-zinc-200 px-1.5 py-0.5 rounded">v4.0</span>
|
| 74 |
</Link>
|
| 75 |
|
| 76 |
+
{/* Desktop Nav */}
|
| 77 |
<div className="hidden md:flex items-center gap-0.5">
|
| 78 |
+
{/* Public links - always visible */}
|
| 79 |
{mainLinks.map((l) => {
|
| 80 |
const isActive = pathname === l.href;
|
| 81 |
return (
|
|
|
|
| 88 |
);
|
| 89 |
})}
|
| 90 |
|
| 91 |
+
{/* Loading skeleton while auth state resolves */}
|
| 92 |
{!loaded && (
|
| 93 |
<>
|
| 94 |
<div className="w-px h-4 bg-zinc-200 mx-1.5" />
|
|
|
|
| 99 |
</>
|
| 100 |
)}
|
| 101 |
|
| 102 |
+
{/* Logged-in links */}
|
| 103 |
{loaded && isLoggedIn && (
|
| 104 |
<>
|
| 105 |
{/* Dashboard */}
|
|
|
|
| 113 |
Dashboard
|
| 114 |
</Link>
|
| 115 |
|
| 116 |
+
{/* Team - only when user belongs to a team */}
|
| 117 |
{hasTeam && (
|
| 118 |
<Link href="/dashboard-pages/team"
|
| 119 |
className={`flex items-center gap-1.5 px-2.5 py-1.5 text-[13px] rounded-md transition-colors ${
|
|
|
|
| 126 |
</Link>
|
| 127 |
)}
|
| 128 |
|
| 129 |
+
{/* Admin - only for admin role */}
|
| 130 |
{isAdmin && (
|
| 131 |
<Link href="/admin"
|
| 132 |
className={`flex items-center gap-1.5 px-2.5 py-1.5 text-[13px] rounded-md transition-colors ${
|
|
|
|
| 152 |
Settings
|
| 153 |
</Link>
|
| 154 |
|
| 155 |
+
{/* User indicator with hover dropdown */}
|
| 156 |
<div className="relative group ml-1">
|
| 157 |
<button className="flex items-center gap-1.5 px-2.5 py-1.5 text-[13px] text-zinc-500 hover:text-zinc-900 rounded-md hover:bg-zinc-50 transition-colors">
|
| 158 |
<UserCircle className="w-3.5 h-3.5" />
|
| 159 |
<span className="max-w-[100px] truncate">{userEmail?.split("@")[0]}</span>
|
| 160 |
</button>
|
| 161 |
+
{/* Dropdown on hover */}
|
| 162 |
<div className="absolute right-0 top-full mt-1 w-52 bg-white border border-zinc-200 rounded-xl shadow-lg opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-150 z-50">
|
| 163 |
<div className="px-3 py-2.5 border-b border-zinc-100">
|
| 164 |
<p className="text-xs text-zinc-400">Signed in as</p>
|
|
|
|
| 198 |
</>
|
| 199 |
)}
|
| 200 |
|
| 201 |
+
{/* Logged-out links */}
|
| 202 |
{loaded && !isLoggedIn && (
|
| 203 |
<>
|
| 204 |
<div className="w-px h-4 bg-zinc-200 mx-1.5" />
|
|
|
|
| 226 |
</button>
|
| 227 |
</div>
|
| 228 |
|
| 229 |
+
{/* Mobile Menu */}
|
| 230 |
{open && (
|
| 231 |
<div className="md:hidden border-t border-zinc-100 bg-white px-5 py-3 space-y-0.5">
|
| 232 |
{/* Public links */}
|
|
|
|
| 244 |
);
|
| 245 |
})}
|
| 246 |
|
| 247 |
+
{/* Mobile loading skeleton */}
|
| 248 |
{!loaded && (
|
| 249 |
<>
|
| 250 |
<div className="h-px bg-zinc-100 my-1.5" />
|
|
|
|
| 255 |
</>
|
| 256 |
)}
|
| 257 |
|
| 258 |
+
{/* Mobile: Logged-in links */}
|
| 259 |
{loaded && isLoggedIn && (
|
| 260 |
<>
|
| 261 |
<div className="h-px bg-zinc-100 my-1.5" />
|
| 262 |
|
| 263 |
+
{/* User info banner */}
|
| 264 |
<div className="px-3 py-2">
|
| 265 |
<p className="text-xs text-zinc-400">Signed in as</p>
|
| 266 |
<p className="text-sm text-zinc-700 font-medium truncate">{userEmail}</p>
|
|
|
|
| 284 |
<Settings className="w-4 h-4 text-zinc-400" /> Settings
|
| 285 |
</Link>
|
| 286 |
|
| 287 |
+
{/* Team link */}
|
| 288 |
{hasTeam && (
|
| 289 |
<Link href="/dashboard-pages/team" onClick={() => setOpen(false)}
|
| 290 |
className={`flex items-center gap-2.5 px-3 py-2.5 text-sm rounded-md ${
|
|
|
|
| 296 |
</Link>
|
| 297 |
)}
|
| 298 |
|
| 299 |
+
{/* Admin link */}
|
| 300 |
{isAdmin && (
|
| 301 |
<Link href="/admin" onClick={() => setOpen(false)}
|
| 302 |
className={`flex items-center gap-2.5 px-3 py-2.5 text-sm rounded-md ${
|
|
|
|
| 324 |
</>
|
| 325 |
)}
|
| 326 |
|
| 327 |
+
{/* Mobile: Logged-out links */}
|
| 328 |
{loaded && !isLoggedIn && (
|
| 329 |
<>
|
| 330 |
<div className="h-px bg-zinc-100 my-1.5" />
|