refactor: Dashboard & Navigation overhaul
Some checks failed
CI / Frontend Lint & Type Check (push) Has been cancelled
CI / Frontend Build (push) Has been cancelled
CI / Backend Lint (push) Has been cancelled
CI / Backend Tests (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
Deploy / Build & Push Images (push) Has been cancelled
Deploy / Deploy to Server (push) Has been cancelled
Deploy / Notify (push) Has been cancelled

DASHBOARD CHANGES:
- Stats cards now all neutral (no colored backgrounds)
- Added limit warning with upgrade CTA when domain limit reached
- Removed TLD Price Intelligence section
- Portfolio now uses table layout like Watchlist
- Consistent styling across both tabs

NAVIGATION OVERHAUL:
- New notification center with dropdown
  - Shows available domains with pulsing indicator
  - Empty state when no notifications
  - Link to manage notifications
- New user dropdown menu
  - Shows user info and plan tier
  - Domain usage (X/Y domains)
  - Quick links to Dashboard, TLD Pricing, Settings
  - Clean logout option
- Dashboard button more prominent
- Plans link hidden when logged in
- Click-outside closes dropdowns

MOBILE:
- User info shown at top of mobile menu
- Plan tier and domain usage visible
- All navigation items accessible
This commit is contained in:
yves.gugger
2025-12-09 09:36:25 +01:00
parent 674a0f0219
commit 56d5a3f194
2 changed files with 311 additions and 126 deletions

View File

@ -13,29 +13,22 @@ import {
Loader2,
Clock,
AlertCircle,
Search,
Calendar,
History,
ChevronRight,
Bell,
BellOff,
Check,
X,
Zap,
Crown,
TrendingUp,
Briefcase,
Eye,
DollarSign,
Tag,
Edit2,
ExternalLink,
Sparkles,
BarChart3,
CreditCard,
Globe,
ArrowUpRight,
ArrowDownRight,
} from 'lucide-react'
import clsx from 'clsx'
import Link from 'next/link'
@ -465,25 +458,37 @@ export default function DashboardPage() {
<p className="text-ui-xs text-foreground-muted uppercase tracking-wider mb-2">Tracked</p>
<p className="text-3xl font-display text-foreground">{domains.length}</p>
</div>
<div className="p-5 bg-accent/5 border border-accent/20 rounded-2xl hover:border-accent/40 transition-colors">
<p className="text-ui-xs text-accent/80 uppercase tracking-wider mb-2">Available</p>
<p className="text-3xl font-display text-accent">{availableCount}</p>
<div className="p-5 bg-background-secondary border border-border rounded-2xl hover:border-foreground/20 transition-colors">
<p className="text-ui-xs text-foreground-muted uppercase tracking-wider mb-2">Available</p>
<p className="text-3xl font-display text-foreground">{availableCount}</p>
</div>
<div className="p-5 bg-accent/5 border border-accent/20 rounded-2xl hover:border-accent/40 transition-colors">
<p className="text-ui-xs text-accent/80 uppercase tracking-wider mb-2">Monitoring</p>
<p className="text-3xl font-display text-accent">{domains.filter(d => d.notify_on_available).length}</p>
<div className="p-5 bg-background-secondary border border-border rounded-2xl hover:border-foreground/20 transition-colors">
<p className="text-ui-xs text-foreground-muted uppercase tracking-wider mb-2">Monitoring</p>
<p className="text-3xl font-display text-foreground">{domains.filter(d => d.notify_on_available).length}</p>
</div>
<div className={clsx(
"p-5 border rounded-2xl transition-colors",
expiringCount > 0
? "bg-warning/5 border-warning/20 hover:border-warning/40"
: "bg-background-secondary border-border hover:border-foreground/20"
)}>
<p className={clsx("text-ui-xs uppercase tracking-wider mb-2", expiringCount > 0 ? "text-warning/80" : "text-foreground-muted")}>Expiring</p>
<p className={clsx("text-3xl font-display", expiringCount > 0 ? "text-warning" : "text-foreground")}>{expiringCount}</p>
<div className="p-5 bg-background-secondary border border-border rounded-2xl hover:border-foreground/20 transition-colors">
<p className="text-ui-xs text-foreground-muted uppercase tracking-wider mb-2">Expiring</p>
<p className="text-3xl font-display text-foreground">{expiringCount}</p>
</div>
</div>
{/* Limit Warning */}
{!canAddMore && (
<div className="p-4 bg-warning/5 border border-warning/20 rounded-xl flex flex-col sm:flex-row sm:items-center justify-between gap-3">
<div className="flex items-center gap-3">
<AlertCircle className="w-5 h-5 text-warning shrink-0" />
<div>
<p className="text-body-sm font-medium text-foreground">You've reached your domain limit</p>
<p className="text-body-xs text-foreground-muted">Upgrade to track more domains and unlock premium features</p>
</div>
</div>
<Link href="/pricing" className="flex items-center justify-center gap-2 px-4 py-2 bg-accent text-background text-ui-sm font-medium rounded-lg hover:bg-accent-hover transition-all whitespace-nowrap">
<Zap className="w-4 h-4" />
Upgrade Now
</Link>
</div>
)}
{/* Add Domain */}
<form onSubmit={handleAddDomain} className="flex gap-3">
<div className="flex-1 relative">
@ -626,25 +631,14 @@ export default function DashboardPage() {
<p className="text-ui-xs text-foreground-muted uppercase tracking-wider mb-2">Invested</p>
<p className="text-2xl sm:text-3xl font-display text-foreground">{formatCurrency(portfolioSummary.total_invested)}</p>
</div>
<div className={clsx(
"p-5 border rounded-2xl transition-colors",
portfolioSummary.unrealized_profit >= 0
? "bg-accent/5 border-accent/20 hover:border-accent/40"
: "bg-danger/5 border-danger/20 hover:border-danger/40"
)}>
<p className={clsx("text-ui-xs uppercase tracking-wider mb-2", portfolioSummary.unrealized_profit >= 0 ? "text-accent/80" : "text-danger/80")}>P/L</p>
<div className="p-5 bg-background-secondary border border-border rounded-2xl hover:border-foreground/20 transition-colors">
<p className="text-ui-xs text-foreground-muted uppercase tracking-wider mb-2">P/L</p>
<p className={clsx("text-2xl sm:text-3xl font-display flex items-center gap-1", portfolioSummary.unrealized_profit >= 0 ? "text-accent" : "text-danger")}>
{portfolioSummary.unrealized_profit >= 0 ? <ArrowUpRight className="w-5 h-5" /> : <ArrowDownRight className="w-5 h-5" />}
{formatCurrency(Math.abs(portfolioSummary.unrealized_profit))}
{portfolioSummary.unrealized_profit >= 0 ? '+' : ''}{formatCurrency(portfolioSummary.unrealized_profit)}
</p>
</div>
<div className={clsx(
"p-5 border rounded-2xl transition-colors",
portfolioSummary.overall_roi >= 0
? "bg-accent/5 border-accent/20 hover:border-accent/40"
: "bg-danger/5 border-danger/20 hover:border-danger/40"
)}>
<p className={clsx("text-ui-xs uppercase tracking-wider mb-2", portfolioSummary.overall_roi >= 0 ? "text-accent/80" : "text-danger/80")}>ROI</p>
<div className="p-5 bg-background-secondary border border-border rounded-2xl hover:border-foreground/20 transition-colors">
<p className="text-ui-xs text-foreground-muted uppercase tracking-wider mb-2">ROI</p>
<p className={clsx("text-2xl sm:text-3xl font-display", portfolioSummary.overall_roi >= 0 ? "text-accent" : "text-danger")}>
{portfolioSummary.overall_roi >= 0 ? '+' : ''}{portfolioSummary.overall_roi.toFixed(1)}%
</p>
@ -652,9 +646,10 @@ export default function DashboardPage() {
</div>
)}
<button onClick={() => setShowAddPortfolioModal(true)} className="flex items-center gap-2.5 px-6 py-3.5 bg-foreground text-background text-ui font-medium rounded-xl hover:bg-foreground/90 transition-all shadow-lg shadow-foreground/10">
{/* Add Domain */}
<button onClick={() => setShowAddPortfolioModal(true)} className="flex items-center gap-2 px-5 py-3 bg-foreground text-background text-ui-sm font-medium rounded-xl hover:bg-foreground/90 transition-all">
<Plus className="w-4 h-4" />
Add Domain to Portfolio
Add Domain
</button>
{loadingPortfolio ? (
@ -668,65 +663,87 @@ export default function DashboardPage() {
<p className="text-body-sm text-foreground-subtle">Add domains you own to track their value and ROI</p>
</div>
) : (
<div className="space-y-3">
{portfolio.map((domain) => {
const roi = domain.roi
const renewal = formatExpirationDate(domain.renewal_date)
return (
<div key={domain.id} className="group p-4 bg-background-secondary border border-border rounded-xl hover:border-border-hover transition-all">
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<h3 className="font-mono text-body font-medium text-foreground">{domain.domain}</h3>
{domain.status === 'sold' && <span className="text-ui-xs px-2 py-0.5 bg-accent/10 text-accent rounded-full">Sold</span>}
</div>
<div className="flex flex-wrap items-center gap-3 text-body-sm text-foreground-muted">
{domain.purchase_price && <span className="flex items-center gap-1"><Tag className="w-3.5 h-3.5" />{formatCurrency(domain.purchase_price)}</span>}
{domain.estimated_value && <span className="flex items-center gap-1"><Sparkles className="w-3.5 h-3.5" />{formatCurrency(domain.estimated_value)}</span>}
{renewal && <span className={clsx("flex items-center gap-1", renewal.urgent && "text-warning")}><Calendar className="w-3.5 h-3.5" />{renewal.text}</span>}
{domain.registrar && <span className="flex items-center gap-1"><Globe className="w-3.5 h-3.5" />{domain.registrar}</span>}
</div>
</div>
<div className="flex items-center gap-3">
{roi !== null && (
<div className={clsx("text-right px-3 py-1 rounded-lg", roi >= 0 ? "bg-accent/10" : "bg-danger/10")}>
<p className="text-ui-xs text-foreground-muted">ROI</p>
<p className={clsx("text-body font-medium", roi >= 0 ? "text-accent" : "text-danger")}>{roi >= 0 ? '+' : ''}{roi.toFixed(1)}%</p>
<div className="border border-border rounded-2xl overflow-hidden bg-background-secondary/30">
<table className="w-full">
<thead className="bg-background-secondary/80 backdrop-blur-sm">
<tr className="border-b border-border">
<th className="text-left text-ui-xs font-medium text-foreground-muted uppercase tracking-wider px-5 py-4">Domain</th>
<th className="text-left text-ui-xs font-medium text-foreground-muted uppercase tracking-wider px-5 py-4 hidden sm:table-cell">Purchased</th>
<th className="text-left text-ui-xs font-medium text-foreground-muted uppercase tracking-wider px-5 py-4 hidden md:table-cell">Value</th>
<th className="text-left text-ui-xs font-medium text-foreground-muted uppercase tracking-wider px-5 py-4 hidden lg:table-cell">Renewal</th>
<th className="text-right text-ui-xs font-medium text-foreground-muted uppercase tracking-wider px-5 py-4">ROI</th>
<th className="text-right text-ui-xs font-medium text-foreground-muted uppercase tracking-wider px-5 py-4">Actions</th>
</tr>
</thead>
<tbody className="divide-y divide-border/50">
{portfolio.map((domain) => {
const roi = domain.roi
const renewal = formatExpirationDate(domain.renewal_date)
return (
<tr key={domain.id} className="group hover:bg-background-secondary/60 transition-all duration-200">
<td className="px-5 py-4">
<div className="flex items-center gap-3">
<div className="relative">
<div className={clsx(
"w-2.5 h-2.5 rounded-full",
domain.status === 'sold' ? "bg-accent" : "bg-foreground-subtle"
)} />
</div>
<div>
<span className="font-mono text-body-sm text-foreground">{domain.domain}</span>
{domain.status === 'sold' && <span className="ml-2 text-ui-xs px-1.5 py-0.5 bg-accent/10 text-accent rounded">Sold</span>}
{domain.registrar && <p className="text-body-xs text-foreground-subtle">{domain.registrar}</p>}
</div>
</div>
)}
<div className="flex items-center gap-1 opacity-60 group-hover:opacity-100 transition-opacity">
{domain.status !== 'sold' && <button onClick={() => handleOpenSellModal(domain)} className="p-2 text-foreground-subtle hover:text-accent hover:bg-accent/10 rounded-lg transition-all" title="Sell"><DollarSign className="w-4 h-4" /></button>}
<button onClick={() => handleOpenEditPortfolio(domain)} className="p-2 text-foreground-subtle hover:text-foreground hover:bg-foreground/5 rounded-lg transition-all" title="Edit"><Edit2 className="w-4 h-4" /></button>
<button onClick={() => handleRefreshPortfolioValue(domain.id)} disabled={refreshingPortfolioId === domain.id} className="p-2 text-foreground-subtle hover:text-foreground hover:bg-foreground/5 rounded-lg transition-all" title="Refresh"><RefreshCw className={clsx("w-4 h-4", refreshingPortfolioId === domain.id && "animate-spin")} /></button>
<button onClick={() => handleDeletePortfolioDomain(domain.id)} className="p-2 text-foreground-subtle hover:text-danger hover:bg-danger/10 rounded-lg transition-all" title="Remove"><Trash2 className="w-4 h-4" /></button>
</div>
</div>
</div>
{domain.notes && <p className="mt-3 pt-3 border-t border-border text-body-sm text-foreground-subtle">{domain.notes}</p>}
</div>
)
})}
</td>
<td className="px-5 py-4 hidden sm:table-cell">
<span className="text-body-sm text-foreground">{domain.purchase_price ? formatCurrency(domain.purchase_price) : ''}</span>
{domain.purchase_date && <p className="text-body-xs text-foreground-subtle">{new Date(domain.purchase_date).toLocaleDateString()}</p>}
</td>
<td className="px-5 py-4 hidden md:table-cell">
<span className="text-body-sm text-foreground">{domain.estimated_value ? formatCurrency(domain.estimated_value) : ''}</span>
</td>
<td className="px-5 py-4 hidden lg:table-cell">
{renewal ? (
<span className={clsx("text-body-sm flex items-center gap-1.5", renewal.urgent ? "text-warning font-medium" : "text-foreground-subtle")}>
<Calendar className="w-3.5 h-3.5" />{renewal.text}
</span>
) : <span className="text-foreground-subtle/50">—</span>}
</td>
<td className="px-5 py-4 text-right">
{roi !== null ? (
<span className={clsx("text-body-sm font-medium", roi >= 0 ? "text-accent" : "text-danger")}>
{roi >= 0 ? '+' : ''}{roi.toFixed(1)}%
</span>
) : <span className="text-foreground-subtle/50">—</span>}
</td>
<td className="px-5 py-4">
<div className="flex items-center justify-end gap-0.5 opacity-50 group-hover:opacity-100 transition-opacity">
{domain.status !== 'sold' && (
<button onClick={() => handleOpenSellModal(domain)} className="p-2 text-foreground-subtle hover:text-accent hover:bg-accent/10 rounded-lg transition-all" title="Mark as Sold">
<DollarSign className="w-4 h-4" />
</button>
)}
<button onClick={() => handleOpenEditPortfolio(domain)} className="p-2 text-foreground-subtle hover:text-foreground hover:bg-foreground/10 rounded-lg transition-all" title="Edit">
<Edit2 className="w-4 h-4" />
</button>
<button onClick={() => handleRefreshPortfolioValue(domain.id)} disabled={refreshingPortfolioId === domain.id} className="p-2 text-foreground-subtle hover:text-foreground hover:bg-foreground/10 rounded-lg transition-all" title="Refresh Value">
<RefreshCw className={clsx("w-4 h-4", refreshingPortfolioId === domain.id && "animate-spin")} />
</button>
<button onClick={() => handleDeletePortfolioDomain(domain.id)} className="p-2 text-foreground-subtle hover:text-danger hover:bg-danger/10 rounded-lg transition-all" title="Remove">
<Trash2 className="w-4 h-4" />
</button>
</div>
</td>
</tr>
)
})}
</tbody>
</table>
</div>
)}
</div>
)}
{/* Quick Links */}
<div className="mt-12 p-6 bg-accent/5 border border-accent/20 rounded-2xl flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4">
<div className="flex items-center gap-4">
<div className="w-12 h-12 bg-accent/10 rounded-xl flex items-center justify-center">
<TrendingUp className="w-6 h-6 text-accent" />
</div>
<div>
<p className="text-body font-medium text-foreground">TLD Price Intelligence</p>
<p className="text-body-sm text-foreground-muted">Track 886+ domain extensions in real-time</p>
</div>
</div>
<Link href="/tld-pricing" className="text-ui font-medium text-accent hover:text-accent-hover transition-colors flex items-center gap-1.5 group">
Explore Prices
<ChevronRight className="w-4 h-4 group-hover:translate-x-0.5 transition-transform" />
</Link>
</div>
</div>
</main>

View File

@ -2,12 +2,37 @@
import Link from 'next/link'
import { useStore } from '@/lib/store'
import { LogOut, LayoutDashboard, Menu, X, Settings } from 'lucide-react'
import { useState } from 'react'
import { LogOut, LayoutDashboard, Menu, X, Settings, Bell, User, ChevronDown, TrendingUp, Briefcase, Eye } from 'lucide-react'
import { useState, useRef, useEffect } from 'react'
import clsx from 'clsx'
export function Header() {
const { isAuthenticated, user, logout } = useStore()
const { isAuthenticated, user, logout, domains, subscription } = useStore()
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
const [userMenuOpen, setUserMenuOpen] = useState(false)
const [notificationsOpen, setNotificationsOpen] = useState(false)
const userMenuRef = useRef<HTMLDivElement>(null)
const notificationsRef = useRef<HTMLDivElement>(null)
// Close dropdowns when clicking outside
useEffect(() => {
function handleClickOutside(event: MouseEvent) {
if (userMenuRef.current && !userMenuRef.current.contains(event.target as Node)) {
setUserMenuOpen(false)
}
if (notificationsRef.current && !notificationsRef.current.contains(event.target as Node)) {
setNotificationsOpen(false)
}
}
document.addEventListener('mousedown', handleClickOutside)
return () => document.removeEventListener('mousedown', handleClickOutside)
}, [])
// Count notifications (available domains, etc.)
const availableDomains = domains?.filter(d => d.is_available) || []
const hasNotifications = availableDomains.length > 0
const tierName = subscription?.tier_name || subscription?.tier || 'Scout'
return (
<header className="fixed top-0 left-0 right-0 z-50 bg-background/80 backdrop-blur-xl border-b border-border-subtle">
@ -50,51 +75,165 @@ export function Header() {
>
Auctions
</Link>
<Link
href="/pricing"
className="flex items-center h-9 px-3 text-[0.8125rem] text-foreground-muted hover:text-foreground
hover:bg-background-secondary rounded-lg transition-all duration-300"
>
Plans
</Link>
{!isAuthenticated && (
<Link
href="/pricing"
className="flex items-center h-9 px-3 text-[0.8125rem] text-foreground-muted hover:text-foreground
hover:bg-background-secondary rounded-lg transition-all duration-300"
>
Plans
</Link>
)}
</nav>
</div>
{/* Right side: Auth Links - vertically centered */}
<nav className="hidden sm:flex items-center h-full gap-1">
<nav className="hidden sm:flex items-center h-full gap-2">
{isAuthenticated ? (
<>
{/* Dashboard Link */}
<Link
href="/dashboard"
className="flex items-center gap-2 h-9 px-4 text-[0.8125rem] text-foreground-muted
hover:text-foreground hover:bg-background-secondary rounded-lg
transition-all duration-300"
className="flex items-center gap-2 h-9 px-4 text-[0.8125rem] font-medium text-foreground
bg-foreground/5 hover:bg-foreground/10 rounded-lg transition-all duration-300"
>
<LayoutDashboard className="w-4 h-4" />
<span>Dashboard</span>
</Link>
<Link
href="/settings"
className="flex items-center justify-center w-9 h-9 text-foreground-subtle hover:text-foreground hover:bg-background-secondary rounded-lg transition-all duration-300"
title="Settings"
>
<Settings className="w-4 h-4" />
</Link>
<div className="flex items-center h-full gap-3 ml-2 pl-4 border-l border-border">
<span className="text-[0.8125rem] text-foreground-subtle hidden md:flex items-center">
{user?.email}
</span>
{/* Notifications */}
<div ref={notificationsRef} className="relative">
<button
onClick={logout}
className="flex items-center justify-center w-9 h-9 text-foreground-subtle hover:text-foreground hover:bg-background-secondary
rounded-lg transition-all duration-300"
title="Sign out"
onClick={() => setNotificationsOpen(!notificationsOpen)}
className={clsx(
"relative flex items-center justify-center w-9 h-9 rounded-lg transition-all duration-300",
notificationsOpen ? "bg-foreground/10 text-foreground" : "text-foreground-muted hover:text-foreground hover:bg-foreground/5"
)}
>
<LogOut className="w-4 h-4" />
<Bell className="w-4 h-4" />
{hasNotifications && (
<span className="absolute top-1.5 right-1.5 w-2 h-2 bg-accent rounded-full">
<span className="absolute inset-0 rounded-full bg-accent animate-ping opacity-50" />
</span>
)}
</button>
{/* Notifications Dropdown */}
{notificationsOpen && (
<div className="absolute right-0 top-full mt-2 w-80 bg-background-secondary border border-border rounded-xl shadow-2xl overflow-hidden">
<div className="p-4 border-b border-border">
<h3 className="text-body-sm font-medium text-foreground">Notifications</h3>
</div>
<div className="max-h-80 overflow-y-auto">
{availableDomains.length > 0 ? (
<div className="p-2">
{availableDomains.map((domain) => (
<Link
key={domain.id}
href="/dashboard"
onClick={() => setNotificationsOpen(false)}
className="flex items-start gap-3 p-3 hover:bg-foreground/5 rounded-lg transition-colors"
>
<div className="w-8 h-8 bg-accent/10 rounded-lg flex items-center justify-center shrink-0">
<Eye className="w-4 h-4 text-accent" />
</div>
<div className="flex-1 min-w-0">
<p className="text-body-sm font-medium text-foreground truncate">{domain.name}</p>
<p className="text-body-xs text-accent">Domain is available!</p>
</div>
</Link>
))}
</div>
) : (
<div className="p-8 text-center">
<Bell className="w-8 h-8 text-foreground-subtle mx-auto mb-3" />
<p className="text-body-sm text-foreground-muted">No notifications</p>
<p className="text-body-xs text-foreground-subtle mt-1">We'll notify you when domains become available</p>
</div>
)}
</div>
<Link
href="/settings"
onClick={() => setNotificationsOpen(false)}
className="block p-3 text-center text-body-xs text-foreground-muted hover:text-foreground hover:bg-foreground/5 border-t border-border transition-colors"
>
Manage notifications
</Link>
</div>
)}
</div>
{/* User Menu */}
<div ref={userMenuRef} className="relative">
<button
onClick={() => setUserMenuOpen(!userMenuOpen)}
className={clsx(
"flex items-center gap-2 h-9 pl-3 pr-2 rounded-lg transition-all duration-300",
userMenuOpen ? "bg-foreground/10" : "hover:bg-foreground/5"
)}
>
<div className="w-6 h-6 bg-accent/10 rounded-full flex items-center justify-center">
<User className="w-3.5 h-3.5 text-accent" />
</div>
<ChevronDown className={clsx("w-3.5 h-3.5 text-foreground-muted transition-transform", userMenuOpen && "rotate-180")} />
</button>
{/* User Dropdown */}
{userMenuOpen && (
<div className="absolute right-0 top-full mt-2 w-64 bg-background-secondary border border-border rounded-xl shadow-2xl overflow-hidden">
{/* User Info */}
<div className="p-4 border-b border-border">
<p className="text-body-sm font-medium text-foreground truncate">{user?.name || user?.email}</p>
<p className="text-body-xs text-foreground-muted truncate">{user?.email}</p>
<div className="flex items-center gap-2 mt-2">
<span className="text-ui-xs px-2 py-0.5 bg-foreground/5 text-foreground-muted rounded-full">{tierName}</span>
<span className="text-ui-xs text-foreground-subtle">{subscription?.domains_used || 0}/{subscription?.domain_limit || 5} domains</span>
</div>
</div>
{/* Menu Items */}
<div className="p-2">
<Link
href="/dashboard"
onClick={() => setUserMenuOpen(false)}
className="flex items-center gap-3 px-3 py-2.5 text-body-sm text-foreground-muted hover:text-foreground hover:bg-foreground/5 rounded-lg transition-colors"
>
<LayoutDashboard className="w-4 h-4" />
Command Center
</Link>
<Link
href="/tld-pricing"
onClick={() => setUserMenuOpen(false)}
className="flex items-center gap-3 px-3 py-2.5 text-body-sm text-foreground-muted hover:text-foreground hover:bg-foreground/5 rounded-lg transition-colors"
>
<TrendingUp className="w-4 h-4" />
TLD Pricing
</Link>
<Link
href="/settings"
onClick={() => setUserMenuOpen(false)}
className="flex items-center gap-3 px-3 py-2.5 text-body-sm text-foreground-muted hover:text-foreground hover:bg-foreground/5 rounded-lg transition-colors"
>
<Settings className="w-4 h-4" />
Settings
</Link>
</div>
{/* Logout */}
<div className="p-2 border-t border-border">
<button
onClick={() => {
logout()
setUserMenuOpen(false)
}}
className="flex items-center gap-3 w-full px-3 py-2.5 text-body-sm text-foreground-muted hover:text-foreground hover:bg-foreground/5 rounded-lg transition-colors"
>
<LogOut className="w-4 h-4" />
Sign out
</button>
</div>
</div>
)}
</div>
</>
) : (
@ -132,6 +271,15 @@ export function Header() {
<nav className="px-4 py-4 space-y-2">
{isAuthenticated ? (
<>
{/* User Info on Mobile */}
<div className="px-4 py-3 mb-2 border-b border-border">
<p className="text-body-sm font-medium text-foreground truncate">{user?.name || user?.email}</p>
<div className="flex items-center gap-2 mt-1">
<span className="text-ui-xs px-2 py-0.5 bg-foreground/5 text-foreground-muted rounded-full">{tierName}</span>
<span className="text-ui-xs text-foreground-subtle">{subscription?.domains_used || 0}/{subscription?.domain_limit || 5} domains</span>
</div>
</div>
<Link
href="/dashboard"
className="flex items-center gap-3 px-4 py-3 text-body-sm text-foreground-muted
@ -142,6 +290,26 @@ export function Header() {
<LayoutDashboard className="w-5 h-5" />
<span>Dashboard</span>
</Link>
<Link
href="/tld-pricing"
className="flex items-center gap-3 px-4 py-3 text-body-sm text-foreground-muted
hover:text-foreground hover:bg-background-secondary rounded-xl
transition-all duration-300"
onClick={() => setMobileMenuOpen(false)}
>
<TrendingUp className="w-5 h-5" />
<span>TLD Pricing</span>
</Link>
<Link
href="/auctions"
className="flex items-center gap-3 px-4 py-3 text-body-sm text-foreground-muted
hover:text-foreground hover:bg-background-secondary rounded-xl
transition-all duration-300"
onClick={() => setMobileMenuOpen(false)}
>
<Briefcase className="w-5 h-5" />
<span>Auctions</span>
</Link>
<Link
href="/settings"
className="flex items-center gap-3 px-4 py-3 text-body-sm text-foreground-muted