import { useState, useEffect, useRef } from 'react'; import PageLoader from './PageLoader'; import { NavLink, Link, useNavigate, useLocation } from 'react-router-dom'; import { useAuth } from '../context/AuthContext'; const ICONS = { dashboard: , requests: , projects: , fileSharing: , invoices: , notes: , survey: , brandBook: , converter: , passwords: , companies: , users: , }; function NI({ icon }) { return {icon}; } function TeamNav({ onNav }) { const location = useLocation(); const primaryLinks = [ { to: '/dashboard', label: 'Dashboard', icon: ICONS.dashboard }, { to: '/tasks', label: 'Tasks', icon: ICONS.requests }, { to: '/invoices', label: 'Finances', icon: ICONS.invoices }, { to: '/file-sharing', label: 'File Sharing', icon: ICONS.fileSharing }, ]; const utilityLinks = [ { to: '/survey-maker', label: 'Survey Maker', icon: ICONS.survey }, { to: '/brand-book', label: 'Brand Book Maker', icon: ICONS.brandBook }, { to: '/converters', label: 'Image Converter', icon: ICONS.converter }, { to: '/fourge-passwords', label: 'Fourge Passwords', icon: ICONS.passwords }, ]; const isCompaniesActive = location.pathname === '/company' && !location.search.includes('tab=users'); const isUsersActive = location.pathname === '/company' && location.search.includes('tab=users'); const isTasksActive = location.pathname === '/tasks' || location.pathname.startsWith('/tasks/') || location.pathname.startsWith('/projects/') || location.pathname.startsWith('/requests/'); return (
{primaryLinks.map(({ to, label, icon }) => ( `sidebar-link${isTasksActive ? ' active' : ''}` : ({ isActive }) => `sidebar-link${isActive ? ' active' : ''}`}> {label} ))}
Tools
{utilityLinks.map(({ to, label, icon }) => ( `sidebar-link${isActive ? ' active' : ''}`}> {label} ))} `sidebar-link${isCompaniesActive ? ' active' : ''}`}> Companies `sidebar-link${isUsersActive ? ' active' : ''}`}> Users
); } function ClientNav({ onNav }) { const location = useLocation(); const isTasksActive = location.pathname === '/tasks' || location.pathname.startsWith('/tasks/') || location.pathname.startsWith('/projects/') || location.pathname.startsWith('/requests/'); const links = [ { to: '/dashboard', label: 'Dashboard', icon: ICONS.dashboard }, { to: '/tasks', label: 'Tasks', icon: ICONS.requests }, { to: '/file-sharing', label: 'File Sharing', icon: ICONS.fileSharing }, { to: '/my-invoices', label: 'Invoices', icon: ICONS.invoices }, ]; return (
{links.map(({ to, label, icon }) => ( `sidebar-link${isTasksActive ? ' active' : ''}` : ({ isActive }) => `sidebar-link${isActive ? ' active' : ''}`}> {label} ))}
); } function ExternalNav({ onNav }) { const location = useLocation(); const isTasksActive = location.pathname === '/tasks' || location.pathname.startsWith('/tasks/') || location.pathname.startsWith('/projects/') || location.pathname.startsWith('/requests/'); const links = [ { to: '/dashboard', label: 'Dashboard', icon: ICONS.dashboard }, { to: '/tasks', label: 'Tasks', icon: ICONS.requests }, { to: '/my-invoices-sub', label: 'Invoices', icon: ICONS.invoices }, { to: '/file-sharing', label: 'File Sharing', icon: ICONS.fileSharing }, { to: '/survey-maker', label: 'Survey Maker', icon: ICONS.survey }, { to: '/brand-book', label: 'Brand Book Maker', icon: ICONS.brandBook }, { to: '/converters', label: 'Image Converter', icon: ICONS.converter }, ]; return (
{links.map(({ to, label, icon }, index) => (
{index === 4 && ( <>
Tools
)} `sidebar-link${isTasksActive ? ' active' : ''}` : ({ isActive }) => `sidebar-link${isActive ? ' active' : ''}`}> {label}
))}
); } function getInitialTheme() { if (typeof document !== 'undefined') { return document.documentElement.getAttribute('data-theme') || localStorage.getItem('theme') || 'dark'; } return 'dark'; } export default function Layout({ children }) { const { currentUser, logout } = useAuth(); const navigate = useNavigate(); const location = useLocation(); const [theme, setTheme] = useState(getInitialTheme); const [menuOpen, setMenuOpen] = useState(false); const [searchQuery, setSearchQuery] = useState(''); const [searchResults, setSearchResults] = useState({ projects: [], tasks: [], companies: [], people: [] }); const [searchOpen, setSearchOpen] = useState(false); const searchInputRef = useRef(null); const [avatarOpen, setAvatarOpen] = useState(false); const avatarRef = useRef(null); const hour = new Date().getHours(); const timeOfDay = hour < 12 ? 'morning' : hour < 17 ? 'afternoon' : 'evening'; const firstName = currentUser?.name?.split(' ')[0] || ''; const isProfileRoute = location.pathname === '/profile' || location.pathname.startsWith('/profile/'); const isFileSharingRoute = location.pathname === '/file-sharing'; const isTaskDetailRoute = location.pathname.startsWith('/tasks/') || location.pathname.startsWith('/projects/') || location.pathname.startsWith('/requests/'); const isRequestsRoute = location.pathname === '/tasks' || location.pathname === '/requests' || location.pathname === '/team/tasks' || isTaskDetailRoute; const headerTitle = isProfileRoute ? 'Profile' : isFileSharingRoute ? 'File Sharing' : isRequestsRoute && !isTaskDetailRoute ? 'Tasks & Projects' : !isTaskDetailRoute ? `Good ${timeOfDay}${firstName ? `, ${firstName}` : ''}` : null; const headerSubtitle = isProfileRoute ? 'Account details and security settings.' : isFileSharingRoute ? 'Browse, share and manage files.' : isRequestsRoute && !isTaskDetailRoute ? 'Browse and manage all tasks and projects.' : isTaskDetailRoute ? null : "Here's what's happening today."; useEffect(() => { document.documentElement.setAttribute('data-theme', theme); document.documentElement.style.colorScheme = theme === 'light' ? 'light' : 'dark'; localStorage.setItem('theme', theme); }, [theme]); useEffect(() => { if (!searchQuery.trim()) { setSearchResults({ projects: [], tasks: [], companies: [], people: [] }); return; } const t = setTimeout(async () => { const { supabase } = await import('../lib/supabase'); const [{ data: projects }, { data: tasks }, { data: companies }, { data: people }] = await Promise.all([ supabase.from('projects').select('id, name').ilike('name', `%${searchQuery}%`).limit(6), supabase.from('tasks').select('id, title').ilike('title', `%${searchQuery}%`).limit(6), supabase.from('companies').select('id, name').ilike('name', `%${searchQuery}%`).limit(6), supabase.from('profiles').select('id, name').ilike('name', `%${searchQuery}%`).limit(6), ]); setSearchResults({ projects: projects || [], tasks: tasks || [], companies: companies || [], people: people || [] }); }, 280); return () => clearTimeout(t); }, [searchQuery]); useEffect(() => { if (!avatarOpen) return; function handler(e) { if (avatarRef.current && !avatarRef.current.contains(e.target)) setAvatarOpen(false); } document.addEventListener('mousedown', handler); return () => document.removeEventListener('mousedown', handler); }, [avatarOpen]); const [navigating, setNavigating] = useState(false); const navTimerRef = useRef(null); const [lastPathname, setLastPathname] = useState(location.pathname); if (lastPathname !== location.pathname) { setLastPathname(location.pathname); setMenuOpen(false); setAvatarOpen(false); } useEffect(() => { setNavigating(true); clearTimeout(navTimerRef.current); navTimerRef.current = setTimeout(() => setNavigating(false), 500); return () => clearTimeout(navTimerRef.current); }, [location.pathname]); const toggleTheme = () => setTheme(t => t === 'dark' ? 'light' : 'dark'); const handleLogout = async () => { await logout(); navigate('/'); }; const hasResults = searchResults.projects.length > 0 || searchResults.tasks.length > 0 || searchResults.companies.length > 0 || searchResults.people.length > 0; return (
{navigating && } {menuOpen &&
setMenuOpen(false)} />}
Fourge Branding
{isTaskDetailRoute ? (
Tasks & Projects
Return back to previous page
) : ( <>
{headerTitle}
{headerSubtitle}
)}
setSearchQuery(e.target.value)} onFocus={() => setSearchOpen(true)} onBlur={() => setTimeout(() => { setSearchOpen(false); setSearchQuery(''); }, 150)} onKeyDown={e => { if (e.key === 'Escape') { setSearchOpen(false); setSearchQuery(''); } }} /> {searchOpen && searchQuery.trim() && (
{!hasResults &&
No results for "{searchQuery}"
} {searchResults.projects.length > 0 && ( <>
Projects
{searchResults.projects.map(p => (
{ navigate(`/projects/${p.id}`); setSearchQuery(''); setSearchOpen(false); }}> {ICONS.projects} {p.name}
))} )} {searchResults.tasks.length > 0 && ( <>
Tasks
{searchResults.tasks.map(r => (
{ navigate(`/tasks/${r.id}`); setSearchQuery(''); setSearchOpen(false); }}> {ICONS.requests} {r.title}
))} )} {searchResults.companies.length > 0 && ( <>
Companies
{searchResults.companies.map(c => (
{ navigate(`/company/${c.id}`); setSearchQuery(''); setSearchOpen(false); }}> {ICONS.companies} {c.name}
))} )} {searchResults.people.length > 0 && ( <>
People
{searchResults.people.map(p => (
{ navigate(`/profile/${p.id}`); setSearchQuery(''); setSearchOpen(false); }}> {ICONS.users} {p.name || 'Unknown User'}
))} )}
)}
{avatarOpen && (
)}
{children}
); }