This is a submission for the GitHub Finish-Up-A-Thon Challenge
What I Built
Bounty Tracker is a web app that helps open source developers discover, track, and manage GitHub bounties and pull requests in one dashboard.
The project started from a real problem. I was hunting bounties across multiple repos, losing track of which issues I was working on, which PRs were pending review, and how much money I was actually owed. I needed a single place to see everything.
I built the first version as a quick Express server with in-memory storage and a basic HTML dashboard. It worked, technically. You could add bounties and PRs. But the data disappeared every time the server restarted. There was no way to discover new bounties. The UI was barebones. I pushed the code and walked away.
The GitHub Finish-Up-A-Thon Challenge gave me the push to revive and actually finish it.
Tech stack: Next.js 14, React 18, TypeScript, Tailwind CSS. Deployed on Vercel as a static app. No server, no database.
Demo
Live: https://bounty-tracker-nu.vercel.app
Source: https://github.com/iyop666/bounty-tracker
The app has four tabs:
- Dashboard shows six stat cards (total bounties, active count, total value, won value, total PRs, merged PRs) and two panels with your five most recent bounties and PRs.
- Bounties tab lets you add, edit, and manage tracked bounties. Status lifecycle: open, working, submitted, won, expired. Inline editing for status and amount.
- PRs tab tracks pull requests with status options (pending, review, merged, closed) and links each PR to a specific bounty.
- Discover tab searches GitHub for bounty-labeled issues via the GitHub Search API. One click to import any result into your tracked bounties.
Everything persists in localStorage. No sign-up, no server. Your data stays in your browser.
The Comeback Story
Before:
The original project was a single Express file with 50 lines of JavaScript. In-memory arrays for storage. A basic HTML dashboard with inline CSS. You could add items and see them listed. Data was gone on every server restart. That was it.
let bounties = [];
let prs = [];
app.get("/api/bounties", (req, res) => {
res.json(bounties);
});
What I changed, fixed, and added:
Full TypeScript rewrite. Replaced the single JS file with a structured Next.js app: layout.tsx for the shell, page.tsx for the four-tab interface, types.ts for data models, storage.ts for localStorage CRUD. The Bounty type uses a union (
"open" | "working" | "submitted" | "won" | "expired") so you cannot set an invalid status.localStorage persistence. The original used in-memory arrays, the worst of both worlds: no persistence, requires a server. I chose localStorage over a database because this is a personal tracking tool, not a multi-user SaaS. Zero cost, works offline, data stays in the browser.
GitHub API discovery. The Discover tab hits
https://api.github.com/search/issues?q=label:bountyand parses the results. Each issue shows title, repo, author, creation date, and labels. Therepository_urlfield gets stripped to extractowner/repopath. One click imports an issue into your bounty list with auto-detected labels.Status management system. 5 bounty states (open, working, submitted, won, expired) and 4 PR states (pending, review, merged, closed). Each state has a distinct color badge matching GitHub's design language: blue for open, yellow for working, purple for submitted, green for won/merged, gray for expired, red for closed.
PR-to-bounty linking. When adding a PR, you can select which bounty it belongs to. The linked bounty name shows next to the PR in the list. This creates a visual connection between the work you are doing (PR) and the money you are chasing (bounty).
Dark theme UI. Built with Tailwind CSS matching GitHub's color palette (#0d1117 background, #161b22 cards, #58a6ff accent). Responsive design works on mobile. Fade-in animations on tab switches.
After:
Over 500 lines of TypeScript across 6 files. 4 major components (Dashboard, Bounties, PRs, Discover). GitHub API integration with search and import. localStorage persistence layer with pure CRUD functions. Status badge system with 9 color mappings. Deployed and live at bounty-tracker-nu.vercel.app.
My Experience with GitHub Copilot
I used GitHub Copilot Free during this rebuild, specifically the Copilot CLI in my terminal.
Scaffolding. Setting up Next.js 14 with TypeScript and Tailwind involves boilerplate: tsconfig.json, postcss.config, tailwind.config, layout files. Copilot suggested the right patterns and filled in the repetitive parts. I did not have to look up "how to configure tailwind v3 with next 14" for the fifth time.
GitHub API patterns. The search endpoint has specific query syntax. You need
label:bountyin the query string, the right Accept header, and you need to parserepository_urlto get the repo path. I typedfetch("https://api.github.com/search/issues?q=and Copilot completed the rest of the URL with the correct parameters. That saved me 20 minutes of reading API docs.Color mapping. I started typing
const STATUS_COLORSand Copilot filled in the entire object with GitHub-style hex values. It knew open should be #58a6ff (blue), merged should be #3fb950 (green), and closed should be #f85149 (red). Small thing, but it kept me in flow.
Where Copilot struggled was the business logic. The bounty status system has five states with implicit transitions. Copilot's suggestions were generic state management patterns that did not match what I needed. I had to write the status update logic and the PR-to-bounty linking myself. For domain-specific logic, Copilot needs guidance. For boilerplate and API patterns, it is genuinely useful.
Top comments (0)