import React, { useState, useEffect } from 'react'; import { Link, useNavigate, useLocation } from 'react-router-dom'; import { useAuth } from '../src/contexts/AuthContext'; import { useLanguage } from '../src/contexts/LanguageContext'; import { useTheme, PALETTES, ColorPalette } from '../src/contexts/ThemeContext'; import { LogOut, User, LayoutDashboard, Menu, Settings, Globe, ChevronDown, Video, Shield, X, Coins, AlertCircle, Sun, Moon, Palette, Check } from 'lucide-react'; import { CaStADLogo, CaStADLogoInline } from './CaStADLogo'; import { Language } from '../types'; import { cn } from '../src/lib/utils'; import { Button } from '../src/components/ui/button'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from '../src/components/ui/dropdown-menu'; import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger, SheetClose, } from '../src/components/ui/sheet'; import { Avatar, AvatarFallback } from '../src/components/ui/avatar'; import { Badge } from '../src/components/ui/badge'; import { Separator } from '../src/components/ui/separator'; const LANGUAGES = [ { code: 'KO', label: '한국어', flag: 'kr' }, { code: 'EN', label: 'English', flag: 'us' }, { code: 'JP', label: '日本語', flag: 'jp' }, { code: 'CN', label: '中文', flag: 'cn' }, { code: 'TH', label: 'ไทย', flag: 'th' }, { code: 'VN', label: 'Tiếng Việt', flag: 'vn' }, ] as const; const Navbar: React.FC = () => { const { user, logout, token } = useAuth(); const { language, setLanguage, t } = useLanguage(); const { theme, palette, toggleTheme, setPalette } = useTheme(); const navigate = useNavigate(); const location = useLocation(); const [isScrolled, setIsScrolled] = useState(false); const [mobileOpen, setMobileOpen] = useState(false); const [credits, setCredits] = useState(null); useEffect(() => { const handleScroll = () => { setIsScrolled(window.scrollY > 10); }; window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll); }, []); // 크레딧 조회 useEffect(() => { const fetchCredits = async () => { if (!user || !token) { setCredits(null); return; } try { const backendPort = import.meta.env.VITE_BACKEND_PORT || '3001'; const res = await fetch(`http://localhost:${backendPort}/api/credits`, { headers: { Authorization: `Bearer ${token}` } }); if (res.ok) { const data = await res.json(); setCredits(data.credits); } } catch (err) { console.error('Failed to fetch credits:', err); } }; fetchCredits(); // 주기적으로 업데이트 (30초마다) const interval = setInterval(fetchCredits, 30000); return () => clearInterval(interval); }, [user, token]); const handleLogout = () => { logout(); navigate('/login'); setMobileOpen(false); }; // Hide navbar during server rendering (autoplay mode) const searchParams = new URLSearchParams(location.search); if (searchParams.get('autoplay') === 'true') { return null; } const currentLanguage = LANGUAGES.find(l => l.code === language) || LANGUAGES[0]; const NavLink = ({ to, children, icon: Icon }: { to: string; children: React.ReactNode; icon?: React.ElementType }) => { const isActive = location.pathname === to; return ( setMobileOpen(false)} className={cn( "flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium transition-all duration-200", isActive ? "bg-primary/10 text-primary" : "text-muted-foreground hover:text-foreground hover:bg-accent" )} > {Icon && } {children} ); }; return ( ); }; export default Navbar;