Skip to content

Comments

feat: migrate bounty mutation hooks to GraphQL#108

Open
autonomy414941 wants to merge 7 commits intoboundlessfi:mainfrom
autonomy414941:feat/migrate-bounty-mutations-graphql-103
Open

feat: migrate bounty mutation hooks to GraphQL#108
autonomy414941 wants to merge 7 commits intoboundlessfi:mainfrom
autonomy414941:feat/migrate-bounty-mutations-graphql-103

Conversation

@autonomy414941
Copy link

@autonomy414941 autonomy414941 commented Feb 22, 2026

Summary

  • migrate hooks/use-bounty-mutations.ts write paths from REST bountiesApi calls to GraphQL mutation calls via fetcher
  • keep optimistic cache behavior for update/delete and preserve rollback/invalidation flow
  • implement useClaimBounty with the requested workaround by calling updateBounty with status: "IN_PROGRESS"
  • switch mutation cache invalidation/cancel logic to shared bountyKeys from @/lib/query/query-keys

Validation

  • npm run lint -- hooks/use-bounty-mutations.ts
  • pre-push next build (via hook) passed

Closes #103

Summary by CodeRabbit

  • Improvements
    • Faster, more responsive bounty actions with optimistic updates for create, update, delete, and claim—users see immediate feedback.
    • Better consistency between bounty lists and detail views with automatic refreshes after operations.
    • Safer error handling: changes are rolled back automatically if an operation fails.
  • Chores
    • Public hooks and interfaces remain unchanged for consumers.

@vercel
Copy link

vercel bot commented Feb 22, 2026

Someone is attempting to deploy a commit to the Threadflow Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link

coderabbitai bot commented Feb 22, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Replaces REST-based bounty mutations with GraphQL mutation fetchers (create, update, delete, claim workaround), adds GraphQL types and optimistic-status mapping, preserves external hook signatures, and keeps optimistic onMutate/onError/onSettled flows with updated cache invalidation keys. (48 words)

Changes

Cohort / File(s) Summary
Bounty Mutation Hook Migration
hooks/use-bounty-mutations.ts
Replaced REST calls with GraphQL mutation fetcher and mutation strings; added GraphQL input/output types and optimistic-status mapping; introduced internal helpers (create/update/delete/claim mutations); updated useCreateBounty/useUpdateBounty/useDeleteBounty/useClaimBounty to use GraphQL, implemented optimistic onMutate/onError/onSettled, and updated query invalidation and detail-cache cleanup.

Sequence Diagram(s)

sequenceDiagram
    participant UI
    participant Hook as useBounty* Hook
    participant Cache as QueryClient Cache
    participant GQL as GraphQL API

    UI->>Hook: trigger create/update/delete/claim
    Hook->>Cache: onMutate (optimistic update)
    Hook->>GQL: send GraphQL mutation via fetcher
    GQL-->>Hook: mutation response or error
    alt error
        Hook->>Cache: onError (revert optimistic change)
    else success
        Hook->>Cache: onSettled (invalidate / refresh queries)
    end
    Hook->>UI: resolve mutation promise
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • #100 — Migrating bounty hooks from REST to GraphQL; this PR implements that migration for mutation hooks and optimistic cache flows.
  • #103 — Specifies migrating bounty mutation hooks to GraphQL and preserving optimistic update patterns; this PR addresses those objectives.

Possibly related PRs

Poem

🐰 I hopped from REST into GraphQL light,

Mutations snug in paw, optimistic and bright.
I nudged the cache gently, then sent off the call,
If error then backtrack, if success — refresh all,
A tiny rabbit cheer for hooks that stand tall.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
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 (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: migrate bounty mutation hooks to GraphQL' directly and clearly describes the main change in the pull request.
Linked Issues check ✅ Passed The PR fulfills all coding requirements from #103: GraphQL mutations replace REST calls, optimistic updates are preserved with onMutate/onError/onSettled, cache invalidation uses shared bountyKeys, and claim flow is implemented with a dedicated claimBounty mutation.
Out of Scope Changes check ✅ Passed All changes are scoped to hooks/use-bounty-mutations.ts and directly address the requirements of migrating bounty mutations from REST to GraphQL without introducing unrelated functionality.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share

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: 1

🧹 Nitpick comments (1)
hooks/use-bounty-mutations.ts (1)

11-17: createBountyMutation returns a partial Bounty typed as a full Bounty.

The GraphQL query only selects id, but the function's return type is Bounty (via CreateBountyMutationResponse). Any consumer accessing fields beyond id on the mutation result will get undefined at runtime without a type error at compile time. The same pattern applies to updateBountyMutation (lines 19-27, 39-41) which only selects id, status, updatedAt.

Since useCreateBounty only invalidates on success and useUpdateBounty doesn't use the return value directly, this isn't breaking today, but it's a latent trap.

Consider using Pick<Bounty, 'id'> (and Pick<Bounty, 'id' | 'status' | 'updatedAt'> for update) for the response types, or expand the selection set to return all fields the Bounty type declares.

Also applies to: 35-37, 52-59

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hooks/use-bounty-mutations.ts` around lines 11 - 17, The mutation GraphQL
selection sets return only partial Bounty fields but the code currently types
the responses as full Bounty; update the type mappings to avoid lying about
available fields: either narrow the response types used by useCreateBounty and
useUpdateBounty to Pick<Bounty,'id'> and Pick<Bounty,'id'|'status'|'updatedAt'>
respectively, or expand the CREATE_BOUNTY_MUTATION and the update mutation
selection sets to include all Bounty fields you expect consumers to read; locate
CREATE_BOUNTY_MUTATION and the update mutation (and the hooks useCreateBounty /
useUpdateBounty) and apply the type change or selection-set expansion
consistently so runtime undefined access is prevented.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@hooks/use-bounty-mutations.ts`:
- Around line 170-183: The optimistic update in the onMutate handler mismatches
the actual mutation payload: updateBountyMutation is called with status
"IN_PROGRESS" but queryClient.setQueryData sets status "claimed", causing a UI
inconsistency; fix by setting the same status string in the optimistic update
(replace the "claimed" value with "IN_PROGRESS") or use a shared constant/enum
for bounty status and reference it in both updateBountyMutation and the
onMutate's setQueryData (see useMutation, onMutate, updateBountyMutation, and
bountyKeys.detail to locate the code).

---

Nitpick comments:
In `@hooks/use-bounty-mutations.ts`:
- Around line 11-17: The mutation GraphQL selection sets return only partial
Bounty fields but the code currently types the responses as full Bounty; update
the type mappings to avoid lying about available fields: either narrow the
response types used by useCreateBounty and useUpdateBounty to Pick<Bounty,'id'>
and Pick<Bounty,'id'|'status'|'updatedAt'> respectively, or expand the
CREATE_BOUNTY_MUTATION and the update mutation selection sets to include all
Bounty fields you expect consumers to read; locate CREATE_BOUNTY_MUTATION and
the update mutation (and the hooks useCreateBounty / useUpdateBounty) and apply
the type change or selection-set expansion consistently so runtime undefined
access is prevented.

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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@hooks/use-bounty-mutations.ts`:
- Around line 77-82: The deleteBountyMutation currently discards the fetched
DeleteBountyMutationResponse (which includes deleteBounty: boolean); change it
to return and validate that boolean like the other mutations (e.g.,
createBountyMutation/updateBountyMutation) — call fetcher to get the response,
check response.deleteBounty and if false throw an Error (or otherwise surface
failure) so callers (like useDeleteBounty's onMutate/onSettled) don’t silently
accept a soft failure; ensure the function signature and return match the other
mutation helpers and propagate the response or error accordingly.

---

Duplicate comments:
In `@hooks/use-bounty-mutations.ts`:
- Around line 35-36: The optimistic status constant
CLAIM_BOUNTY_OPTIMISTIC_STATUS currently uses "claimed" while the mutation
persists "IN_PROGRESS", causing a flash when useClaimBounty's onMutate writes
"claimed" to the cache and onSettled refetches "IN_PROGRESS"; fix this by
aligning the optimistic value with the server-persisted status—either change
CLAIM_BOUNTY_OPTIMISTIC_STATUS to CLAIM_BOUNTY_MUTATION_STATUS ("IN_PROGRESS")
or update useClaimBounty's onMutate to write CLAIM_BOUNTY_MUTATION_STATUS to the
detail cache (and if you later add a true claimBounty that returns "claimed",
normalize that response before cache writes).

@autonomy414941
Copy link
Author

autonomy414941 commented Feb 22, 2026

Maintainer update for #108:

Resolved items:

  1. deleteBountyMutation now validates the GraphQL acknowledgement and throws if deleteBounty is false (prevents silent soft-fail).
  2. Added an explicit inline note clarifying that optimistic claimed is the UI alias for GraphQL IN_PROGRESS to avoid status-semantics confusion in this migration.

Verification:

  • npm run lint -- hooks/use-bounty-mutations.ts
  • npm run build

Please reply with one word: accept or decline.
Payout path if accepted: merge this PR, then process payout through the bounty flow tied to #103 with the payment receipt/tx reference in the thread.

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.

🧹 Nitpick comments (1)
hooks/use-bounty-mutations.ts (1)

140-174: Consider removing the detail cache entry for the deleted bounty.

After a successful delete, the detail cache for that bounty ID remains. If anything references or navigates to it, stale data could briefly appear. An optional improvement:

Suggested addition in onSettled
     onSettled: () => {
       queryClient.invalidateQueries({ queryKey: bountyKeys.lists() });
+      // Prevent stale detail data from being served for the deleted bounty
+      // queryClient.removeQueries({ queryKey: bountyKeys.detail(id) });
     },

Note: this would require changing the onSettled signature to accept the id parameter:

-    onSettled: () => {
+    onSettled: (_data, _err, id) => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hooks/use-bounty-mutations.ts` around lines 140 - 174, The delete mutation
currently only updates the lists cache but leaves the deleted bounty's detail
cache stale; change the onSettled handler in the delete mutation to accept the
mutation variables (the id) and remove or clear the detail cache for that bounty
(use queryClient.removeQueries({ queryKey: bountyKeys.detail(id) }) or
queryClient.setQueryData(bountyKeys.detail(id), () => undefined)), keeping the
existing invalidateQueries for bountyKeys.lists(); update the onSettled
signature to receive the variables parameter (id) per React Query's (data,
error, variables, context) convention so you can target bountyKeys.detail(id).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@hooks/use-bounty-mutations.ts`:
- Around line 35-37: The optimistic status constant
CLAIM_BOUNTY_OPTIMISTIC_STATUS ("claimed") will be overwritten if responses
still contain the GraphQL status "IN_PROGRESS", so update the query-side
response transformation that hydrates the cache (e.g., the fetcher used by
useBounties / fetchBounties or any normalizeBountyResponse function) to map
GraphQL "IN_PROGRESS" → REST "claimed" before writing to the cache; ensure the
same mapping is applied in any generic response normalizer and in the onSettled
refetch path so the cached status matches CLAIM_BOUNTY_OPTIMISTIC_STATUS and
prevents a flicker.

---

Nitpick comments:
In `@hooks/use-bounty-mutations.ts`:
- Around line 140-174: The delete mutation currently only updates the lists
cache but leaves the deleted bounty's detail cache stale; change the onSettled
handler in the delete mutation to accept the mutation variables (the id) and
remove or clear the detail cache for that bounty (use
queryClient.removeQueries({ queryKey: bountyKeys.detail(id) }) or
queryClient.setQueryData(bountyKeys.detail(id), () => undefined)), keeping the
existing invalidateQueries for bountyKeys.lists(); update the onSettled
signature to receive the variables parameter (id) per React Query's (data,
error, variables, context) convention so you can target bountyKeys.detail(id).

@autonomy414941
Copy link
Author

Update pushed: d9f66d5

Change: clear stale detail cache for the deleted bounty ID in delete mutation onSettled via queryClient.removeQueries({ queryKey: bountyKeys.detail(id) }).

Commands run:

  • npm run lint -- hooks/use-bounty-mutations.ts
  • npm run build

Please reply with accept or decline, and include the payment receipt URL.

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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@hooks/use-bounty-mutations.ts`:
- Around line 43-54: Update the types and call sites to stop mixing REST-side
Bounty["status"] with GraphQL enums: introduce a new GraphQLBountyStatus type
matching the schema (OPEN | CLAIMED | CLOSED) and use it in
UpdateBountyMutationInput and UpdateBountyMutationResponse so the mutation input
and returned status reflect GraphQL's BountyStatus only; replace any uses of
Bounty["status"] and the union with CLAIM_BOUNTY_MUTATION_STATUS in those types,
update the typing of updateBountyMutation's response field referenced by
UpdateBountyMutationResponse to use GraphQLBountyStatus, and fix useClaimBounty
to call the dedicated claimBounty(id) mutation (or pass "CLAIMED" per
GraphQLBountyStatus) instead of calling updateBountyMutation with "IN_PROGRESS".

---

Duplicate comments:
In `@hooks/use-bounty-mutations.ts`:
- Around line 36-37: The optimistic status constant
CLAIM_BOUNTY_OPTIMISTIC_STATUS currently uses "claimed" which diverges from the
server's persisted "IN_PROGRESS"; change the optimistic value to "IN_PROGRESS"
(and update any duplicate occurrences around the other block at lines 188-194)
so the optimistic cache matches the server shape, or alternatively add a
normalized check helper (e.g., treatStatusEqual(statusA, statusB)) and update UI
branches to treat "claimed" and "IN_PROGRESS" as equivalent; locate and modify
the constant CLAIM_BOUNTY_OPTIMISTIC_STATUS and any code paths that set or read
the optimistic status to ensure consistency.

@autonomy414941
Copy link
Author

Update pushed: faa007f\n\nChanges:\n- aligned mutation-layer status typing to GraphQL status values via a dedicated GraphQLBountyStatus type\n- switched useClaimBounty to call dedicated GraphQL claimBounty mutation\n\nCommands run:\n- npm run lint -- hooks/use-bounty-mutations.ts\n- npm run build\n\nPlease reply with accept or decline, and include the payment receipt URL.

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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@hooks/use-bounty-mutations.ts`:
- Around line 205-208: The onSettled handler unconditionally calls
queryClient.removeQueries({ queryKey: bountyKeys.detail(id) }) even when the
delete fails; change onSettled (in the same mutation where onError restores list
data) to only remove the detail cache when the mutation succeeded by checking
the error/data parameters (e.g., only call queryClient.removeQueries when _err
is falsy or data is present), leaving the invalidateQueries({ queryKey:
bountyKeys.lists() }) behavior as-is.
- Line 9: Remove the duplicate bountyKeys export from hooks/use-bounties.ts and
update all imports to reference the canonical bountyKeys in
"@/lib/query/query-keys" (fix usages in hooks/use-infinite-bounties.ts,
hooks/use-bounty.ts, hooks/Use-bounty-detail.ts and lib/query/sync/handlers.ts)
so there is a single source that includes .infinite(); then in the
useDeleteBounty mutation handler (function useDeleteBounty) change the onSettled
logic that currently calls detailCache.removeQueries(...) unconditionally to
only clear the detail cache on success (or check the error argument and skip
removal when error is present) to avoid wiping a still-existing bounty on failed
deletes.

type PaginatedResponse,
} from "@/lib/api";
import { fetcher } from "@/lib/graphql/client";
import { bountyKeys } from "@/lib/query/query-keys";
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Search for all occurrences of bountyKeys to check for duplication
rg "bountyKeys" --type ts -B 2 -A 5

Repository: boundlessfi/bounties

Length of output: 17574


🏁 Script executed:

# Find and examine the UpdateBountyInput type definition
rg "type UpdateBountyInput|interface UpdateBountyInput" --type ts -A 8

Repository: boundlessfi/bounties

Length of output: 1266


🏁 Script executed:

# Check the complete structure of hooks/use-bounties.ts to see what it exports
fd "use-bounties.ts" --type f -x head -30 {}

Repository: boundlessfi/bounties

Length of output: 752


🏁 Script executed:

# Check the content of `@/lib/query/query-keys` to confirm bountyKeys definition there
fd "query-keys" --type ts -x cat {}

Repository: boundlessfi/bounties

Length of output: 233


🏁 Script executed:

# Find the updateBountySchema to understand UpdateBountyInput type structure
rg "updateBountySchema|const updateBountySchema" -A 15

Repository: boundlessfi/bounties

Length of output: 1525


🏁 Script executed:

# Check if hooks/use-bounties.ts was updated to import bountyKeys from the shared module
cat hooks/use-bounties.ts | head -20

Repository: boundlessfi/bounties

Length of output: 752


🏁 Script executed:

# Verify if both bountyKeys have the same structure (especially the .infinite method)
rg "infinite:" lib/query/query-keys.ts hooks/use-bounties.ts -B 2 -A 2

Repository: boundlessfi/bounties

Length of output: 565


🏁 Script executed:

# Check lib/query/sync/handlers.ts to see which bountyKeys it's importing
head -10 lib/query/sync/handlers.ts

Repository: boundlessfi/bounties

Length of output: 478


🏁 Script executed:

# Find createBountySchema to understand what UpdateBountyInput contains for status
rg "createBountySchema.*=" -A 20 lib/api/bounties.ts

Repository: boundlessfi/bounties

Length of output: 714


🏁 Script executed:

# Check if any code is using the .infinite method which differs between the two bountyKeys definitions
rg "bountyKeys\.infinite" --type-list | head -20

Repository: boundlessfi/bounties

Length of output: 453


🏁 Script executed:

# Verify the actual import pattern in hooks/use-infinite-bounties.ts
cat hooks/use-infinite-bounties.ts | head -20

Repository: boundlessfi/bounties

Length of output: 1016


🏁 Script executed:

# Check the bountySchema to understand what fields it has, especially status
rg "bountySchema\s*=" -A 25 lib/api/bounties.ts | head -35

Repository: boundlessfi/bounties

Length of output: 888


🏁 Script executed:

# Verify which files import bountyKeys from hooks/use-bounties (the old location) vs lib/query/query-keys (correct)
rg "from.*['\"]\.?/?use-bounties['\"]" --no-heading

Repository: boundlessfi/bounties

Length of output: 276


🏁 Script executed:

# Look at the exact lines around useDeleteBounty's onSettled to confirm the unconditional removeQueries
sed -n '200,215p' hooks/use-bounty-mutations.ts

Repository: boundlessfi/bounties

Length of output: 514


Remove the duplicate bountyKeys definition from hooks/use-bounties.ts; this file still exports its own version, while the canonical definition now lives in @/lib/query/query-keys.ts.

Multiple hooks and the sync handler still import from the old location in hooks/use-bounties.ts (e.g., hooks/use-infinite-bounties.ts, hooks/use-bounty.ts, hooks/Use-bounty-detail.ts, and critically lib/query/sync/handlers.ts). This creates two conflicting bountyKeys instances with different structure: the old one lacks the .infinite() method. Update all imports to use @/lib/query/query-keys instead, then delete the duplicate export from hooks/use-bounties.ts.

Additionally, in useDeleteBounty (line 205–208), the removeQueries call on the detail cache executes unconditionally in onSettled, which fires on both success and error. On error, this clears the cache for a bounty that still exists on the server. Consider removing the detail cache only on success, or add a check for error state.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hooks/use-bounty-mutations.ts` at line 9, Remove the duplicate bountyKeys
export from hooks/use-bounties.ts and update all imports to reference the
canonical bountyKeys in "@/lib/query/query-keys" (fix usages in
hooks/use-infinite-bounties.ts, hooks/use-bounty.ts, hooks/Use-bounty-detail.ts
and lib/query/sync/handlers.ts) so there is a single source that includes
.infinite(); then in the useDeleteBounty mutation handler (function
useDeleteBounty) change the onSettled logic that currently calls
detailCache.removeQueries(...) unconditionally to only clear the detail cache on
success (or check the error argument and skip removal when error is present) to
avoid wiping a still-existing bounty on failed deletes.

Comment on lines 205 to 208
onSettled: (_data, _err, id) => {
queryClient.removeQueries({ queryKey: bountyKeys.detail(id) });
queryClient.invalidateQueries({ queryKey: bountyKeys.lists() });
},
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

removeQueries fires unconditionally in onSettled, stripping the detail cache even on a failed deletion.

onSettled receives both data and error as parameters, so it fires on failure as well. When the delete mutation fails, onError (line 200) correctly restores the list data, but onSettled then calls queryClient.removeQueries({ queryKey: bountyKeys.detail(id) }) regardless. This evicts the detail cache entry for a bounty that still exists on the server, causing any mounted detail view to enter a loading state and trigger an unnecessary refetch.

🛠️ Proposed fix — gate `removeQueries` on success
-  onSettled: (_data, _err, id) => {
-    queryClient.removeQueries({ queryKey: bountyKeys.detail(id) });
-    queryClient.invalidateQueries({ queryKey: bountyKeys.lists() });
-  },
+  onSettled: (_data, _err, id) => {
+    if (!_err) {
+      queryClient.removeQueries({ queryKey: bountyKeys.detail(id) });
+    }
+    queryClient.invalidateQueries({ queryKey: bountyKeys.lists() });
+  },
📝 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.

Suggested change
onSettled: (_data, _err, id) => {
queryClient.removeQueries({ queryKey: bountyKeys.detail(id) });
queryClient.invalidateQueries({ queryKey: bountyKeys.lists() });
},
onSettled: (_data, _err, id) => {
if (!_err) {
queryClient.removeQueries({ queryKey: bountyKeys.detail(id) });
}
queryClient.invalidateQueries({ queryKey: bountyKeys.lists() });
},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hooks/use-bounty-mutations.ts` around lines 205 - 208, The onSettled handler
unconditionally calls queryClient.removeQueries({ queryKey:
bountyKeys.detail(id) }) even when the delete fails; change onSettled (in the
same mutation where onError restores list data) to only remove the detail cache
when the mutation succeeded by checking the error/data parameters (e.g., only
call queryClient.removeQueries when _err is falsy or data is present), leaving
the invalidateQueries({ queryKey: bountyKeys.lists() }) behavior as-is.

@autonomy414941
Copy link
Author

Pushed a0970f5 to address the latest 2026-02-22T20:37:43Z blockers.

Changes made:

  • Removed duplicate bountyKeys export from hooks/use-bounties.ts and switched affected imports to canonical @/lib/query/query-keys (hooks/use-infinite-bounties.ts, hooks/use-bounty.ts, hooks/Use-bounty-detail.ts, lib/query/sync/handlers.ts).
  • Updated useDeleteBounty onSettled to remove detail cache only when mutation succeeds (!_err).

Verification commands run:

  • npm run lint -- hooks/use-bounty-mutations.ts
  • npm run build

Please respond with one line: ACCEPT or DECLINE, and if ACCEPT include the payment receipt URL.

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.

Migrate bounty mutation hooks to GraphQL

1 participant