Skip to content

feat-Implement Bounty Status Logic & Anti-Squatting#55

Merged
0xdevcollins merged 6 commits intoboundlessfi:mainfrom
Dprof-in-tech:feat-Implement-Bounty-Status-Logic-&-Anti-Squatting
Jan 29, 2026
Merged

feat-Implement Bounty Status Logic & Anti-Squatting#55
0xdevcollins merged 6 commits intoboundlessfi:mainfrom
Dprof-in-tech:feat-Implement-Bounty-Status-Logic-&-Anti-Squatting

Conversation

@Dprof-in-tech
Copy link
Contributor

@Dprof-in-tech Dprof-in-tech commented Jan 29, 2026

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:

  • Added a new BountyLogic class in lib/logic/bounty-logic.ts that processes bounty status based on timestamps and claim model, handling auto-release of claims on expiration or inactivity, and provides UI-friendly status metadata.
  • Updated API route (app/api/bounties/route.ts), bounty detail page (app/bounty/[id]/page.tsx), and discover page (app/discover/page.tsx) to use BountyLogic.processBountyStatus for 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]
  • Updated bounty count display in the discover page to reflect the source data, not filtered results.

Data Model Enhancements:

  • Extended the Bounty types/interfaces in both lib/types.ts and types/bounty.ts to include fields needed for status logic: claimedAt, claimedBy, lastActivityAt, claimExpiresAt, and submissionsEndDate. [1] [2]
  • Updated the validation schema in lib/api/bounties.ts to accept the new optional fields.

Mock Data Updates:

  • Enhanced mock bounty data (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

    • Automatic claim expiration and auto-release for single-claim bounties
    • Enhanced claim status labels and UI display (Available / Claimed / Applications Open, with expiry/details)
    • Added claim-tracking metadata (owner, claim timestamps, last-activity, expiry, submissions deadline)
  • Chores

    • Normalized timestamps to ISO string format across mock and source data for consistent sorting and display
    • Updated public data shapes to use string-based timestamps
  • Bug Fixes

    • Ensure bounty status is processed before filtering and rendering

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 29, 2026

📝 Walkthrough

Walkthrough

Adds 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

Cohort / File(s) Summary
Schema & Types
lib/api/bounties.ts, lib/types.ts, types/bounty.ts
Added optional fields claimedAt, claimedBy, lastActivityAt, claimExpiresAt, submissionsEndDate; converted several Date fields to string.
Business Logic
lib/logic/bounty-logic.ts
New BountyLogic class: INACTIVITY_THRESHOLD_DAYS, processBountyStatus, getClaimStatusDisplay, date helpers; implements auto-release on expiry/inactivity using date-fns.
Mock Data
lib/mock-bounty.ts, lib/mock-data.ts
Mock timestamps switched to ISO string literals; bounty id: "2" now includes claimedBy, claimedAt, and a commented expired claimExpiresAt.
API & Pages
app/api/bounties/route.ts, app/bounty/[id]/page.tsx, app/discover/page.tsx
Bounties are processed via BountyLogic.processBountyStatus before filtering/rendering; date-based sorts now parse ISO strings; discover page shows raw mock count where applicable.

Sequence Diagram

sequenceDiagram
    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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I tidy timestamps where claims once sat,
I nudge stale hands and free a trap.
I hop through logic, whiskers bright,
Releasing bounties into light—
Carrots, code, and one small clap!

🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR implements core requirements from #53: dynamic status processing via BountyLogic.processBountyStatus with auto-release on claim expiration/inactivity, status accessible via getClaimStatusDisplay, and extended bounty fields. Auto-release logic for Model 1 is present; creator overrides are not yet implemented. Implement creator override mechanism for releasing claims with justification as specified in #53 acceptance criteria. This feature is incomplete in the current changeset.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat-Implement Bounty Status Logic & Anti-Squatting' directly and clearly summarizes the main changes: implementing bounty status logic and anti-squatting mechanisms.
Out of Scope Changes check ✅ Passed All changes align with #53 objectives: BountyLogic class, status processing integration, field extensions, and mock data updates. Date format conversions (Date → string) in lib/mock-data.ts and lib/types.ts support the status logic requirements and are not out of scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_DAYS constant 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 in generateMetadata for consistency.

The generateMetadata function uses the raw bounty without calling processBountyStatus. 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" }
   }

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 — ClaimingModel is 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 (details is 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: Use parseISO for consistent date parsing.

The rest of the file uses parseISO from date-fns, but formatDate uses new 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();
     }

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Model-Specific Status Tracking and Anti-Squatting Logic

2 participants