Files
compor-academy/components/Navbar.tsx
Cauê Faleiros 7b2d25aabb
All checks were successful
CI / Validate frontend and API (push) Successful in 54s
CI / Build and publish Docker images (push) Successful in 26s
feat: add public instructor profiles
2026-09-08 10:50:35 -03:00

144 lines
7.5 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { User as UserIcon, LogOut, Search, Folder, BookOpenCheck, ChevronDown, ShieldCheck, Settings, UserRound } from 'lucide-react';
import { useAuth } from '../context/AuthContext';
import { LoginModal } from './LoginModal';
import { SearchModal } from './SearchModal';
import { useNavigate, useLocation } from 'react-router-dom';
import { Course } from '../types';
import { Logo } from './Logo';
interface NavbarProps {
onPlay: (course: Course) => void;
}
export const Navbar: React.FC<NavbarProps> = ({ onPlay }) => {
const [scrolled, setScrolled] = useState(false);
const [showLoginModal, setShowLoginModal] = useState(false);
const [showSearchModal, setShowSearchModal] = useState(false);
const [showAccountMenu, setShowAccountMenu] = useState(false);
const { user, logout } = useAuth();
const navigate = useNavigate();
const location = useLocation();
useEffect(() => {
const handleScroll = () => {
setScrolled(window.scrollY > 20);
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
const handleLogout = () => {
logout();
navigate('/');
};
const isMaterialsPage = location.pathname === '/materiais';
const isHomePage = location.pathname === '/';
const goTo = (path: string) => {
setShowAccountMenu(false);
navigate(path);
};
return (
<>
<nav
className={`fixed top-0 left-0 right-0 z-50 transition-all duration-500 ease-in-out px-6 md:px-12 py-4 ${
scrolled || location.pathname !== '/'
? 'bg-[#09090b]/95 backdrop-blur-xl shadow-2xl shadow-black/80'
: 'bg-transparent bg-gradient-to-b from-black/90 via-black/40 to-transparent'
}`}
>
<div className="max-w-[1440px] mx-auto flex items-center justify-between gap-4">
<div className="flex items-center gap-6 md:gap-8">
<div
className="flex items-center gap-2 group cursor-pointer"
onClick={() => navigate('/')}
>
<Logo variant="dark" size="lg" />
</div>
{/* Quick Navigation Links */}
<div className="hidden md:flex items-center gap-2 text-sm font-medium">
<button
onClick={() => navigate('/')}
className={`px-4 py-2 rounded-[980px] transition-colors ${
isHomePage
? 'text-white bg-white/10 font-semibold'
: 'text-gray-400 hover:text-white hover:bg-white/5'
}`}
>
Cursos
</button>
<button
onClick={() => navigate('/materiais')}
className={`px-4 py-2 rounded-[980px] transition-colors flex items-center gap-2 ${
isMaterialsPage
? 'text-orange-400 bg-orange-500/15 font-semibold border border-orange-500/30'
: 'text-gray-400 hover:text-orange-400 hover:bg-white/5'
}`}
>
<Folder className="w-4 h-4 text-orange-400" />
<span>Biblioteca de Materiais</span>
</button>
</div>
</div>
<div className="flex items-center gap-3 sm:gap-4">
{/* Search */}
<button
onClick={() => setShowSearchModal(true)}
className="text-gray-300 hover:text-white text-sm font-medium transition-colors flex items-center gap-2 px-3.5 py-2.5 rounded-[980px] hover:bg-white/10 border border-transparent hover:border-white/10"
>
<Search className="w-4 h-4" />
<span className="hidden lg:inline">Buscar</span>
</button>
{!user ? (
<button
onClick={() => setShowLoginModal(true)}
className="flex items-center gap-2.5 bg-orange-500 hover:bg-orange-600 active:scale-95 transition-all duration-300 px-6 py-2.5 rounded-[980px] text-sm font-bold text-white shadow-xl shadow-orange-500/25 shrink-0"
>
<UserIcon className="w-4 h-4 text-white" />
<span>Entrar</span>
</button>
) : (
<div className="flex items-center gap-3">
<div className="relative">
<button onClick={() => setShowAccountMenu((current) => !current)} className="flex items-center gap-2 rounded-[980px] px-3 py-2 text-sm text-gray-300 hover:bg-white/10 hover:text-white transition-colors" aria-expanded={showAccountMenu} aria-haspopup="menu">
<span className="hidden md:block">Olá, <strong className="font-semibold text-white">{user.name.split(' ')[0]}</strong></span>
<ChevronDown className={`h-4 w-4 transition-transform ${showAccountMenu ? 'rotate-180' : ''}`} />
</button>
{showAccountMenu && <div role="menu" className="absolute right-0 top-full mt-2 w-56 overflow-hidden rounded-xl border border-white/10 bg-zinc-950 p-1.5 shadow-2xl shadow-black/60">
<button role="menuitem" onClick={() => goTo('/perfil')} className="flex w-full items-center gap-2.5 rounded-lg px-3 py-2.5 text-left text-sm text-gray-200 hover:bg-white/10"><UserRound className="h-4 w-4 text-orange-400" /> Meu perfil</button>
{user.role === 'student' && <button role="menuitem" onClick={() => goTo('/meu-aprendizado')} className="flex w-full items-center gap-2.5 rounded-lg px-3 py-2.5 text-left text-sm text-gray-200 hover:bg-white/10"><BookOpenCheck className="h-4 w-4 text-orange-400" /> Meu aprendizado</button>}
{user.role === 'professor' && <button role="menuitem" onClick={() => goTo('/gerenciar')} className="flex w-full items-center gap-2.5 rounded-lg px-3 py-2.5 text-left text-sm text-gray-200 hover:bg-white/10"><Settings className="h-4 w-4 text-orange-400" /> Painel do instrutor</button>}
{user.role === 'superadmin' && <><button role="menuitem" onClick={() => goTo('/admin')} className="flex w-full items-center gap-2.5 rounded-lg px-3 py-2.5 text-left text-sm text-gray-200 hover:bg-white/10"><ShieldCheck className="h-4 w-4 text-orange-400" /> Painel administrativo</button><button role="menuitem" onClick={() => goTo('/gerenciar')} className="flex w-full items-center gap-2.5 rounded-lg px-3 py-2.5 text-left text-sm text-gray-200 hover:bg-white/10"><Settings className="h-4 w-4 text-orange-400" /> Gerenciar cursos</button></>}
</div>}
</div>
<div className="h-4 w-[1px] bg-white/20 hidden sm:block"></div>
<div className="flex items-center gap-2.5">
<button
onClick={handleLogout}
className="flex items-center gap-2 bg-red-500/10 hover:bg-red-500/20 active:scale-95 transition-all duration-300 px-4 py-2 rounded-[980px] border border-red-500/20 group text-xs font-semibold text-red-400"
title="Encerrar Sessão"
>
<LogOut className="w-3.5 h-3.5" />
<span className="hidden sm:inline">Sair</span>
</button>
</div>
</div>
)}
</div>
</div>
</nav>
<LoginModal isOpen={showLoginModal} onClose={() => setShowLoginModal(false)} />
<SearchModal isOpen={showSearchModal} onClose={() => setShowSearchModal(false)} onPlay={onPlay} />
</>
);
};