diff --git a/src/Routes/Router.tsx b/src/Routes/Router.tsx index 40a7861..c08dee8 100644 --- a/src/Routes/Router.tsx +++ b/src/Routes/Router.tsx @@ -7,6 +7,7 @@ import Signup from "../pages/Signup/Signup.tsx"; import Login from "../pages/Login/Login.tsx"; import ContributorProfile from "../pages/ContributorProfile/ContributorProfile.tsx"; import Home from "../pages/Home/Home.tsx"; +import Issues from "../pages/Issues/Issues.tsx"; const Router = () => { return ( @@ -19,6 +20,7 @@ const Router = () => { } /> } /> } /> + } /> ); }; diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index c6cc86d..c876cb2 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -40,6 +40,12 @@ const Navbar: React.FC = () => { > Tracker + + Issues + { > Contributors + setIsOpen(false)} + > + Issues + { + const theme = useTheme(); + + const [issues, setIssues] = useState([]); + const [totalIssues, setTotalIssues] = useState(0); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(""); + const [page, setPage] = useState(0); + + const [language, setLanguage] = useState(""); + const [tag, setTag] = useState(""); + const [sortOrder, setSortOrder] = useState("desc"); + + const fetchIssues = useCallback(async (currentPage: number, currentLanguage: string, currentTag: string, currentOrder: string) => { + setLoading(true); + setError(""); + + try { + let q = "is:issue is:open"; + if (currentLanguage) { + q += ` language:${currentLanguage}`; + } + if (currentTag) { + q += ` label:"${currentTag}"`; + } + + const response = await fetch( + `https://api.github.com/search/issues?q=${encodeURIComponent(q)}&sort=created&order=${currentOrder}&per_page=${ROWS_PER_PAGE}&page=${currentPage + 1}` + ); + + if (!response.ok) { + if (response.status === 403) { + throw new Error("GitHub API rate limit exceeded."); + } + throw new Error("Failed to fetch data"); + } + + const data = await response.json(); + setIssues(data.items); + setTotalIssues(data.total_count > 1000 ? 1000 : data.total_count); // GitHub limits search results to 1000 + } catch (err: unknown) { + if (err instanceof Error) { + setError(err.message || "Failed to fetch issues"); + } else { + setError("Failed to fetch issues"); + } + } finally { + setLoading(false); + } + }, []); + + useEffect(() => { + fetchIssues(page, language, tag, sortOrder); + }, [page, language, tag, sortOrder, fetchIssues]); + + const handlePageChange = (_: unknown, newPage: number) => { + setPage(newPage); + }; + + const formatDate = (dateString: string): string => + new Date(dateString).toLocaleDateString(); + + return ( + + + Explore GitHub Issues + + + + + + Language + + + + + Tags / Labels + + + + + Sort by Time + + + + + + {error && ( + + {error} + + )} + + {loading ? ( + + + + ) : ( + + + + + + Title + Repository + State + Created + + + + {issues.map((item) => ( + + + {item.state === "closed" ? ( + + ) : ( + + )} + + {item.title} + + + + {item.repository_url.split("/").slice(-2).join("/")} + + {item.state} + {formatDate(item.created_at)} + + ))} + {issues.length === 0 && !loading && !error && ( + + + No issues found. + + + )} + +
+ +
+
+ )} +
+ ); +}; + +export default Issues;