Instantly share code, notes, and snippets.
Created
March 29, 2025 13:02
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
Save xerudro/d5cc5dacc452d1b6c922b1d07e4b5c0f to your computer and use it in GitHub Desktop.
SuperHosting Navbar
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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