MCPcopy Index your code
hub / github.com/GreatStackDev/project-management / ProjectSidebar

Function ProjectSidebar

src/components/ProjectsSidebar.jsx:6–75  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

4import { useSelector } from 'react-redux';
5
6const ProjectSidebar = () => {
7
8 const location = useLocation();
9
10 const [expandedProjects, setExpandedProjects] = useState(new Set());
11 const [searchParams] = useSearchParams();
12
13 const projects = useSelector(
14 (state) => state?.workspace?.currentWorkspace?.projects || []
15 );
16
17 const getProjectSubItems = (projectId) => [
18 { title: 'Tasks', icon: KanbanIcon, url: `/projectsDetail?id=${projectId}&tab=tasks` },
19 { title: 'Analytics', icon: ChartColumnIcon, url: `/projectsDetail?id=${projectId}&tab=analytics` },
20 { title: 'Calendar', icon: CalendarIcon, url: `/projectsDetail?id=${projectId}&tab=calendar` },
21 { title: 'Settings', icon: SettingsIcon, url: `/projectsDetail?id=${projectId}&tab=settings` }
22 ];
23
24 const toggleProject = (id) => {
25 const newSet = new Set(expandedProjects);
26 newSet.has(id) ? newSet.delete(id) : newSet.add(id);
27 setExpandedProjects(newSet);
28 };
29
30 return (
31 <div className="mt-6 px-3">
32 <div className="flex items-center justify-between px-3 py-2">
33 <h3 className="text-xs font-medium text-gray-500 dark:text-zinc-400 uppercase tracking-wider">
34 Projects
35 </h3>
36 <Link to="/projects">
37 <button className="size-5 text-gray-500 dark:text-zinc-400 hover:text-gray-900 dark:hover:text-white hover:bg-gray-100 dark:hover:bg-zinc-800 rounded flex items-center justify-center transition-colors duration-200">
38 <ArrowRightIcon className="size-3" />
39 </button>
40 </Link>
41 </div>
42
43 <div className="space-y-1 px-3">
44 {projects.map((project) => (
45 <div key={project.id}>
46 <button onClick={() => toggleProject(project.id)} className="w-full flex items-center gap-2 px-3 py-2 rounded-lg transition-colors duration-200 text-gray-700 dark:text-zinc-300 hover:bg-gray-100 dark:hover:bg-zinc-800 hover:text-gray-900 dark:hover:text-white" >
47 <ChevronRightIcon className={`size-3 text-gray-500 dark:text-zinc-400 transition-transform duration-200 ${expandedProjects.has(project.id) && 'rotate-90'}`} />
48 <div className="size-2 rounded-full bg-blue-500" />
49 <span className="truncate max-w-40 text-sm">{project.name}</span>
50 </button>
51
52 {expandedProjects.has(project.id) && (
53 <div className="ml-5 mt-1 space-y-1">
54 {getProjectSubItems(project.id).map((subItem) => {
55 // checking if the current path matches the sub-item's URL
56 const isActive =
57 location.pathname === `/projectsDetail` &&
58 searchParams.get('id') === project.id &&
59 searchParams.get('tab') === subItem.title.toLowerCase();
60
61 return (
62 <Link key={subItem.title} to={subItem.url} className={`flex items-center gap-3 px-3 py-1.5 rounded-lg transition-colors duration-200 text-xs ${isActive ? 'bg-blue-100 text-blue-600 hover:bg-blue-200 dark:bg-blue-500/10 dark:text-blue-400 dark:hover:bg-blue-500/20' : 'text-gray-600 dark:text-zinc-400 hover:text-gray-900 dark:hover:text-white hover:bg-gray-100 dark:hover:bg-zinc-800'}`} >
63 <subItem.icon className="size-3" />

Callers

nothing calls this directly

Calls 2

toggleProjectFunction · 0.85
getProjectSubItemsFunction · 0.85

Tested by

no test coverage detected