Chore/remove dead rest api surface - #171
Conversation
Accept upstream removal of lib/api/bounties.ts (GraphQL/types replace REST schemas). Align lib/api/index.ts exports with ./client (no token helpers). Made-with: Cursor
Remove put/patch/del and stop exporting apiClient; barrel exports get/post only. Bounty proxy routes were already absent. Regenerate lockfile after npm install; build verified with npm run build. Made-with: Cursor
|
@Abidoyesimze is attempting to deploy a commit to the Threadflow Team on Vercel. A member of the Team first needs to authorize it. |
|
@Abidoyesimze Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
📝 WalkthroughWalkthroughThis PR removes Next.js API route proxies for application reviews and submission selection endpoints, eliminates unused HTTP helper functions from the API client library, standardizes code formatting across leaderboard components and hooks, and refactors the mini-leaderboard component's rendering logic to handle error states distinctly. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 3❌ Failed checks (2 warnings, 1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
lib/mock-leaderboard.ts (1)
11-11: Replace deprecated.substr()with.slice().The
.substr()method is deprecated in modern JavaScript (ES2020+). While this function will continue to work for mock data, migrating to.slice()improves compatibility with current standards.♻️ Suggested change
- walletAddress: `0x${Math.random().toString(16).substr(2, 40)}`, + walletAddress: `0x${Math.random().toString(16).slice(2)}`,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/mock-leaderboard.ts` at line 11, Replace the deprecated use of String.prototype.substr in the walletAddress generation with String.prototype.slice: locate the walletAddress template string that uses Math.random().toString(16).substr(2, 40) and change it to use slice by computing the same substring range (start 2, end 42) so the expression becomes Math.random().toString(16).slice(2, 42); update the walletAddress assignment in lib/mock-leaderboard.ts accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/leaderboard/page.tsx`:
- Around line 26-46: The filters state is initialized from URL params
(initialTimeframe, initialTier, initialTags) but never updated when searchParams
change; replace the one-time useState seed with logic that syncs state to URL
changes by adding a useEffect that watches searchParams (or
rawTimeframe/rawTier/rawTags) and calls setFilters(...) with the validated
values (using the same TIMEFRAMES/TIERS checks and split for tags) so that
filters remains in sync when the user navigates/back-forward or lands on a new
/leaderboard?... URL; keep existing validation logic and only update filters
when derived values actually differ to avoid needless renders.
- Around line 48-50: The hard-coded currentUserId ("user-1") in
app/leaderboard/page.tsx causes wrong highlighting/rank for real users; replace
it by deriving the id from the app's auth/session layer (e.g., obtain user via
your auth hook or session getter and set currentUserId = user?.id) and ensure
any UI that expects a user (sidebar highlighting, rank logic) safely handles
undefined by hiding or disabling user-specific UI until auth is available;
update any references to currentUserId in this file so they tolerate undefined
and do not assume a string.
- Around line 115-118: The AlertDescription currently renders raw error details
((error as Error)?.message) to users; change the UI to show a generic,
user-facing message like "Failed to load leaderboard data. Please try again
later." and remove the direct interpolation of error.message in the JSX, while
recording the full error to safe logging/telemetry (e.g., call your existing
logger/reportError or console.error) near the error handling in page.tsx; locate
the JSX using the AlertDescription element and the error variable to make this
change.
In `@components/leaderboard/mini-leaderboard.tsx`:
- Around line 73-110: The list currently maps contributors and if the array is
empty only the footer CTA is shown; add an explicit empty-state render when
contributors is an empty array by checking contributors?.length === 0 and
returning a small fallback block (e.g., centered message/icon and optional CTA)
inside the component between the contributors map and the footer CTA div so
users see a clear "No contributors yet" state instead of an apparent blank card;
update the JSX around the contributors?.map(...) and the subsequent <div
className="p-2"> footer to conditionally render the empty-state when
contributors exists but has length 0.
- Around line 75-78: The leaderboard page uses a wrong profile route for
contributor links: change the Link href that currently builds
`/user/${entry.contributor.userId}` to `/profile/${entry.contributor.userId}` so
it matches the rest of the app; locate the Link rendering that uses
entry.contributor.userId in the leaderboard page component and update the href
string accordingly (keep the dynamic interpolation and the existing key/props
intact).
---
Nitpick comments:
In `@lib/mock-leaderboard.ts`:
- Line 11: Replace the deprecated use of String.prototype.substr in the
walletAddress generation with String.prototype.slice: locate the walletAddress
template string that uses Math.random().toString(16).substr(2, 40) and change it
to use slice by computing the same substring range (start 2, end 42) so the
expression becomes Math.random().toString(16).slice(2, 42); update the
walletAddress assignment in lib/mock-leaderboard.ts accordingly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 8e738bb4-7559-439f-a8fa-5c73397420a9
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (14)
app/api/applications/[id]/review/route.tsapp/api/submissions/[id]/select/route.tsapp/leaderboard/page.tsxcomponents/leaderboard/leaderboard-filters.tsxcomponents/leaderboard/mini-leaderboard.tsxdocs/REALTIME_SYNC.mdhooks/use-bounty-subscription.tshooks/use-leaderboard.tslib/api/client.tslib/api/index.tslib/graphql/generated.tslib/graphql/ws-client.tslib/mock-leaderboard.tstypes/leaderboard.ts
💤 Files with no reviewable changes (2)
- app/api/submissions/[id]/select/route.ts
- app/api/applications/[id]/review/route.ts
| // Validate and initialize filters from URL | ||
| const rawTimeframe = searchParams.get("timeframe"); | ||
| const rawTier = searchParams.get("tier"); | ||
|
|
||
| const initialTimeframe = TIMEFRAMES.some((t) => t.value === rawTimeframe) | ||
| ? (rawTimeframe as FiltersType["timeframe"]) | ||
| : LeaderboardTimeframe.AllTime; | ||
|
|
||
| const initialTier = TIERS.some((t) => t.value === rawTier) | ||
| ? (rawTier as ReputationTier) | ||
| : undefined; | ||
|
|
||
| const initialTags = searchParams.get("tags") | ||
| ? searchParams.get("tags")?.split(",") | ||
| : []; | ||
|
|
||
| const [filters, setFilters] = useState<FiltersType>({ | ||
| timeframe: initialTimeframe, | ||
| tier: initialTier, | ||
| tags: initialTags || [], | ||
| }); |
There was a problem hiding this comment.
Keep filter state in sync when the URL changes.
useState only consumes initialTimeframe, initialTier, and initialTags on the first render. If the user navigates with browser back/forward or lands on another /leaderboard?... URL while this page stays mounted, filters can remain stale and the URL-sync effect can overwrite the navigated query.
💡 Suggested direction
+ // Consider extracting URL parsing into a helper and syncing `filters`
+ // when `searchParams.toString()` changes, with an equality guard to avoid loops.
+ // Also build the replace URL without a trailing `?` when params are empty.
+
// Sync debounced filters to URL
useEffect(() => {
const params = new URLSearchParams();
@@
- router.replace(`/leaderboard?${params.toString()}`, { scroll: false });
+ const query = params.toString();
+ router.replace(query ? `/leaderboard?${query}` : "/leaderboard", {
+ scroll: false,
+ });
}, [debouncedFilters, router]);Also applies to: 75-86
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/leaderboard/page.tsx` around lines 26 - 46, The filters state is
initialized from URL params (initialTimeframe, initialTier, initialTags) but
never updated when searchParams change; replace the one-time useState seed with
logic that syncs state to URL changes by adding a useEffect that watches
searchParams (or rawTimeframe/rawTier/rawTags) and calls setFilters(...) with
the validated values (using the same TIMEFRAMES/TIERS checks and split for tags)
so that filters remains in sync when the user navigates/back-forward or lands on
a new /leaderboard?... URL; keep existing validation logic and only update
filters when derived values actually differ to avoid needless renders.
| // Fake current user ID for demo purposes | ||
| // In a real app this would come from auth context | ||
| const currentUserId = "user-1"; |
There was a problem hiding this comment.
Avoid shipping a hard-coded current user.
currentUserId = "user-1" makes the sidebar rank and current-user highlighting wrong for every real user. Prefer auth-derived user identity, or pass undefined/hide user-specific UI until auth is available.
Do you want me to draft a follow-up implementation that wires this to the project’s auth source?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/leaderboard/page.tsx` around lines 48 - 50, The hard-coded currentUserId
("user-1") in app/leaderboard/page.tsx causes wrong highlighting/rank for real
users; replace it by deriving the id from the app's auth/session layer (e.g.,
obtain user via your auth hook or session getter and set currentUserId =
user?.id) and ensure any UI that expects a user (sidebar highlighting, rank
logic) safely handles undefined by hiding or disabling user-specific UI until
auth is available; update any references to currentUserId in this file so they
tolerate undefined and do not assume a string.
| <AlertDescription className="flex flex-col gap-2"> | ||
| <p> | ||
| Failed to load leaderboard data. {(error as Error)?.message} | ||
| </p> |
There was a problem hiding this comment.
Don’t render raw error messages directly to users.
error.message can include backend or GraphQL details. Show a generic message here and reserve detailed errors for safe logging/telemetry.
🛡️ Proposed user-facing copy change
- <p>
- Failed to load leaderboard data. {(error as Error)?.message}
- </p>
+ <p>Failed to load leaderboard data. Please try again.</p>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <AlertDescription className="flex flex-col gap-2"> | |
| <p> | |
| Failed to load leaderboard data. {(error as Error)?.message} | |
| </p> | |
| <AlertDescription className="flex flex-col gap-2"> | |
| <p>Failed to load leaderboard data. Please try again.</p> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/leaderboard/page.tsx` around lines 115 - 118, The AlertDescription
currently renders raw error details ((error as Error)?.message) to users; change
the UI to show a generic, user-facing message like "Failed to load leaderboard
data. Please try again later." and remove the direct interpolation of
error.message in the JSX, while recording the full error to safe
logging/telemetry (e.g., call your existing logger/reportError or console.error)
near the error handling in page.tsx; locate the JSX using the AlertDescription
element and the error variable to make this change.
| {contributors?.map( | ||
| (contributor: LeaderboardContributor, index: number) => ( | ||
| <Link | ||
| key={contributor.id} | ||
| href={`/profile/${contributor.userId}`} | ||
| className="flex items-center gap-3 px-4 py-3 hover:bg-muted/50 transition-colors border-b border-border/40 last:border-0 group" | ||
| > | ||
| <div className="flex-shrink-0 relative"> | ||
| <Avatar className="h-9 w-9 border border-border/50"> | ||
| <AvatarImage src={contributor.avatarUrl || undefined} /> | ||
| <AvatarFallback> | ||
| {contributor.displayName?.[0] ?? "?"} | ||
| </AvatarFallback> | ||
| </Avatar> | ||
| <div className="absolute -top-1 -left-1 text-foreground flex items-center justify-center w-4 h-4 rounded-full bg-background border border-border text-[10px] font-bold"> | ||
| {index + 1} | ||
| </div> | ||
| ) : ( | ||
| <div className="flex flex-col"> | ||
| {contributors?.map((contributor: LeaderboardContributor, index: number) => ( | ||
| <Link | ||
| key={contributor.id} | ||
| href={`/profile/${contributor.userId}`} | ||
| className="flex items-center gap-3 px-4 py-3 hover:bg-muted/50 transition-colors border-b border-border/40 last:border-0 group" | ||
| > | ||
| <div className="flex-shrink-0 relative"> | ||
| <Avatar className="h-9 w-9 border border-border/50"> | ||
| <AvatarImage src={contributor.avatarUrl || undefined} /> | ||
| <AvatarFallback>{contributor.displayName?.[0] ?? "?"}</AvatarFallback> | ||
| </Avatar> | ||
| <div className="absolute -top-1 -left-1 text-foreground flex items-center justify-center w-4 h-4 rounded-full bg-background border border-border text-[10px] font-bold"> | ||
| {index + 1} | ||
| </div> | ||
| </div> | ||
| <div className="flex-1 min-w-0"> | ||
| <div className="flex items-center gap-2"> | ||
| <span className="font-medium text-foreground text-sm truncate group-hover:text-muted-foreground transition-colors"> | ||
| {contributor.displayName} | ||
| </span> | ||
| </div> | ||
| <div className="flex items-center gap-2 mt-0.5"> | ||
| <TierBadge tier={contributor.tier} className="h-4 text-[10px] px-1.5 py-0" /> | ||
| <span className="text-[10px] text-muted-foreground font-mono"> | ||
| {contributor.totalScore.toLocaleString()} pts | ||
| </span> | ||
| </div> | ||
| </div> | ||
| </Link> | ||
| ))} | ||
| <div className="p-2"> | ||
| <Button variant="ghost" className="w-full text-xs h-8 text-muted-foreground hover:text-foreground" asChild> | ||
| <Link href="/leaderboard"> | ||
| See full rankings | ||
| </Link> | ||
| </Button> | ||
| </div> | ||
| </div> | ||
| <div className="flex-1 min-w-0"> | ||
| <div className="flex items-center gap-2"> | ||
| <span className="font-medium text-foreground text-sm truncate group-hover:text-muted-foreground transition-colors"> | ||
| {contributor.displayName} | ||
| </span> | ||
| </div> | ||
| )} | ||
| </CardContent> | ||
| </Card> | ||
| ); | ||
| <div className="flex items-center gap-2 mt-0.5"> | ||
| <TierBadge | ||
| tier={contributor.tier} | ||
| className="h-4 text-[10px] px-1.5 py-0" | ||
| /> | ||
| <span className="text-[10px] text-muted-foreground font-mono"> | ||
| {contributor.totalScore.toLocaleString()} pts | ||
| </span> | ||
| </div> | ||
| </div> | ||
| </Link> | ||
| ), | ||
| )} | ||
| <div className="p-2"> |
There was a problem hiding this comment.
Render an explicit empty state when there are no contributors.
If contributors resolves to an empty array, this card currently shows only the footer CTA, which looks like missing content.
💡 Proposed empty-state handling
- {contributors?.map(
+ {contributors?.length ? contributors.map(
(contributor: LeaderboardContributor, index: number) => (
<Link
key={contributor.id}
href={`/profile/${contributor.userId}`}
className="flex items-center gap-3 px-4 py-3 hover:bg-muted/50 transition-colors border-b border-border/40 last:border-0 group"
@@
</Link>
),
- )}
+ ) : (
+ <div className="px-4 py-6 text-center text-sm text-muted-foreground">
+ No contributors yet
+ </div>
+ )}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| {contributors?.map( | |
| (contributor: LeaderboardContributor, index: number) => ( | |
| <Link | |
| key={contributor.id} | |
| href={`/profile/${contributor.userId}`} | |
| className="flex items-center gap-3 px-4 py-3 hover:bg-muted/50 transition-colors border-b border-border/40 last:border-0 group" | |
| > | |
| <div className="flex-shrink-0 relative"> | |
| <Avatar className="h-9 w-9 border border-border/50"> | |
| <AvatarImage src={contributor.avatarUrl || undefined} /> | |
| <AvatarFallback> | |
| {contributor.displayName?.[0] ?? "?"} | |
| </AvatarFallback> | |
| </Avatar> | |
| <div className="absolute -top-1 -left-1 text-foreground flex items-center justify-center w-4 h-4 rounded-full bg-background border border-border text-[10px] font-bold"> | |
| {index + 1} | |
| </div> | |
| ) : ( | |
| <div className="flex flex-col"> | |
| {contributors?.map((contributor: LeaderboardContributor, index: number) => ( | |
| <Link | |
| key={contributor.id} | |
| href={`/profile/${contributor.userId}`} | |
| className="flex items-center gap-3 px-4 py-3 hover:bg-muted/50 transition-colors border-b border-border/40 last:border-0 group" | |
| > | |
| <div className="flex-shrink-0 relative"> | |
| <Avatar className="h-9 w-9 border border-border/50"> | |
| <AvatarImage src={contributor.avatarUrl || undefined} /> | |
| <AvatarFallback>{contributor.displayName?.[0] ?? "?"}</AvatarFallback> | |
| </Avatar> | |
| <div className="absolute -top-1 -left-1 text-foreground flex items-center justify-center w-4 h-4 rounded-full bg-background border border-border text-[10px] font-bold"> | |
| {index + 1} | |
| </div> | |
| </div> | |
| <div className="flex-1 min-w-0"> | |
| <div className="flex items-center gap-2"> | |
| <span className="font-medium text-foreground text-sm truncate group-hover:text-muted-foreground transition-colors"> | |
| {contributor.displayName} | |
| </span> | |
| </div> | |
| <div className="flex items-center gap-2 mt-0.5"> | |
| <TierBadge tier={contributor.tier} className="h-4 text-[10px] px-1.5 py-0" /> | |
| <span className="text-[10px] text-muted-foreground font-mono"> | |
| {contributor.totalScore.toLocaleString()} pts | |
| </span> | |
| </div> | |
| </div> | |
| </Link> | |
| ))} | |
| <div className="p-2"> | |
| <Button variant="ghost" className="w-full text-xs h-8 text-muted-foreground hover:text-foreground" asChild> | |
| <Link href="/leaderboard"> | |
| See full rankings | |
| </Link> | |
| </Button> | |
| </div> | |
| </div> | |
| <div className="flex-1 min-w-0"> | |
| <div className="flex items-center gap-2"> | |
| <span className="font-medium text-foreground text-sm truncate group-hover:text-muted-foreground transition-colors"> | |
| {contributor.displayName} | |
| </span> | |
| </div> | |
| )} | |
| </CardContent> | |
| </Card> | |
| ); | |
| <div className="flex items-center gap-2 mt-0.5"> | |
| <TierBadge | |
| tier={contributor.tier} | |
| className="h-4 text-[10px] px-1.5 py-0" | |
| /> | |
| <span className="text-[10px] text-muted-foreground font-mono"> | |
| {contributor.totalScore.toLocaleString()} pts | |
| </span> | |
| </div> | |
| </div> | |
| </Link> | |
| ), | |
| )} | |
| <div className="p-2"> | |
| {contributors?.length ? contributors.map( | |
| (contributor: LeaderboardContributor, index: number) => ( | |
| <Link | |
| key={contributor.id} | |
| href={`/profile/${contributor.userId}`} | |
| className="flex items-center gap-3 px-4 py-3 hover:bg-muted/50 transition-colors border-b border-border/40 last:border-0 group" | |
| > | |
| <div className="flex-shrink-0 relative"> | |
| <Avatar className="h-9 w-9 border border-border/50"> | |
| <AvatarImage src={contributor.avatarUrl || undefined} /> | |
| <AvatarFallback> | |
| {contributor.displayName?.[0] ?? "?"} | |
| </AvatarFallback> | |
| </Avatar> | |
| <div className="absolute -top-1 -left-1 text-foreground flex items-center justify-center w-4 h-4 rounded-full bg-background border border-border text-[10px] font-bold"> | |
| {index + 1} | |
| </div> | |
| </div> | |
| <div className="flex-1 min-w-0"> | |
| <div className="flex items-center gap-2"> | |
| <span className="font-medium text-foreground text-sm truncate group-hover:text-muted-foreground transition-colors"> | |
| {contributor.displayName} | |
| </span> | |
| </div> | |
| <div className="flex items-center gap-2 mt-0.5"> | |
| <TierBadge | |
| tier={contributor.tier} | |
| className="h-4 text-[10px] px-1.5 py-0" | |
| /> | |
| <span className="text-[10px] text-muted-foreground font-mono"> | |
| {contributor.totalScore.toLocaleString()} pts | |
| </span> | |
| </div> | |
| </div> | |
| </Link> | |
| ), | |
| ) : ( | |
| <div className="px-4 py-6 text-center text-sm text-muted-foreground"> | |
| No contributors yet | |
| </div> | |
| )} | |
| <div className="p-2"> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@components/leaderboard/mini-leaderboard.tsx` around lines 73 - 110, The list
currently maps contributors and if the array is empty only the footer CTA is
shown; add an explicit empty-state render when contributors is an empty array by
checking contributors?.length === 0 and returning a small fallback block (e.g.,
centered message/icon and optional CTA) inside the component between the
contributors map and the footer CTA div so users see a clear "No contributors
yet" state instead of an apparent blank card; update the JSX around the
contributors?.map(...) and the subsequent <div className="p-2"> footer to
conditionally render the empty-state when contributors exists but has length 0.
| <Link | ||
| key={contributor.id} | ||
| href={`/profile/${contributor.userId}`} | ||
| className="flex items-center gap-3 px-4 py-3 hover:bg-muted/50 transition-colors border-b border-border/40 last:border-0 group" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Inspect Next.js app routes and leaderboard navigation targets.
# Expect: Either both /profile/[id] and /user/[id] routes exist intentionally,
# or MiniLeaderboard and LeaderboardPage use the same canonical route.
printf '\n== App route pages ==\n'
fd -i 'page\.(tsx|ts|jsx|js)$' app
printf '\n== Leaderboard/profile/user navigation references ==\n'
rg -n -C3 'href=\{?`/(profile|user)/|router\.push\(`/((profile|user))/' --type=tsx --type=tsRepository: boundlessfi/bounties
Length of output: 516
🏁 Script executed:
#!/bin/bash
# Read mini-leaderboard to verify href at lines 75-78
echo "=== mini-leaderboard.tsx lines 70-82 ==="
fd -i 'mini-leaderboard\.tsx' | xargs cat -n | sed -n '70,82p'
echo ""
echo "=== app/leaderboard/page.tsx lines 135-145 ==="
fd -i 'page\.tsx' app/leaderboard | xargs cat -n | sed -n '135,145p'
echo ""
echo "=== Search for /user/ and /profile/ hrefs without file type restrictions ==="
rg -n 'href.*/(profile|user)/' --max-count=20Repository: boundlessfi/bounties
Length of output: 1771
🏁 Script executed:
#!/bin/bash
# Search for any /user/ route definition
echo "=== Checking for /user/[userId] route ==="
fd -i 'page\.tsx' app/user 2>/dev/null || echo "No user directory found"
echo ""
echo "=== All user-related pages/routes ==="
fd 'page\.(tsx|ts)$' app | grep -i user
echo ""
echo "=== Verify /profile/ route exists ==="
fd 'page\.(tsx|ts)$' app | grep -i profileRepository: boundlessfi/bounties
Length of output: 267
Fix inconsistent profile route navigation in leaderboard.
The leaderboard page navigates to /user/${entry.contributor.userId} (line 138), but this route does not exist. The mini-leaderboard component correctly uses /profile/${contributor.userId}, which is the only defined profile route in the application. Update line 138 in app/leaderboard/page.tsx to use /profile/ to match the rest of the codebase and prevent broken navigation.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@components/leaderboard/mini-leaderboard.tsx` around lines 75 - 78, The
leaderboard page uses a wrong profile route for contributor links: change the
Link href that currently builds `/user/${entry.contributor.userId}` to
`/profile/${entry.contributor.userId}` so it matches the rest of the app; locate
the Link rendering that uses entry.contributor.userId in the leaderboard page
component and update the href string accordingly (keep the dynamic interpolation
and the existing key/props intact).
closes #106
Summary
This PR removes unused HTTP helpers from the shared Axios client and narrows the lib/api barrel exports. Bounty REST proxy routes under app/api/bounties/ (and related application/submission proxies) were already removed on main; this change finishes the cleanup on the client side and refreshes the lockfile after a full install.
Changes
lib/api/client.ts — Drop put, patch, and del (no callers). Keep apiClient as an internal implementation detail instead of exporting it.
lib/api/index.ts — Re-export only get and post from ./client.
package-lock.json — Updated via npm install so CI/local installs match resolved dependencies.
Summary by CodeRabbit
Bug Fixes
Refactor