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)} />}
{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}
);
}