Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 5 additions & 12 deletions components/bounty-detail/bounty-detail-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { BountyDetailSkeleton } from "@/components/ui/loading";
import { useBountyDetail } from "@/hooks/use-bounty-detail";
import { FcfsApprovalPanel } from "@/components/bounty/fcfs-approval-panel";
import { CompetitionJudging } from "@/components/bounty/competition-judging";
import type { CompetitionSubmissionEntry } from "@/components/bounty/competition-judging";
import { EscrowDetailPanel } from "../bounty/escrow-detail-panel";
import { RefundStatusTracker } from "../bounty/refund-status";
import { FeeCalculator } from "../bounty/fee-calculator";
Expand Down Expand Up @@ -72,10 +71,7 @@ function getFullMilestoneData(bounty: BountyData): {
// Backend does not currently provide applications in the response.
// Fall back to empty array until the schema supports it.
const getApplications = (bounty: BountyData): Application[] => {
return (
(bounty as BountyData & { applications?: Application[] })?.applications ??
[]
);
return bounty?.applications ?? [];
};

export function BountyDetailClient({ bountyId }: { bountyId: string }) {
Expand Down Expand Up @@ -156,17 +152,14 @@ export function BountyDetailClient({ bountyId }: { bountyId: string }) {
// Identify if the current user is the assigned contributor
// using a fallback check on submissions or assumed backend field.
const isAssignedApplicant =
(bounty as BountyData & { assignedContributorId?: string })
?.assignedContributorId === session?.user?.id ||
bounty.assignedContributorId === session?.user?.id ||
bounty.submissions?.some((s) => s.submittedBy === session?.user?.id) ||
(!isCreator && bounty.status === "IN_PROGRESS");
Comment thread
coderabbitai[bot] marked this conversation as resolved.

// submissions is present on BountyQuery (single-bounty query) but not on
// BountyFieldsFragment (list query). The cast is safe here because
// useBountyDetail returns BountyFieldsFragment & Partial<BountyQuery["bounty"]>.
const competitionSubmissions =
(bounty as { submissions?: CompetitionSubmissionEntry[] | null })
.submissions ?? [];
// BountyFieldsFragment (list query). Accessed via the Partial<Bounty>
// intersection in useBountyDetail's return type.
const competitionSubmissions = bounty.submissions ?? [];

return (
<div className="flex flex-col lg:flex-row gap-10">
Expand Down
7 changes: 3 additions & 4 deletions hooks/use-competition-join-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from "@/hooks/use-competition-bounty";
import { useDeadlinePassed } from "@/hooks/use-deadline-passed";
import type { BountyFieldsFragment } from "@/lib/graphql/generated";
import type { Bounty } from "@/types/bounty";

interface CompetitionJoinState {
walletAddress: string | null;
Expand All @@ -19,7 +20,7 @@ interface CompetitionJoinState {
}

export function useCompetitionJoinState(
bounty: BountyFieldsFragment,
bounty: BountyFieldsFragment & Partial<Bounty>,
): CompetitionJoinState {
const { data: session } = authClient.useSession();
const joinMutation = useJoinCompetition();
Expand All @@ -38,9 +39,7 @@ export function useCompetitionJoinState(
// Derive from server payload (submissions list on BountyQuery) + local optimism.
// BountyFieldsFragment (list queries) doesn't include submissions, so falls
// back to false until the detail query resolves.
const bountySubmissions = (
bounty as { submissions?: Array<{ submittedBy: string }> | null }
).submissions;
const bountySubmissions = bounty.submissions;
const serverHasJoined =
walletAddress != null &&
(bountySubmissions?.some((s) => s.submittedBy === walletAddress) ?? false);
Expand Down
23 changes: 23 additions & 0 deletions types/bounty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,24 @@ export interface ContributorProgress {
currentMilestoneId: string;
}

export interface BountyApplication {
id: string;
applicantAddress: string;
applicantName?: string;
proposal: {
approach: string;
estimatedTimeline: string;
relevantExperience: string;
portfolioUrl?: string;
};
reputation: {
score: number;
tier: string;
completionStats: string;
};
createdAt: string;
}
Comment on lines +86 to +102
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check the GraphQL schema for BountyApplication type definition

# Search for the BountyApplication type or Application type in schema files
fd -e gql -e graphql | xargs rg -A 20 'type.*Application' 

# Also search for reputation-related types
fd -e gql -e graphql | xargs rg -A 10 'type.*Reputation|reputation'

Repository: boundlessfi/bounties

Length of output: 48


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Find all references to completionStats anywhere in the repo
rg -n "completionStats" . || true

# 2) Locate GraphQL schema files likely containing type definitions
# (expand beyond .gql/.graphql to catch .graphqls, .ts schema strings, etc.)
fd -e gql -e graphql -e graphqls -e schema -e schemas -e apollo -e apis -e api \
  -e ts -e js -e json -e yml -e yaml \
  --type f . | head -n 50 || true

# More targeted: list likely schema-containing files
fd -e graphql -e gql -e graphqls -e schema --type f . || true

# 3) Search those schema files for the BountyApplication/reputation types
# If no schema files exist, this will yield nothing, but rg for completionStats above should still show schema usage.
schema_files=$(fd -e graphql -e gql -e graphqls -e schema --type f . || true)
if [ -n "${schema_files}" ]; then
  printf "%s\n" "${schema_files}" | xargs -I{} rg -n -C 2 --hidden -S "type\\s+.*Application|type\\s+.*Reputation|reputation|completionStats" {} || true
fi

Repository: boundlessfi/bounties

Length of output: 2339


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Check the schema definition
rg -n "completionStats" lib/graphql/schema.graphql || true

# 2) Check any GraphQL fragments/operations that reference completionStats
rg -n "completionStats" lib/graphql/operations --glob='*.graphql' || true

# 3) Also search for the reputation field selection set to find the surrounding type context
rg -n "reputation\\s*\\{" lib/graphql/operations --glob='*.graphql' || true

# 4) Print the relevant portion of schema.graphql around the match
# (use sed to keep output small)
line=$(rg -n "completionStats" lib/graphql/schema.graphql | head -n1 | cut -d: -f1 || true)
if [ -n "${line}" ]; then
  start=$((line-20))
  end=$((line+20))
  sed -n "${start},${end}p" lib/graphql/schema.graphql
fi

Repository: boundlessfi/bounties

Length of output: 46


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Broad searches in the GraphQL schema and operations
echo "== schema.graphql matches for completionStats =="
rg -n "completionStats" lib/graphql/schema.graphql || echo "NO MATCH"

echo
echo "== lib/graphql matches for completionStats ==" 
rg -n "completionStats" lib/graphql || echo "NO MATCH IN lib/graphql"

echo
echo "== schema.graphql matches for completion ==" 
rg -n "completion" lib/graphql/schema.graphql | head -n 50 || echo "NO MATCH"

echo
echo "== schema.graphql matches for reputation type ==" 
rg -n "type\\s+.*Reputation|reputation\\b" lib/graphql/schema.graphql | head -n 80 || true

echo
echo "== schema.graphql matches for completionStats-like fields ==" 
rg -n "Stats|stats" lib/graphql/schema.graphql | head -n 80 || true

Repository: boundlessfi/bounties

Length of output: 441


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Where is reputation requested in GraphQL operations?
echo "== references to reputation in lib/graphql/operations =="
rg -n "reputation" lib/graphql/operations --glob='*.graphql' || true

# 2) Dump nearby text for the first few reputation matches (to see selected fields)
# (Limit output to keep it small)
echo
echo "== context around first reputation occurrence (operations) =="
first=$(rg -n "reputation" lib/graphql/operations --glob='*.graphql' | head -n1 || true)
if [ -n "$first" ]; then
  file=$(echo "$first" | cut -d: -f1)
  line=$(echo "$first" | cut -d: -f2)
  start=$((line-30)); end=$((line+30))
  sed -n "${start},${end}p" "$file"
fi

# 3) Search schema.graphql for "reputation" and "stats" types
echo
echo "== schema.graphql references to reputation =="
rg -n "reputation" lib/graphql/schema.graphql || echo "NO reputation match"

echo
echo "== schema.graphql references to \"tier\" and \"completion\" =="
rg -n "tier|completion|Completion|completionRate|ContributorStats" lib/graphql/schema.graphql | head -n 120 || true

# 4) Show the ContributorStats type definition area
echo
echo "== ContributorStats definition area =="
line=$(rg -n "type ContributorStats" lib/graphql/schema.graphql | head -n1 | cut -d: -f1 || true)
if [ -n "${line}" ]; then
  start=$((line-10)); end=$((line+60))
  sed -n "${start},${end}p" lib/graphql/schema.graphql
fi

Repository: boundlessfi/bounties

Length of output: 1631


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find where completionStats is assigned/constructed (not only referenced)
rg -n "completionStats\\s*:" . || true
rg -n "completionStats" components app lib types hooks --glob='*.ts' --glob='*.tsx' || true

# Find where BountyApplication / reputation objects are built
rg -n "BountyApplication" . || true
rg -n "reputation:\\s*\\{" . || true
rg -n "reputation\\s*=\\s*" . || true

# Inspect the relevant type definition area in types/bounty.ts
sed -n '60,130p' types/bounty.ts

# Inspect the component usage area
sed -n '1,140p' components/bounty/application-review-dashboard.tsx

Repository: boundlessfi/bounties

Length of output: 7436


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Search GraphQL ops for reputation-related selections (tier/stats/contributor stats)
rg -n "reputation|ContributorStats|completionRate|averageCompletionTime|currentStreak|tier\\b|completionStats" lib/graphql/operations --glob='*.graphql' || true

# 2) Inspect the main bounty queries/mutations that likely fetch applications
for f in lib/graphql/operations/bounty-queries.graphql lib/graphql/operations/bounty-mutations.graphql lib/graphql/operations/fragments.graphql lib/graphql/operations/submission-mutations.graphql; do
  if [ -f "$f" ]; then
    echo "===== $f ====="
    # show only the most relevant parts (around common keywords)
    rg -n "applications|application|BountyApplication|reputation|Contributor|tier|stats" "$f" || true
  fi
done

# 3) Print fragments file sections around "stats" and "tier" if present
if [ -f lib/graphql/operations/fragments.graphql ]; then
  rg -n "stats|tier|ContributorStats|LeaderboardContributor|reputation" lib/graphql/operations/fragments.graphql || true
fi

# 4) Search for mapping usage in TS/TSX: any transform of completionRate into completionStats
rg -n "completionRate|averageCompletionTime|currentStreak|longestStreak|completionStats" . --glob='*.ts' --glob='*.tsx' || true

Repository: boundlessfi/bounties

Length of output: 4852


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Look for any completionStats mention in generated GraphQL types
rg -n "completionStats" lib/graphql/generated.ts || true

# 2) Inspect bounty queries for application/reputation selections
for f in lib/graphql/operations/bounty-queries.graphql lib/graphql/operations/fragments.graphql lib/graphql/operations/bounty-mutations.graphql; do
  if [ -f "$f" ]; then
    echo "===== $f ====="
    # show any "reputation" / "applications" sections
    rg -n "applications|application|reputation|Contributor|completionRate|averageCompletionTime|stats|tier" "$f" || true
    # show full file if it's small; otherwise show around matches
    wc -l "$f"
    if [ "$(wc -l < "$f")" -le 220 ]; then
      sed -n '1,220p' "$f"
    else
      for pat in "applications" "reputation" "Contributor" "completionRate" "averageCompletionTime"; do
        line=$(rg -n "$pat" "$f" | head -n1 | cut -d: -f1 || true)
        if [ -n "$line" ]; then
          start=$((line-60)); end=$((line+80))
          sed -n "${start},${end}p" "$f"
        fi
      done
    fi
    echo
  fi
done

# 3) Search TS code for constructing completionStats from numeric fields
rg -n "completionStats\\s*[:=]" . --glob='*.ts' --glob='*.tsx' || true
rg -n "completionRate|averageCompletionTime|currentStreak|longestStreak" lib/services --glob='*.ts' || true

# 4) Inspect reputation service and any bounty application service
sed -n '1,200p' lib/services/reputation.ts 2>/dev/null || true

# find possible bounty-application-related services
rg -n "get.*application|bounty.*application|selectApplicant|applications" lib/services --glob='*.ts' || true

Repository: boundlessfi/bounties

Length of output: 8237


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Trace the review dashboard data flow
rg -n "useSelectApplicant|use-bounty-application|selectApplicant" . --glob='*.ts' --glob='*.tsx' || true

# 2) Find where "applications" are loaded for bounty creators/admins
rg -n "applications\\b" app lib components hooks --glob='*.ts' --glob='*.tsx' || true

# 3) Find any API/route returning applications
rg -n "route\\.ts|applications" app/api --glob='*.ts' || true

# 4) Inspect GraphQL ops for "application"
rg -n "application|applications|BountyApplication" lib/graphql/operations --glob='*.graphql' || true

# 5) Find complete set of completionStats occurrences to see if it’s ever derived/assigned
rg -n "completionStats" . --glob='*.ts' --glob='*.tsx' || true

Repository: boundlessfi/bounties

Length of output: 2647


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the note about backend not providing applications
sed -n '1,140p' components/bounty-detail/bounty-detail-client.tsx

echo
echo "---- getApplications helper ----"
rg -n "function getApplications|getApplications\\b|applications\\s*\\?\\?\\s*\\[\\]" components/bounty-detail/bounty-detail-client.tsx
# print around the function use site
sed -n '40,120p' components/bounty-detail/bounty-detail-client.tsx

echo
echo "---- Inspect use-bounty-application hook ----"
sed -n '1,220p' hooks/use-bounty-application.ts

echo
echo "---- Inspect store applications type usage ----"
sed -n '1,200p' lib/store.ts

echo
echo "---- Inspect any mock/normalization for application reputation ----"
rg -n "completionStats" components hooks lib --glob='*.ts' --glob='*.tsx' || true

Repository: boundlessfi/bounties

Length of output: 21935


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find where Application[] is created/mocked
rg -n "mock.*application|applications\\s*:\\s*\\[|BountyApplication\\b|type\\s+Application\\b|const\\s+.*applications" . --glob='*.ts' --glob='*.tsx' || true

# Also inspect mock-bounty files
fd -e ts -e tsx -e js -e jsx mock . | head -n 50 || true
fd -e ts -e tsx -e js -e jsx mock-bounty . || true

# List and inspect mock-bounty/applications usage
rg -n "useLocalApplications\\(|useAddLocalApplication\\(|useUpdateLocalApplication\\(" . --glob='*.ts' --glob='*.tsx' || true
rg -n "applications\\s*\\]" lib components app hooks types --glob='*.ts' --glob='*.tsx' || true

Repository: boundlessfi/bounties

Length of output: 691


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect mock-bounty and related mock data for application/reputation completionStats
for f in lib/mock-bounty.ts lib/mock-data.ts lib/mock-project.ts lib/mock-model4.ts lib/mock-leaderboard.ts lib/mock-wallet.ts; do
  if [ -f "$f" ]; then
    echo "===== $f ====="
    # show any Application or completionStats related lines
    rg -n "completionStats|applications|reputation\\s*:\\s*\\{" "$f" || true
    # show surrounding blocks around completionStats if present
    if rg -n "completionStats" "$f" >/dev/null; then
      line=$(rg -n "completionStats" "$f" | head -n1 | cut -d: -f1)
      start=$((line-40)); end=$((line+40))
      sed -n "${start},${end}p" "$f"
    fi
    echo
  fi
done

# Also inspect any mock-bounty usage that might set completionStats in a constant
rg -n "completionStats" lib/mock-bounty.ts lib/mock-data.ts lib/mock-leaderboard.ts lib/mock-model4.ts lib/mock-project.ts lib/mock-wallet.ts types/bounty.ts components/bounty -S || true

Repository: boundlessfi/bounties

Length of output: 494


Update completionStats typing: it isn’t defined in the GraphQL schema

completionStats doesn’t exist in lib/graphql/schema.graphql, while the schema exposes ContributorStats numeric fields like completionRate: Float! and averageCompletionTime: Float!. Update types/bounty.ts / ApplicationReviewDashboard to align with the actual GraphQL fields (or derive a display string from ContributorStats), since BountyFields also doesn’t fetch applications from the backend yet.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@types/bounty.ts` around lines 86 - 102, The BountyApplication.type currently
declares reputation.completionStats (string) which doesn't exist in the GraphQL
schema; update the BountyApplication interface and any uses in
ApplicationReviewDashboard and BountyFields to match ContributorStats fields
(use numeric fields completionRate: number and averageCompletionTime: number) or
replace completionStats with a derived display string constructed from those
numeric fields; adjust types and any code paths that read
reputation.completionStats to instead read reputation.completionRate and
reputation.averageCompletionTime (or compute a formatted string) so the TS types
align with the GraphQL schema.


export interface Bounty {
id: string;
title: string;
Expand All @@ -105,14 +123,19 @@ export interface Bounty {
bountyWindow?: BountyWindowType | null;

submissions?: BountySubmission[] | null;
applications?: BountyApplication[] | null;
_count?: BountyCount | null;

milestones?: Milestone[] | null;
contributorProgress?: ContributorProgress[] | null;

claimCount?: number | null;
maxParticipants?: number | null;
maxSlots?: number | null;
totalSlotsOccupied?: number | null;

assignedContributorId?: string | null;

createdBy: string;
createdAt: string;
updatedAt: string;
Expand Down
Loading