feat-Implement Bounty Status Logic & Anti-Squatting#55
Conversation
📝 WalkthroughWalkthroughAdds claim/activity fields and converts several date fields to strings; introduces BountyLogic (auto-release/inactivity logic and UI status helpers); wires BountyLogic.processBountyStatus into API and page flows; updates mock data and date-based sorting to handle ISO string timestamps. Changes
Sequence DiagramsequenceDiagram
participant Client
participant API
participant DataModel
participant BountyLogic
participant Page
participant UI
Client->>API: GET /api/bounties or GET /bounty/:id
API->>DataModel: fetch raw bounty(ies) (ISO timestamps, claim fields)
DataModel-->>API: return raw data
API->>BountyLogic: processBountyStatus(all bounties)
BountyLogic-->>API: return processed bounty(ies)
API-->>Client: respond with processed data
Client->>Page: navigate to list or detail
Page->>API: request processed bounty(ies)
Page->>BountyLogic: (optional) process single bounty before render
BountyLogic-->>Page: status metadata (label, color, details)
Page->>UI: render list or detail with updated claim state
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@lib/logic/bounty-logic.ts`:
- Around line 1-2: Remove the unused named imports BountyStatus, ClaimingModel
and addDays from the top import list (keep only Bounty and the used date-fns
helpers), and replace the variable currently typed as any in this module with
the correct specific type from your domain (e.g., Bounty, Date, string, or a
typed interface) so the file no longer uses any; update any code that relies on
that variable to match the chosen type and import any additional types if
needed.
In `@lib/types.ts`:
- Around line 48-55: The date fields in this interface (claimedAt, claimedBy,
lastActivityAt, claimExpiresAt, submissionsEndDate and also createdAt/updatedAt
if present) are typed as Date here but are strings in the Bounty interface in
types/bounty.ts and in lib/api/bounties.ts; change these fields in this file to
use string (or a unified alias like ISODateString) to match the API/Zod schema,
update any related type aliases or imports accordingly, and run a quick grep/TS
compile to find and fix any callsites that assume Date methods so they instead
parse to Date only where needed.
🧹 Nitpick comments (2)
lib/logic/bounty-logic.ts (1)
9-9:CLAIM_DURATION_DAYSconstant is defined but never used.Consider removing it if it's not needed, or documenting its intended use if it's planned for future implementation.
app/bounty/[id]/page.tsx (1)
15-27: Consider processing status ingenerateMetadatafor consistency.The
generateMetadatafunction uses the raw bounty without callingprocessBountyStatus. While the current metadata fields (issueTitle,projectName,description) aren't affected by status changes, applying consistent processing would ensure future metadata additions don't inadvertently use stale status data.♻️ Proposed consistency fix
export async function generateMetadata({ params }: BountyPageProps): Promise<Metadata> { const { id } = await params - const bounty = getBountyById(id) + let bounty = getBountyById(id) + + if (bounty) { + bounty = BountyLogic.processBountyStatus(bounty) + } if (!bounty) { return { title: "Bounty Not Found" } }
…roject data, updating types, mock data, and sorting logic.
…te parsing in bounty logic.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@lib/logic/bounty-logic.ts`:
- Line 9: Remove the unused static constant CLAIM_DURATION_DAYS from the
BountyLogic class (or implement its intended use): either delete the declaration
"static readonly CLAIM_DURATION_DAYS = 14;" in bounty-logic.ts, or wire it into
the claim flow by computing and storing claimExpiresAt when a bounty is claimed
(use CLAIM_DURATION_DAYS to add days to the claim timestamp), updating methods
like the claim handler (e.g., createClaim / handleClaim or any method that
processes claims) and the bounty data model field claimExpiresAt so the value is
persisted and later checked for expiration.
🧹 Nitpick comments (4)
lib/logic/bounty-logic.ts (4)
2-2: Remove stale comment.The comment is outdated —
ClaimingModelis actively used in the type constraints on lines 19 and 75.-import { ClaimingModel } from '@/types/bounty'; // Keep if needed for value checking, or remove if just string +import { ClaimingModel } from '@/types/bounty';
44-64: Redundant auto-release logic when both conditions are met.If the claim has expired (lines 45-51), the bounty is already released, but the inactivity check (lines 54-64) still runs and may redundantly set the same fields. Consider short-circuiting after the first release:
♻️ Suggested refactor
// If claim expired if (expiresAt && isPast(expiresAt)) { // Auto-release newBounty.status = 'open'; newBounty.claimedBy = undefined; newBounty.claimedAt = undefined; newBounty.claimExpiresAt = undefined; + return newBounty; } // If inactive for too long
73-94: Add explicit return type for consistency.The method returns objects with varying shapes (
detailsis only present for single-claim). An explicit return type documents the contract and helps catch mismatches in consumers.♻️ Suggested type annotation
+ interface ClaimStatusDisplay { + label: string; + color: string; + details?: string; + } + static getClaimStatusDisplay(bounty: { status: string; claimingModel: ClaimingModel; claimExpiresAt?: string; - }) { + }): ClaimStatusDisplay {
96-98: UseparseISOfor consistent date parsing.The rest of the file uses
parseISOfrom date-fns, butformatDateusesnew Date(). The latter can exhibit browser-specific behavior with certain date string formats.🔧 Suggested fix
private static formatDate(dateStr: string) { - return new Date(dateStr).toLocaleDateString(); + return parseISO(dateStr).toLocaleDateString(); }
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@lib/logic/bounty-logic.ts`:
- Around line 31-64: The inactivity check currently only uses lastActivityAt and
thus never fires for bounties missing that field; modify the logic where
lastActive is computed (near the getDate helper and the inactivity block) to
fall back to claimedAt by setting lastActive = getDate(bounty.lastActivityAt) ||
getDate(bounty.claimedAt), then proceed to compute daysInactive with
differenceInDays(now, lastActive) and compare to this.INACTIVITY_THRESHOLD_DAYS
to possibly reset newBounty.status, newBounty.claimedBy, newBounty.claimedAt,
and newBounty.claimExpiresAt as before.
🧹 Nitpick comments (1)
lib/logic/bounty-logic.ts (1)
96-98: Use deterministic date formatting to avoid locale/SSR drift.Line 97 uses
toLocaleDateString()without a fixed locale/timezone, which can produce inconsistent UI across environments (server vs. client). Prefer a deterministic formatter.♻️ Proposed fix (date-fns format)
-import { differenceInDays, isPast, parseISO } from 'date-fns'; +import { differenceInDays, isPast, parseISO, format } from 'date-fns'; private static formatDate(dateStr: string) { - return new Date(dateStr).toLocaleDateString(); + return format(parseISO(dateStr), 'MMM d, yyyy'); }
…terface and improve date parsing robustness.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@lib/logic/bounty-logic.ts`:
- Around line 50-69: When auto-releasing a claim in bounty-logic.ts, also clear
the bounty.lastActivityAt field so future checks don't immediately treat the
bounty as inactive; update both the "claim expired" block and the "inactive for
too long" block to set newBounty.lastActivityAt = undefined along with
newBounty.status = 'open', newBounty.claimedBy = undefined, newBounty.claimedAt
= undefined, and newBounty.claimExpiresAt = undefined (referencing newBounty,
lastActivityAt, expiresAt, and the inactivity check that uses
getDate(bounty.lastActivityAt) || getDate(bounty.claimedAt)).
This pull request introduces logic for dynamic bounty status handling, particularly around claim expiration and inactivity, and updates the data models and mock data accordingly. The main goal is to ensure that bounty statuses (such as "claimed" or "open") accurately reflect their real-time state, supporting features like auto-release when a claim expires or the claimant is inactive. These changes are integrated across the API, UI, and data layers.
Dynamic Bounty Status Logic:
BountyLogicclass inlib/logic/bounty-logic.tsthat processes bounty status based on timestamps and claim model, handling auto-release of claims on expiration or inactivity, and provides UI-friendly status metadata.app/api/bounties/route.ts), bounty detail page (app/bounty/[id]/page.tsx), and discover page (app/discover/page.tsx) to useBountyLogic.processBountyStatusfor each bounty, ensuring up-to-date status is shown to users. [1] app/bounty/[id]/page.tsxR5, app/bounty/[id]/page.tsxL30-R35, [2] [3]Data Model Enhancements:
Bountytypes/interfaces in bothlib/types.tsandtypes/bounty.tsto include fields needed for status logic:claimedAt,claimedBy,lastActivityAt,claimExpiresAt, andsubmissionsEndDate. [1] [2]lib/api/bounties.tsto accept the new optional fields.Mock Data Updates:
lib/mock-bounty.ts) to include realistic values for new status-related fields, such as an expired claim.HOW TO TEST
I have set up a specific test case in the mock data:
Bounty #2 ("Implement dark mode toggle")
Raw Data: Status is 'claimed', but claimExpiresAt is set to Jan 15, 2024 (expired).
The Test:
Visit UI: Go to the bounty list or detail page for Bounty #2.
Expected Result: You should see the status as "OPEN" (or "Available").
Failure State: If you see "CLAIMED", it means the
BountyLogic didn't run, and the app is showing the stale raw data.
closes #53
Summary by CodeRabbit
New Features
Chores
Bug Fixes
✏️ Tip: You can customize this high-level summary in your review settings.