diff --git a/src/pages/Contributors/Contributors.tsx b/src/pages/Contributors/Contributors.tsx index 29fcbaf..d236076 100644 --- a/src/pages/Contributors/Contributors.tsx +++ b/src/pages/Contributors/Contributors.tsx @@ -1,19 +1,12 @@ import { useEffect, useState } from "react"; -import { - Container, - Grid, - Card, - CardContent, - Avatar, - Typography, - Button, - Box, - CircularProgress, - Alert, -} from "@mui/material"; -import { FaGithub, FaCopy, FaCheck } from "react-icons/fa"; -import { Link } from "react-router-dom"; import axios from "axios"; +import { + Sparkles, + Github, + Users, + GitPullRequest, + ArrowRight, +} from "lucide-react"; import { GITHUB_REPO_CONTRIBUTORS_URL } from "../../utils/constants"; import BackToTopButton from "../../components/Backtotop"; @@ -25,40 +18,23 @@ interface Contributor { html_url: string; } -interface FetchError { - message: string; - isRateLimited: boolean; - statusCode?: number; -} - -// Custom error class for Contributors fetch errors -class ContributorsError extends Error { - constructor( - message: string, - public isRateLimited = false, - public statusCode?: number - ) { - super(message); - this.name = "ContributorsError"; - } -} - -// Type guard to validate if data is Contributor[] -const isContributorArray = (data: unknown): data is Contributor[] => { - if (!Array.isArray(data)) return false; - return data.every((item) => { - if (typeof item !== "object" || item === null) return false; - - // Validate all required fields with correct types - return ( - typeof item.id === "number" && - typeof item.login === "string" && - typeof item.avatar_url === "string" && - typeof item.contributions === "number" && - typeof item.html_url === "string" - ); - }); -}; +const stats = [ + { + title: "Contributors", + value: "30+", + icon: Users, + }, + { + title: "Pull Requests", + value: "250+", + icon: GitPullRequest, + }, + { + title: "Open Source", + value: "Community Driven", + icon: Github, + }, +]; const ContributorsPage = () => { const [contributors, setContributors] = useState([]); @@ -69,68 +45,16 @@ const handleCopy = async (contributor: Contributor) => { await navigator.clipboard.writeText(contributor.html_url); setCopiedId(contributor.id); - setTimeout(() => { - setCopiedId(null); - }, 2000); -}; - // Fetch contributors from GitHub API useEffect(() => { const fetchContributors = async () => { try { - setLoading(true); - setError(null); - - const response = await axios.get(GITHUB_REPO_CONTRIBUTORS_URL, { - withCredentials: false, - timeout: 10000, - }); - - // ✅ Validate response structure matches Contributor[] - if (!isContributorArray(response.data)) { - throw new ContributorsError( - "Invalid API response structure. Expected array of contributors.", - false - ); - } + const response = await axios.get( + GITHUB_REPO_CONTRIBUTORS_URL + ); setContributors(response.data); - } catch (err) { - const fetchError: FetchError = { - message: "Failed to fetch contributors. Please try again later.", - isRateLimited: false, - }; - - // Handle ContributorsError instances - if (err instanceof ContributorsError) { - fetchError.message = err.message; - fetchError.isRateLimited = err.isRateLimited; - fetchError.statusCode = err.statusCode; - } else if (axios.isAxiosError(err)) { - // Handle Axios errors - if (err.response?.status === 403) { - fetchError.message = - "GitHub API rate limit exceeded. Try again later."; - fetchError.isRateLimited = true; - fetchError.statusCode = 403; - } else if (err.response?.status === 404) { - fetchError.message = "Repository not found."; - fetchError.statusCode = 404; - } else if (err.code === "ECONNABORTED") { - fetchError.message = "Request timeout. Server took too long to respond."; - fetchError.statusCode = 408; - } else if (err.response?.status) { - fetchError.message = `HTTP ${err.response.status}: Failed to fetch contributors`; - fetchError.statusCode = err.response.status; - } else if (err.message) { - fetchError.message = err.message; - } - } else if (err instanceof Error) { - fetchError.message = err.message || fetchError.message; - } - - setError(fetchError); - console.error("Contributors fetch error:", fetchError); - setContributors([]); + } catch { + setError("Failed to fetch contributors."); } finally { setLoading(false); } @@ -141,131 +65,241 @@ const handleCopy = async (contributor: Contributor) => { if (loading) { return ( - - - +
+
+
+

+ Loading Contributors... +

+
+
); } if (error) { return ( - - - - ⚠️ {error.message} - - {error.isRateLimited && ( - - You've hit GitHub's API rate limit. The limit resets in 1 hour. - - )} - {error.statusCode === 404 && ( - - Please verify the repository exists and is accessible. - - )} - {error.statusCode === 408 && ( - - The server took too long to respond. Please try again. - - )} - - +
+
+ {error} +
+
); } return ( -
- - - 🤝 Contributors - - - - {contributors.map((contributor) => ( - - - - + + {/* BACKGROUND GLOWS */} +
+
+ + {/* GRID OVERLAY */} +
+ +
+ + {/* HERO SECTION */} +
+ +
+ + Open Source Community +
+ +

+ Meet Our{" "} + + Amazing Contributors + +

+ +

+ These amazing developers are helping build and improve GitHub Tracker through open-source collaboration and innovation. +

+
+ + {/* STATS */} +
+ + {stats.map((stat) => { + const Icon = stat.icon; + + return ( +
+
+ +
+ +

+ {stat.title === "Contributors" + ? `${contributors.length}+` + : stat.value} +

+ +

+ {stat.title} +

+
+ ); + })} +
+ + {/* CONTRIBUTORS SECTION */} +
+ +
+

+ Community Contributors +

+ +

+ The incredible developers helping GitHub Tracker grow through collaboration, innovation, and open-source contributions. +

+
+ +
+ + {contributors.map((contributor) => ( + + + {/* GLOW */} +
+ + {/* CTA SECTION */} +
+ +
+ +
+ +
+ +
+ + Join the Community +
+ +

+ Want to Contribute? +

+ +

+ Help improve GitHub Tracker, contribute new features, fix bugs, and become part of our growing open-source community. +

+ + + Start Contributing + + + +
+
+
+ +
); }; -export default ContributorsPage; +export default ContributorsPage; \ No newline at end of file