Skip to content

Instantly share code, notes, and snippets.

@xerudro
Created March 29, 2025 13:02
Show Gist options
  • Save xerudro/d5cc5dacc452d1b6c922b1d07e4b5c0f to your computer and use it in GitHub Desktop.
Save xerudro/d5cc5dacc452d1b6c922b1d07e4b5c0f to your computer and use it in GitHub Desktop.
SuperHosting Navbar
// src/components/Navbar.tsx
import React, { useState, useEffect } from 'react';
import { Menu, X, Globe, LogIn, UserPlus, User, LogOut, Shield } from 'lucide-react';
import { Link, useLocation } from 'react-router-dom';
// Updated import path
import { useAuth } from '../components/AuthContext';
// REMOVED: useRole import
// import { useRole } from '../lib/hooks/useRole';
import { AuthModal } from './AuthModal';
const Navbar = () => {
const [isOpen, setIsOpen] = useState(false);
// TODO: Implement proper i18n for language switching
const [language, setLanguage] = useState('EN');
const [showAuthModal, setShowAuthModal] = useState(false);
const [authMode, setAuthMode] = useState<'login' | 'signup'>('login');
// Use correct hook
const { user, logout, isLoadingAuth } = useAuth();
const location = useLocation(); // Get location to close menu on navigation
// --- Direct Role Check (replaces isAdmin()) ---
const isUserAdmin = user?.role === 'admin' || user?.role === 'superadmin';
// Close mobile menu on navigation
useEffect(() => {
setIsOpen(false);
}, [location]);
const toggleLanguage = () => {
// Placeholder - Actual implementation requires i18n library
setLanguage(prev => prev === 'EN' ? 'RO' : 'EN');
console.warn("Language toggle is visual only. Implement i18n.");
};
const handleAuthClick = (mode: 'login' | 'signup') => {
setAuthMode(mode);
setShowAuthModal(true);
setIsOpen(false); // Close mobile menu when opening modal
};
const handleLogout = () => {
logout();
setIsOpen(false); // Close mobile menu on logout
}
// Helper for common link classes
const navLinkClasses = "text-gray-300 hover:text-orangered transition-colors px-3 py-2 rounded-md text-sm font-medium";
const mobileNavLinkClasses = "block px-3 py-2 text-base font-medium text-gray-300 hover:text-orangered transition-colors";
const actionButtonClasses = "inline-flex items-center justify-center px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white transition-colors duration-150 focus:outline-none focus-visible:ring-2 focus->
const navItems = [
{ path: "/", label: "Home" },
{ path: "/services", label: "Services" },
{ path: "/hosting", label: "Hosting" },
{ path: "/websites", label: "Web Design" },
{ path: "/support", label: "Support" },
{ path: "/contact", label: "Contact" },
];
return (
<>
{/* Navigation Bar */}
<nav className="fixed w-full bg-black/90 backdrop-blur-sm z-50 border-b border-gray-800/50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex items-center justify-between h-16">
{/* Logo */}
<div className="flex-shrink-0">
<Link to="/" className="flex items-center" aria-label="VIP Super Hosting Home">
{/* Consider using an SVG logo for better scalability */}
<span className="text-orangered font-bold text-xl sm:text-2xl">VIP</span>
<span className="text-white font-bold text-xl sm:text-2xl mx-1 sm:mx-2">SUPER</span>
<span className="text-blue-500 font-bold text-xl sm:text-2xl">HOSTING</span>
</Link>
</div>
{/* Desktop Navigation */}
<div className="hidden md:flex items-center space-x-1 lg:space-x-4">
{navItems.map(item => (
<Link key={item.path} to={item.path} className={navLinkClasses}>
{item.label}
</Link>
))}
</div>
{/* Desktop Action Buttons */}
<div className="hidden md:flex items-center space-x-3 lg:space-x-4">
{/* Language Toggle Placeholder */}
<button
onClick={toggleLanguage}
className="flex items-center text-gray-400 hover:text-white p-2 rounded-full transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-gray-500"
title="Switch language (Visual Only)"
>
<Globe className="h-5 w-5" />
<span className="ml-1 text-xs font-medium">{language}</span>
</button>
{/* Conditionally render based on auth loading and user state */}
{!isLoadingAuth && (
user ? (
// Logged In Buttons
<>
{isUserAdmin && ( // Use direct role check
<Link
to="/admin"
className={`${actionButtonClasses} bg-gray-700 hover:bg-gray-600 focus-visible:ring-gray-500`}
title="Admin Dashboard"
>
<Shield className="h-4 w-4 mr-1.5" />
Admin
</Link>
)}
<Link
to="/profile" // Changed to /dashboard as per AuthContext redirect? Or keep /profile? Let's keep /profile for now.
className={`${actionButtonClasses} bg-blue-600 hover:bg-blue-700 focus-visible:ring-blue-500`}
title="User Profile"
<User className="h-4 w-4 mr-1.5" />
Profile
</Link>
<button
onClick={handleLogout}
className={`${actionButtonClasses} bg-orangered hover:bg-red-600 focus-visible:ring-orangered`}
>
<LogOut className="h-4 w-4 mr-1.5" />
Logout
</button>
</>
) : (
// Logged Out Buttons
<>
<button
onClick={() => handleAuthClick('login')}
className={`${actionButtonClasses} bg-blue-600 hover:bg-blue-700 focus-visible:ring-blue-500`}
>
<LogIn className="h-4 w-4 mr-1.5" />
Login
</button>
{/* Changed Signup to button opening modal */}
<button
onClick={() => handleAuthClick('signup')}
className={`${actionButtonClasses} bg-orangered hover:bg-red-600 focus-visible:ring-orangered`}
>
<UserPlus className="h-4 w-4 mr-1.5" />
Sign Up
</button>
</>
)
)}
{/* Optionally show a loader while isLoadingAuth is true */}
{/* {isLoadingAuth && <Loader className="animate-spin" />} */}
</div>
{/* Mobile menu button */}
<div className="md:hidden flex items-center">
{/* Optional: Add language toggle for mobile too */}
{/* <button onClick={toggleLanguage} ... /> */}
<button
onClick={() => setIsOpen(!isOpen)}
className="ml-2 inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white"
aria-controls="mobile-menu"
aria-expanded={isOpen}
>
<span className="sr-only">Open main menu</span>
{isOpen ? <X className="block h-6 w-6" aria-hidden="true" /> : <Menu className="block h-6 w-6" aria-hidden="true" />}
</button>
</div>
</div>
</div>
{/* Mobile menu */}
{/* Use absolute positioning or conditional rendering instead of max-h for more reliable layout */}
{isOpen && (
<div className="md:hidden absolute top-full left-0 w-full bg-black/95 shadow-lg" id="mobile-menu">
<div className="px-2 pt-2 pb-3 space-y-1 sm:px-3">
{navItems.map(item => (
<Link key={item.path} to={item.path} className={mobileNavLinkClasses}>
{item.label}
</Link>
))}
</div>
{/* Mobile Action Buttons */}
<div className="border-t border-gray-700 pt-4 pb-3">
{!isLoadingAuth && (
<div className="px-5 space-y-3">
{user ? (
<>
{isUserAdmin && (
<Link to="/admin" className={`${actionButtonClasses} w-full bg-gray-700 hover:bg-gray-600 focus-visible:ring-gray-500`}>
<Shield className="h-4 w-4 mr-1.5" /> Admin
</Link>
)}
<Link to="/profile" className={`${actionButtonClasses} w-full bg-blue-600 hover:bg-blue-700 focus-visible:ring-blue-500`}>
<User className="h-4 w-4 mr-1.5" /> Profile
</Link>
<button onClick={handleLogout} className={`${actionButtonClasses} w-full bg-orangered hover:bg-red-600 focus-visible:ring-orangered`}>
<LogOut className="h-4 w-4 mr-1.5" /> Logout
</button>
</>
) : (
<>
<button onClick={() => handleAuthClick('login')} className={`${actionButtonClasses} w-full bg-blue-600 hover:bg-blue-700 focus-visible:ring-blue-500`}>
<LogIn className="h-4 w-4 mr-1.5" /> Login
</button>
<button onClick={() => handleAuthClick('signup')} className={`${actionButtonClasses} w-full bg-orangered hover:bg-red-600 focus-visible:ring-orangered`}>
<UserPlus className="h-4 w-4 mr-1.5" /> Sign Up
</button>
</>
)}
{/* Mobile Language Toggle */}
<button onClick={toggleLanguage} className="flex items-center justify-center w-full mt-2 text-gray-400 hover:text-white transition-colors">
<Globe className="h-5 w-5 mr-2" /> {language}
</button>
</div>
)}
</div>
</div>
)}
</nav>
{/* --- Fixed Height Spacer --- */}
{/* Ensures content below doesn't get hidden by the fixed navbar */}
<div className="h-16" />
{/* Auth Modal (Unchanged) */}
<AuthModal
isOpen={showAuthModal}
onClose={() => setShowAuthModal(false)}
defaultMode={authMode}
/>
</>
);
};
export default Navbar;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment