From 1e248ffe1be2ccb13d1f4c87afe3fa3b74d32e04 Mon Sep 17 00:00:00 2001 From: denshaw-09 Date: Tue, 29 Jul 2025 18:36:47 +0530 Subject: [PATCH 1/4] Improved the feature of Contributor's page --- backend/.env.sample | 6 +- src/pages/Contributors/Contributors.tsx | 446 ++++++++++++++++++------ 2 files changed, 340 insertions(+), 112 deletions(-) diff --git a/backend/.env.sample b/backend/.env.sample index 98f9688..3fee936 100644 --- a/backend/.env.sample +++ b/backend/.env.sample @@ -1,3 +1,3 @@ -PORT=5000 -MONGO_URI=mongodb://localhost:27017/githubTracker -SESSION_SECRET=your-secret-key +MONGO_URI=mongodb://127.0.0.1:27017/github_tracker +SESSION_SECRET=c356d915b0161d2f7fcab51b4e179988fcfee503e3b7be3fef9347862eec9eedd88c6670129f81214b9351d33ad51f8d6cfc2d3d146375f6b66ad059e6e05d10 +PORT=5000 \ No newline at end of file diff --git a/src/pages/Contributors/Contributors.tsx b/src/pages/Contributors/Contributors.tsx index 6ad7d5a..5861172 100644 --- a/src/pages/Contributors/Contributors.tsx +++ b/src/pages/Contributors/Contributors.tsx @@ -1,143 +1,371 @@ -import { useEffect, useState } from "react"; +import React, { useEffect, useState } from "react"; import { Container, - Grid, + Box, + Typography, Card, CardContent, + Grid, Avatar, - Typography, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + Paper, + LinearProgress, Button, - Box, + Select, + MenuItem, + IconButton, + Tooltip, CircularProgress, - Alert, + Checkbox, + Pagination, } from "@mui/material"; import { FaGithub } from "react-icons/fa"; -import { Link } from "react-router-dom"; import axios from "axios"; -import { GITHUB_REPO_CONTRIBUTORS_URL } from "../../utils/constants"; -interface Contributor { - id: number; - login: string; - avatar_url: string; - contributions: number; - html_url: string; -} +const REPO_OWNER = "mehul-m-prajapati"; +const REPO_NAME = "github_tracker"; +const REPO_FULL = `${REPO_OWNER}/${REPO_NAME}`; + +const PERIOD_OPTIONS = ["7d", "14d", "30d", "90d"]; const ContributorsPage = () => { - const [contributors, setContributors] = useState([]); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); + // Summary stats + const [repoStats, setRepoStats] = useState(null); + const [prStats, setPrStats] = useState({ opened: 0, merged: 0, velocity: "-" }); + const [issueStats, setIssueStats] = useState({ opened: 0, closed: 0, velocity: "-" }); + const [contributors, setContributors] = useState([]); + const [loading, setLoading] = useState(true); + const [period, setPeriod] = useState("30d"); + const [page, setPage] = useState(1); + const [perPage] = useState(5); - // Fetch contributors from GitHub API + // Fetch repo stats, PRs, issues, contributors useEffect(() => { - const fetchContributors = async () => { + const fetchData = async () => { + setLoading(true); try { - const response = await axios.get(GITHUB_REPO_CONTRIBUTORS_URL, { - withCredentials: false, - }); - setContributors(response.data); + // Repo stats (stars, forks, open issues) + const repoRes = await axios.get(`https://api.github.com/repos/${REPO_FULL}`); + setRepoStats(repoRes.data); + + // Contributors + const contribRes = await axios.get(`https://api.github.com/repos/${REPO_FULL}/contributors?per_page=100`); + setContributors(contribRes.data); + + // PRs (all states) + const prRes = await axios.get(`https://api.github.com/repos/${REPO_FULL}/pulls?state=all&per_page=100`); + const prs = prRes.data; + const opened = prs.length; + const merged = prs.filter(pr => pr.merged_at).length; + // Calculate PR velocity (mock: 1d if any, else '-') + const velocity = opened > 0 ? "1d" : "-"; + setPrStats({ opened, merged, velocity }); + + // Issues (all states, filter out PRs) + const issueRes = await axios.get(`https://api.github.com/repos/${REPO_FULL}/issues?state=all&per_page=100`); + const issues = issueRes.data.filter(issue => !issue.pull_request); + const openedIssues = issues.length; + const closedIssues = issues.filter(issue => issue.state === "closed").length; + // Calculate Issue velocity (mock: 5d if any, else '-') + const issueVelocity = openedIssues > 0 ? "5d" : "-"; + setIssueStats({ opened: openedIssues, closed: closedIssues, velocity: issueVelocity }); } catch (err) { - setError("Failed to fetch contributors. Please try again later."); + setRepoStats(null); + setContributors([]); + setPrStats({ opened: 0, merged: 0, velocity: "-" }); + setIssueStats({ opened: 0, closed: 0, velocity: "-" }); } finally { setLoading(false); } }; + fetchData(); + }, [period]); - fetchContributors(); - }, []); + // Pagination logic + const paginatedContributors = contributors.slice((page - 1) * perPage, page * perPage); + const totalPages = Math.ceil(contributors.length / perPage); - if (loading) { - return ( - - - - ); - } + // Helper for activity (mock: based on contributions) + const getActivity = (contrib) => { + if (contrib.contributions > 50) return { + label: "High", + color: "#22c55e", + bg: "linear-gradient(90deg, #bbf7d0 0%, #d1fae5 100%)", + icon: ( + + ) + }; + if (contrib.contributions > 10) return { + label: "Medium", + color: "#eab308", + bg: "linear-gradient(90deg, #fde68a 0%, #fef9c3 100%)", + icon: "— " + }; + return { + label: "Low", + color: "#ef4444", + bg: "linear-gradient(90deg, #fecaca 0%, #fee2e2 100%)", + icon: ( + + ) + }; + }; - if (error) { - return ( - - {error} - - ); - } + // Helper for PR overview (mock: random %) + const getPROverview = (contrib) => { + const prs = contrib.contributions; + // For demo, percent is capped at 100 + const percent = Math.min(100, Math.round((prs / 132) * 100)); // 132 is max in demo + return { prs, percent }; + }; - return ( -
- - - 🤝 Contributors - + // Helper for PR velocity (mock: random) + const getPRVelocity = () => ({ velocity: "1d", percent: 55 }); - - {contributors.map((contributor) => ( - - - - + // Helper for contributors avatars (mock: show avatar) + const getContributorsAvatars = (contrib) => [contrib.avatar_url]; - - - {contributor.login} - - - - {contributor.contributions} Contributions - - {/* - - Thank you for your valuable contributions to our - community! - */} + // Helper for last 30 days (mock: SVG line) + const ActivityGraph = () => ( + + + + ); - - + return ( + + {/* Header */} + + + + Github-Tracker Workspace + + + {/* */} + + + + + {/* Summary Cards */} + + {/* PRs */} + + + + + {/* PR Icon in box */} + + + + Pull Requests + + + + Opened + {prStats.opened} + + + Merged + {prStats.merged} + + + Velocity + {prStats.velocity} + + + + + + {/* Issues */} + + + + + {/* Issue Icon in box */} + + + + Issues + + + + Opened + {issueStats.opened} + + + Closed + {issueStats.closed} + + + Velocity + {issueStats.velocity} + + + + + + {/* Engagement */} + + + + + {/* Heart Icon in box */} + + + + Engagement + + + + Stars + {repoStats ? repoStats.stargazers_count : 0} + + + Forks + {repoStats ? repoStats.forks_count : 0} + + + Activity Ratio + {/* Activity Ratio pill */} + + + Low - - - - - ))} + + + + + + {/* Repositories Table */} + + + + + + + REPOSITORY + ACTIVITY + PR OVERVIEW + PR VELOCITY + SPAM + CONTRIBUTORS + LAST 30 DAYS + + + + {loading ? ( + + + + + + ) : ( + paginatedContributors.map((contrib, idx) => { + const activity = getActivity(contrib); + const prOverview = getPROverview(contrib); + const prVelocity = getPRVelocity(); + const avatars = getContributorsAvatars(contrib); + return ( + + + + + + + + + {contrib.login} + @{REPO_OWNER} + + + + + {/* Activity pill */} + + {activity.icon} + {activity.label} + + + + + {prOverview.prs} PRs + + {/* Green base bar */} + + {/* Purple overlay bar */} + + + {prOverview.percent}% + + + + + + {prVelocity.velocity} + {prVelocity.percent}% + + + + - + + + + {avatars.map((url, i) => ( + + ))} + + + + + + + ); + }) + )} + +
+
+ + + Showing {paginatedContributors.length > 0 ? (page - 1) * perPage + 1 : 0} - {Math.min(page * perPage, contributors.length)} of {contributors.length} repos + + setPage(value)} + color="primary" + shape="rounded" + /> + +
-
+ ); }; From d8ba0d95b91ee6e8df3b953efe070c6c6980c713 Mon Sep 17 00:00:00 2001 From: denshaw Date: Tue, 29 Jul 2025 18:53:49 +0530 Subject: [PATCH 2/4] Update .env.sample --- backend/.env.sample | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/.env.sample b/backend/.env.sample index 3fee936..d5109dc 100644 --- a/backend/.env.sample +++ b/backend/.env.sample @@ -1,3 +1,3 @@ MONGO_URI=mongodb://127.0.0.1:27017/github_tracker -SESSION_SECRET=c356d915b0161d2f7fcab51b4e179988fcfee503e3b7be3fef9347862eec9eedd88c6670129f81214b9351d33ad51f8d6cfc2d3d146375f6b66ad059e6e05d10 -PORT=5000 \ No newline at end of file +SESSION_SECRET=your_secret_key +PORT=5000 From 01ff3911e77fbd1e01adf17a6bca647265ec2814 Mon Sep 17 00:00:00 2001 From: denshaw Date: Tue, 29 Jul 2025 19:02:41 +0530 Subject: [PATCH 3/4] Update src/pages/Contributors/Contributors.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- src/pages/Contributors/Contributors.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Contributors/Contributors.tsx b/src/pages/Contributors/Contributors.tsx index 5861172..b58b310 100644 --- a/src/pages/Contributors/Contributors.tsx +++ b/src/pages/Contributors/Contributors.tsx @@ -296,7 +296,7 @@ const ContributorsPage = () => { - + {contrib.login} @{REPO_OWNER} From 0c0d8450e32509daef60d98ae4956a2fd5c81cc1 Mon Sep 17 00:00:00 2001 From: denshaw Date: Tue, 29 Jul 2025 20:00:09 +0530 Subject: [PATCH 4/4] Delete backend/.env.sample --- backend/.env.sample | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 backend/.env.sample diff --git a/backend/.env.sample b/backend/.env.sample deleted file mode 100644 index d5109dc..0000000 --- a/backend/.env.sample +++ /dev/null @@ -1,3 +0,0 @@ -MONGO_URI=mongodb://127.0.0.1:27017/github_tracker -SESSION_SECRET=your_secret_key -PORT=5000