From cbd86757aac70889e1103f60df6df8b0c11b2e43 Mon Sep 17 00:00:00 2001 From: Ayush R Kumar Date: Mon, 1 Jun 2026 19:27:06 +0530 Subject: [PATCH 1/4] feat: add search and sort filter for contributors --- src/pages/Contributors/Contributors.tsx | 153 ++++++++++++++---------- 1 file changed, 91 insertions(+), 62 deletions(-) diff --git a/src/pages/Contributors/Contributors.tsx b/src/pages/Contributors/Contributors.tsx index d4fee52c..fcd9562e 100644 --- a/src/pages/Contributors/Contributors.tsx +++ b/src/pages/Contributors/Contributors.tsx @@ -10,6 +10,11 @@ import { Box, CircularProgress, Alert, + TextField, + MenuItem, + Select, + FormControl, + InputLabel, } from "@mui/material"; import { FaGithub } from "react-icons/fa"; import { Link } from "react-router-dom"; @@ -28,8 +33,9 @@ const ContributorsPage = () => { const [contributors, setContributors] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); + const [search, setSearch] = useState(""); + const [sortOrder, setSortOrder] = useState("desc"); - // Fetch contributors from GitHub API useEffect(() => { const fetchContributors = async () => { try { @@ -43,10 +49,17 @@ const ContributorsPage = () => { setLoading(false); } }; - fetchContributors(); }, []); + const filtered = contributors + .filter((c) => c.login.toLowerCase().includes(search.toLowerCase())) + .sort((a, b) => + sortOrder === "desc" + ? b.contributions - a.contributions + : a.contributions - b.contributions + ); + if (loading) { return ( @@ -70,69 +83,85 @@ const ContributorsPage = () => { 🤝 Contributors + + setSearch(e.target.value)} + sx={{ flex: 1, minWidth: 200 }} + /> + + Sort by Contributions + + + + + + Showing {filtered.length} of {contributors.length} contributors + + - {contributors.map((contributor) => ( + {filtered.map((contributor) => ( - + - - - - - {contributor.login} - - - - {contributor.contributions} Contributions - - {/* - - Thank you for your valuable contributions to our - community! - */} - - - - - - - + + + + {contributor.login} + + + {contributor.contributions} Contributions + + + + + + + ))} From 54296e549fd74cf3b21b89b2ed3c49474b0b11d1 Mon Sep 17 00:00:00 2001 From: Ayush R Kumar Date: Mon, 1 Jun 2026 19:47:06 +0530 Subject: [PATCH 2/4] perf: memoize filtered contributors list with useMemo --- src/pages/Contributors/Contributors.tsx | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/pages/Contributors/Contributors.tsx b/src/pages/Contributors/Contributors.tsx index fcd9562e..ed6538eb 100644 --- a/src/pages/Contributors/Contributors.tsx +++ b/src/pages/Contributors/Contributors.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useEffect, useState, useMemo } from "react"; import { Container, Grid, @@ -52,13 +52,17 @@ const ContributorsPage = () => { fetchContributors(); }, []); - const filtered = contributors - .filter((c) => c.login.toLowerCase().includes(search.toLowerCase())) - .sort((a, b) => - sortOrder === "desc" - ? b.contributions - a.contributions - : a.contributions - b.contributions - ); + const filtered = useMemo( + () => + contributors + .filter((c) => c.login.toLowerCase().includes(search.toLowerCase())) + .sort((a, b) => + sortOrder === "desc" + ? b.contributions - a.contributions + : a.contributions - b.contributions + ), + [contributors, search, sortOrder] + ); if (loading) { return ( From e4adcecc95cc386b66c60efca72b4d4f640a73f9 Mon Sep 17 00:00:00 2001 From: Ayush R Kumar Date: Mon, 1 Jun 2026 19:49:24 +0530 Subject: [PATCH 3/4] feat: complete remaining filters and clear button requirements --- src/pages/Contributors/Contributors.tsx | 72 ++++++++++++++++++++----- 1 file changed, 58 insertions(+), 14 deletions(-) diff --git a/src/pages/Contributors/Contributors.tsx b/src/pages/Contributors/Contributors.tsx index ed6538eb..bf62ddb0 100644 --- a/src/pages/Contributors/Contributors.tsx +++ b/src/pages/Contributors/Contributors.tsx @@ -27,6 +27,7 @@ interface Contributor { avatar_url: string; contributions: number; html_url: string; + type?: string; } const ContributorsPage = () => { @@ -35,6 +36,8 @@ const ContributorsPage = () => { const [error, setError] = useState(null); const [search, setSearch] = useState(""); const [sortOrder, setSortOrder] = useState("desc"); + const [minPRs, setMinPRs] = useState(""); + const [prType, setPrType] = useState("all"); useEffect(() => { const fetchContributors = async () => { @@ -46,23 +49,34 @@ const ContributorsPage = () => { } catch { setError("Failed to fetch contributors. Please try again later."); } finally { - setLoading(false); + loading && setLoading(false); } }; fetchContributors(); }, []); - const filtered = useMemo( - () => - contributors - .filter((c) => c.login.toLowerCase().includes(search.toLowerCase())) - .sort((a, b) => - sortOrder === "desc" - ? b.contributions - a.contributions - : a.contributions - b.contributions - ), - [contributors, search, sortOrder] - ); + const handleClearFilters = () => { + setSearch(""); + setSortOrder("desc"); + setMinPRs(""); + setPrType("all"); + }; + + const filtered = useMemo(() => { + return contributors + .filter((c) => { + const matchesSearch = c.login.toLowerCase().includes(search.toLowerCase()); + const matchesMinPR = minPRs === "" || c.contributions >= parseInt(minPRs, 10); + const matchesType = prType === "all" || (c.type && c.type.toLowerCase() === prType.toLowerCase()); + return matchesSearch && matchesMinPR && matchesType; + }) + .sort((a, b) => { + if (sortOrder === "desc") { + return b.contributions - a.contributions; + } + return a.contributions - b.contributions; + }); + }, [contributors, search, sortOrder, minPRs, prType]); if (loading) { return ( @@ -87,7 +101,7 @@ const ContributorsPage = () => { 🤝 Contributors - + { onChange={(e) => setSearch(e.target.value)} sx={{ flex: 1, minWidth: 200 }} /> + setMinPRs(e.target.value)} + sx={{ width: 130 }} + /> + + PR Type + + Sort by Contributions + @@ -159,7 +203,7 @@ const ContributorsPage = () => { backgroundColor: "#333333", textTransform: "none", color: "#FFFFFF", - "&:hover": { backgroundColor: "#555555" }, + &:hover: { backgroundColor: "#555555" }, }} > GitHub From 8c5724ae0d82332293b8b903125c598da2546ba4 Mon Sep 17 00:00:00 2001 From: Ayush R Kumar Date: Mon, 1 Jun 2026 19:51:04 +0530 Subject: [PATCH 4/4] fix: resolve syntax build error on card hover state --- src/pages/Contributors/Contributors.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/Contributors/Contributors.tsx b/src/pages/Contributors/Contributors.tsx index bf62ddb0..a801e9a1 100644 --- a/src/pages/Contributors/Contributors.tsx +++ b/src/pages/Contributors/Contributors.tsx @@ -49,7 +49,7 @@ const ContributorsPage = () => { } catch { setError("Failed to fetch contributors. Please try again later."); } finally { - loading && setLoading(false); + setLoading(false); } }; fetchContributors(); @@ -203,7 +203,7 @@ const ContributorsPage = () => { backgroundColor: "#333333", textTransform: "none", color: "#FFFFFF", - &:hover: { backgroundColor: "#555555" }, + "&:hover": { backgroundColor: "#555555" }, }} > GitHub