From 8d0a461e7a9fc84df7b56962d7d1eca32b5dc77c Mon Sep 17 00:00:00 2001 From: Krao Hasanee Date: Fri, 29 May 2026 15:23:20 -0400 Subject: [PATCH] Session 2026-05-29: shared dashboard, team tasks page, requests card style, copy/paste files, loading modals, avatar cache bust Co-Authored-By: Claude Sonnet 4.6 --- src/App.jsx | 13 +- src/components/Layout.jsx | 26 ++- src/components/PageLoader.jsx | 40 ++-- src/pages/FileSharing.jsx | 115 +++++++---- src/pages/RequestsPage.jsx | 111 ++++------- src/pages/Settings.jsx | 3 +- src/pages/team/TeamDashboard.jsx | 175 ++++++++++------- src/pages/team/TeamTasksPage.jsx | 327 +++++++++++++++++++++++++++++++ 8 files changed, 605 insertions(+), 205 deletions(-) create mode 100644 src/pages/team/TeamTasksPage.jsx diff --git a/src/App.jsx b/src/App.jsx index 224a8d1..7ccb32c 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -63,6 +63,7 @@ const ProjectDetailPage = lazy(() => import('./pages/ProjectDetailPage')); const DashboardPage = lazy(() => import('./pages/DashboardPage')); const TeamDashboard = lazy(() => import('./pages/team/TeamDashboard')); const RequestsPage = lazy(() => import('./pages/RequestsPage')); +const TeamTasksPage = lazy(() => import('./pages/team/TeamTasksPage')); const MyInvoices = lazy(() => import('./pages/client/MyInvoices')); const NewRequest = lazy(() => import('./pages/client/NewRequest')); const NewProject = lazy(() => import('./pages/client/NewProject')); @@ -82,11 +83,7 @@ function NavigateCompanyDetail() { return ; } -function DashboardRoute() { - const { currentUser } = useAuth(); - if (currentUser?.role === 'team') return ; - return ; -} + export default function App() { return ( @@ -97,8 +94,7 @@ export default function App() { } /> - } /> - } /> + } /> } /> } /> } /> @@ -107,7 +103,8 @@ export default function App() { } /> } /> } /> - } /> + } /> + } /> } /> } /> } /> diff --git a/src/components/Layout.jsx b/src/components/Layout.jsx index 888ecc6..17322c2 100644 --- a/src/components/Layout.jsx +++ b/src/components/Layout.jsx @@ -1,4 +1,5 @@ import { useState, useEffect, useRef } from 'react'; +import PageLoader from './PageLoader'; import { NavLink, useNavigate, useLocation } from 'react-router-dom'; import { useAuth } from '../context/AuthContext'; @@ -25,8 +26,8 @@ function TeamNav({ onNav }) { const location = useLocation(); const primaryLinks = [ - { to: '/team/dashboard', label: 'Dashboard', icon: ICONS.dashboard }, - { to: '/requests', label: 'Requests', icon: ICONS.requests }, + { to: '/dashboard', label: 'Dashboard', icon: ICONS.dashboard }, + { to: '/team/tasks', label: 'Tasks', icon: ICONS.requests }, { to: '/projects', label: 'Projects', icon: ICONS.projects }, { to: '/invoices', label: 'Finances', icon: ICONS.invoices }, { to: '/file-sharing', label: 'File Sharing', icon: ICONS.fileSharing }, @@ -140,12 +141,18 @@ export default function Layout({ children }) { const firstName = currentUser?.name?.split(' ')[0] || ''; const isProfileRoute = location.pathname === '/profile' || location.pathname.startsWith('/profile/'); const isFileSharingRoute = location.pathname === '/file-sharing'; - const headerTitle = isProfileRoute ? 'Profile' : isFileSharingRoute ? 'File Sharing' : `Good ${timeOfDay}${firstName ? `, ${firstName}` : ''}`; + const isRequestsRoute = location.pathname === '/requests'; + const isTasksRoute = location.pathname === '/team/tasks'; + const headerTitle = isProfileRoute ? 'Profile' : isFileSharingRoute ? 'File Sharing' : isTasksRoute ? 'Tasks & Projects' : isRequestsRoute ? 'Requests' : `Good ${timeOfDay}${firstName ? `, ${firstName}` : ''}`; const headerSubtitle = isProfileRoute ? 'Account details and security settings.' : isFileSharingRoute ? 'Browse, share and manage files.' - : "Here's what's happening today."; + : isTasksRoute + ? 'Browse and manage all tasks and projects.' + : isRequestsRoute + ? 'Browse and manage all your requests.' + : "Here's what's happening today."; useEffect(() => { document.documentElement.setAttribute('data-theme', theme); @@ -174,6 +181,9 @@ export default function Layout({ children }) { 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); @@ -181,6 +191,13 @@ export default function Layout({ children }) { 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('/'); }; @@ -188,6 +205,7 @@ export default function Layout({ children }) { return (
+ {navigating && } {menuOpen &&
setMenuOpen(false)} />}