From 32d8e765117dd19377260424087fe7bbc48cbb7e Mon Sep 17 00:00:00 2001 From: adityakukade32 Date: Mon, 17 Nov 2025 00:01:02 +0530 Subject: [PATCH 1/2] Fix the issue #173 to add the filter option --- .../dashboard/ProjectsContainer.tsx | 107 +++++++++++++++++- 1 file changed, 101 insertions(+), 6 deletions(-) diff --git a/apps/web/src/components/dashboard/ProjectsContainer.tsx b/apps/web/src/components/dashboard/ProjectsContainer.tsx index be004035..6fe04c38 100644 --- a/apps/web/src/components/dashboard/ProjectsContainer.tsx +++ b/apps/web/src/components/dashboard/ProjectsContainer.tsx @@ -15,7 +15,8 @@ import { DashboardProjectsProps } from "@/types"; import Image from "next/image"; import { useFilterStore } from "@/store/useFilterStore"; import { usePathname } from "next/navigation"; -import { MagnifyingGlassIcon } from "@heroicons/react/24/outline"; +import { MagnifyingGlassIcon, FunnelIcon } from "@heroicons/react/24/outline"; +import { useState, useMemo } from "react"; type ProjectsContainerProps = { projects: DashboardProjectsProps[] }; @@ -58,6 +59,33 @@ export default function ProjectsContainer({ const { projectTitle } = useProjectTitleStore(); const { setShowFilters } = useFilterStore(); const isProjectsPage = pathname === "/dashboard/projects"; + const [searchQuery, setSearchQuery] = useState(""); + + // Client-side filtering of projects based on search query + const filteredProjects = useMemo(() => { + if (!searchQuery.trim()) { + return projects; + } + + const query = searchQuery.toLowerCase().trim(); + return projects.filter((project) => { + const nameMatch = project.name.toLowerCase().includes(query); + const languageMatch = project.primaryLanguage?.toLowerCase().includes(query); + const stageMatch = project.stage?.toLowerCase().includes(query); + const popularityMatch = project.popularity?.toLowerCase().includes(query); + const competitionMatch = project.competition?.toLowerCase().includes(query); + const activityMatch = project.activity?.toLowerCase().includes(query); + + return ( + nameMatch || + languageMatch || + stageMatch || + popularityMatch || + competitionMatch || + activityMatch + ); + }); + }, [projects, searchQuery]); return (
@@ -67,14 +95,58 @@ export default function ProjectsContainer({ {isProjectsPage && ( )}
+ {/* Search Input for Quick Filtering */} + {isProjectsPage && projects && projects.length > 0 && ( +
+
+ + setSearchQuery(e.target.value)} + className="w-full pl-10 pr-4 py-2.5 bg-[#15161a] border border-[#1a1a1d] rounded-md text-white text-sm placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-ox-purple focus:border-transparent transition-all" + /> + {searchQuery && ( + + )} +
+ {searchQuery && ( +

+ Showing {filteredProjects.length} of {projects.length} projects +

+ )} +
+ )} + {projects && projects.length > 0 ? (
- ))} + )) + ) : ( + + +
+ +

No projects found

+

+ Try adjusting your search query or{" "} + +

+
+
+
+ )}
@@ -169,7 +264,7 @@ export default function ProjectsContainer({

Find Your Next Project

- Click the 'Find projects' button above to discover open + Click the 'Filter Projects' button above to discover open source projects that match your interests

From 3cf0cb2d1f1695b86e98b31158858cc6323ca279 Mon Sep 17 00:00:00 2001 From: adityakukade32 Date: Mon, 17 Nov 2025 00:14:04 +0530 Subject: [PATCH 2/2] make Changes according to the description --- .../dashboard/ProjectsContainer.tsx | 53 ++++++++++++++----- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/apps/web/src/components/dashboard/ProjectsContainer.tsx b/apps/web/src/components/dashboard/ProjectsContainer.tsx index 6fe04c38..26c90fbc 100644 --- a/apps/web/src/components/dashboard/ProjectsContainer.tsx +++ b/apps/web/src/components/dashboard/ProjectsContainer.tsx @@ -62,22 +62,42 @@ export default function ProjectsContainer({ const [searchQuery, setSearchQuery] = useState(""); // Client-side filtering of projects based on search query + // Memoized for performance optimization const filteredProjects = useMemo(() => { - if (!searchQuery.trim()) { - return projects; + // Return all projects if no search query or empty projects array + if (!searchQuery.trim() || !projects || projects.length === 0) { + return projects || []; } const query = searchQuery.toLowerCase().trim(); + + // Filter projects by checking all searchable fields return projects.filter((project) => { - const nameMatch = project.name.toLowerCase().includes(query); - const languageMatch = project.primaryLanguage?.toLowerCase().includes(query); - const stageMatch = project.stage?.toLowerCase().includes(query); - const popularityMatch = project.popularity?.toLowerCase().includes(query); - const competitionMatch = project.competition?.toLowerCase().includes(query); - const activityMatch = project.activity?.toLowerCase().includes(query); + // Search in project name + const nameMatch = project.name?.toLowerCase().includes(query) ?? false; + + // Search in description + const descriptionMatch = project.description?.toLowerCase().includes(query) ?? false; + + // Search in primary language + const languageMatch = project.primaryLanguage?.toLowerCase().includes(query) ?? false; + + // Search in stage + const stageMatch = project.stage?.toLowerCase().includes(query) ?? false; + + // Search in popularity + const popularityMatch = project.popularity?.toLowerCase().includes(query) ?? false; + + // Search in competition level + const competitionMatch = project.competition?.toLowerCase().includes(query) ?? false; + + // Search in activity level + const activityMatch = project.activity?.toLowerCase().includes(query) ?? false; + // Return true if any field matches the query return ( nameMatch || + descriptionMatch || languageMatch || stageMatch || popularityMatch || @@ -112,15 +132,17 @@ export default function ProjectsContainer({ setSearchQuery(e.target.value)} className="w-full pl-10 pr-4 py-2.5 bg-[#15161a] border border-[#1a1a1d] rounded-md text-white text-sm placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-ox-purple focus:border-transparent transition-all" + aria-label="Search projects" /> {searchQuery && (