From 2085bdee38115ee1efa7bc9b130349c0d6c55517 Mon Sep 17 00:00:00 2001 From: Vahap Ogut Date: Tue, 23 Jun 2026 01:30:49 +0300 Subject: [PATCH] fix: filter stale closed roulette issues --- app/page.tsx | 2 +- components/IssueRoulette.tsx | 7 ++++--- lib/github.ts | 16 ++++++++-------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/app/page.tsx b/app/page.tsx index 9f82421..1aa2d00 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -5,7 +5,7 @@ import { fetchGithubIssues } from "@/lib/github" import { GitHubLogoIcon } from "@radix-ui/react-icons" import { Suspense } from "react" -export const revalidate = 3600 // Revalidate every hour +export const revalidate = 300 // Keep closed issues from lingering in the roulette export default async function Home() { const issues = await fetchGithubIssues(process.env.GITHUB_TOKEN || "") diff --git a/components/IssueRoulette.tsx b/components/IssueRoulette.tsx index 6ce1520..03426db 100644 --- a/components/IssueRoulette.tsx +++ b/components/IssueRoulette.tsx @@ -9,7 +9,7 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select" -import type { IssuesByFilter, Issue } from "@/lib/github" +import type { Issue, IssuesByFilter } from "@/lib/github" import { format } from "date-fns" import { AlertCircle, Calendar, Dices, ExternalLink, User } from "lucide-react" import { useState } from "react" @@ -32,8 +32,9 @@ export default function IssueRoulette({ try { // Filter available issues based on bounty preference and used status - const availableIssues = initialIssues[filterType] - .filter((issue) => !usedIssues.has(issue.id)) + const availableIssues = initialIssues[filterType].filter( + (issue) => !usedIssues.has(issue.id), + ) if (availableIssues.length === 0) { setUsedIssues(new Set()) diff --git a/lib/github.ts b/lib/github.ts index 58553c5..99c3f96 100644 --- a/lib/github.ts +++ b/lib/github.ts @@ -6,6 +6,7 @@ export interface Issue { body: string html_url: string created_at: string + state: "open" | "closed" user: { login: string avatar_url: string @@ -32,7 +33,7 @@ export async function fetchGithubIssues( org, }) - const reposNotArchived = repos.filter(repo => !repo.archived) + const reposNotArchived = repos.filter((repo) => !repo.archived) // Fetch issues from all repositories; tolerate per-repo fetch failures const allIssues = await Promise.allSettled( @@ -52,10 +53,7 @@ export async function fetchGithubIssues( }, })) } catch (error) { - console.error( - `Failed to fetch issues for ${org}/${repo.name}:`, - error, - ) + console.error(`Failed to fetch issues for ${org}/${repo.name}:`, error) return [] } }), @@ -67,6 +65,7 @@ export async function fetchGithubIssues( .filter( (issue) => !issue.pull_request && // Not a PR + issue.state === "open" && // Still open if cached/revalidated late !issue.assignees?.length, // Not assigned ) .map((issue) => { @@ -86,6 +85,7 @@ export async function fetchGithubIssues( body: issue.body || "", html_url: issue.html_url, created_at: issue.created_at, + state: issue.state as "open" | "closed", user: { login: issue.user?.login || "unknown", avatar_url: issue.user?.avatar_url || "", @@ -133,9 +133,9 @@ export async function fetchGithubIssues( } return { - "bounty": getBountiedIssues(), - "all": getWeightedIssues(), - "unbountied": processedIssues + bounty: getBountiedIssues(), + all: getWeightedIssues(), + unbountied: processedIssues .filter((issue) => (issue.bountyAmount ?? 0) === 0) .slice(0, 20), // Keep same limit as other filters }