import React, { useState, useRef, useEffect } from 'react'; import { Link, useNavigate } from 'react-router-dom'; import { UserIcon, Bars3Icon, BoltIcon, InboxIcon, } from '@heroicons/react/24/solid'; import { EnvelopeIcon, MagnifyingGlassIcon } from '@heroicons/react/24/outline'; import { useTranslation } from 'react-i18next'; import PomodoroTimer from './Shared/PomodoroTimer'; import UniversalSearch from './UniversalSearch/UniversalSearch'; import NotificationsDropdown from './Notifications/NotificationsDropdown'; import { getApiPath } from '../config/paths'; import { getFeatureFlags, FeatureFlags } from '../utils/featureFlags'; import { setUserTimezone } from '../utils/dateUtils'; interface NavbarProps { isDarkMode: boolean; toggleDarkMode: () => void; currentUser: { email: string; avatar_image?: string; is_admin?: boolean; }; setCurrentUser: React.Dispatch>; isSidebarOpen: boolean; setIsSidebarOpen: React.Dispatch>; } const Navbar: React.FC = ({ currentUser, setCurrentUser, isSidebarOpen, setIsSidebarOpen, isDarkMode, }) => { const { t } = useTranslation(); const [isDropdownOpen, setIsDropdownOpen] = useState(false); const [isMobileSearchOpen, setIsMobileSearchOpen] = useState(false); const [pomodoroEnabled, setPomodoroEnabled] = useState(true); // Default to true const [featureFlags, setFeatureFlags] = useState({ backups: false, calendar: false, habits: false, }); const dropdownRef = useRef(null); const navigate = useNavigate(); // Dispatch event when mobile search state changes useEffect(() => { window.dispatchEvent( new CustomEvent('mobileSearchToggle', { detail: { isOpen: isMobileSearchOpen }, }) ); }, [isMobileSearchOpen]); // Listen for close mobile search events useEffect(() => { const handleCloseMobileSearch = () => { setIsMobileSearchOpen(false); }; window.addEventListener('closeMobileSearch', handleCloseMobileSearch); return () => { window.removeEventListener( 'closeMobileSearch', handleCloseMobileSearch ); }; }, []); useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if ( dropdownRef.current && !dropdownRef.current.contains(event.target as Node) ) { setIsDropdownOpen(false); } }; document.addEventListener('mousedown', handleClickOutside); return () => { document.removeEventListener('mousedown', handleClickOutside); }; }, []); // Fetch user's pomodoro setting and feature flags useEffect(() => { const fetchProfile = async () => { try { const response = await fetch(getApiPath('profile'), { credentials: 'include', }); if (response.ok) { const profile = await response.json(); setPomodoroEnabled( profile.pomodoro_enabled !== undefined ? profile.pomodoro_enabled : true ); // Set user timezone for date formatting if (profile.timezone) { setUserTimezone(profile.timezone); } } } catch (error) { console.error('Error fetching profile:', error); // Keep default value (true) if fetch fails } }; const fetchFlags = async () => { const flags = await getFeatureFlags(); setFeatureFlags(flags); }; fetchProfile(); fetchFlags(); // Listen for Pomodoro setting changes from ProfileSettings const handlePomodoroSettingChange = (event: CustomEvent) => { setPomodoroEnabled(event.detail.enabled); }; window.addEventListener( 'pomodoroSettingChanged', handlePomodoroSettingChange as EventListener ); return () => { window.removeEventListener( 'pomodoroSettingChanged', handlePomodoroSettingChange as EventListener ); }; }, []); const toggleDropdown = () => { setIsDropdownOpen(!isDropdownOpen); }; const handleLogout = async () => { try { const response = await fetch(getApiPath('logout'), { method: 'GET', credentials: 'include', }); if (response.ok) { setCurrentUser(null); navigate('/login'); } else { console.error('Logout failed:', await response.json()); } } catch (error) { console.error('Error during logout:', error); } }; return ( ); }; export default Navbar;