Skip to content

Split bounty detail CTA components and share state hook - #224

Closed
18060910075zx-coder wants to merge 4 commits into
boundlessfi:mainfrom
18060910075zx-coder:split-bounty-detail-cta
Closed

Split bounty detail CTA components and share state hook#224
18060910075zx-coder wants to merge 4 commits into
boundlessfi:mainfrom
18060910075zx-coder:split-bounty-detail-cta

Conversation

@18060910075zx-coder

@18060910075zx-coder 18060910075zx-coder commented May 27, 2026

Copy link
Copy Markdown

Summary

Closes #209.

Splits bounty-detail-sidebar-cta.tsx into separate desktop/mobile CTA files and moves the shared state/action logic into use-bounty-cta-state.ts.

Changes

  • bounty-detail-sidebar-cta.tsx now exports only SidebarCTA
  • Added bounty-detail-mobile-cta.tsx exporting MobileCTA
  • Added use-bounty-cta-state.ts for shared CTA state and handlers:
    • session/creator checks
    • cancel dialog state and handler
    • competition join state
    • milestone application handler
    • copy-link state
    • dispute/cancel availability
  • Updated bounty-detail-client.tsx to import MobileCTA from the new file
  • Removed the existing duplicate variant="outline" prop and duplicated deadline helper block while preserving the rendered behavior

Verification

  • File line counts after split:
    • bounty-detail-sidebar-cta.tsx: 296 lines
    • bounty-detail-mobile-cta.tsx: 184 lines
    • use-bounty-cta-state.ts: 120 lines
  • Confirmed shared state/handler duplication moved into the hook
  • Checked braces/parentheses balance across changed TSX files

Notes

I could not run the full local app test suite because cloning/installing dependencies from GitHub/npm is intermittently timing out in this environment, so this PR is scoped to the requested component split with static verification.

Summary by CodeRabbit

  • New Features
    • Added mobile-optimized bounty call-to-action display with support for FCFS claims, competition joins, bounty applications, disputes, and cancellations with confirmation dialogs.

Review Change Stack

@vercel

vercel Bot commented May 27, 2026

Copy link
Copy Markdown

@18060910075zx-coder is attempting to deploy a commit to the Threadflow Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR refactors the bounty call-to-action (CTA) components by extracting shared state logic into a new useBountyCTAState hook, splitting MobileCTA into its own file, and simplifying both sidebar and mobile components to eliminate duplication.

Changes

CTA state extraction and component split

Layer / File(s) Summary
Shared CTA state hook: types and implementation
components/bounty-detail/use-bounty-cta-state.ts
Introduces useBountyCTAState hook that centralizes eligibility checks, action handlers (join, apply, cancel, copy, dispute), dialog state, and CTA label computation. Exports SidebarBounty type and BountyCTAProps interface for component consumption.
SidebarCTA refactoring to consume shared hook
components/bounty-detail/bounty-detail-sidebar-cta.tsx
Refactors SidebarCTA to replace ~318 lines of duplicated inline state/hooks with useBountyCTAState consumption. Updates desktop cancel dialog layout, adds section separators, cleans JSX comments, and updates button labels.
New MobileCTA component using shared hook
components/bounty-detail/bounty-detail-mobile-cta.tsx
Creates MobileCTA component (184 lines) that consumes useBountyCTAState to render mobile-specific UI with conditional branches for FCFS claim, competition join, milestone application, default issue action, dispute button (disabled), and cancel dialog.
Client component import updates
components/bounty-detail/bounty-detail-client.tsx
Splits the SidebarCTA/MobileCTA import into two statements, sourcing MobileCTA from the new bounty-detail-mobile-cta.tsx file.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • boundlessfi/bounties#88: Introduced the original bounty-detail-sidebar-cta.tsx file with both SidebarCTA and MobileCTA components.
  • boundlessfi/bounties#170: Added cancellation & refund UI flow with onCancelled prop that is now centralized in useBountyCTAState.
  • boundlessfi/bounties#200: Introduced milestone "Apply for Bounty" flow that is now managed by the shared hook.

Suggested reviewers

  • Benjtalkshow

Poem

🐰 A hook now holds what two components shared,
No more duplication, no more merge despair!
MobileCTA spins off with grace and ease,
While SidebarCTA leans on useBountyCTAState's keys.
Three files, one truth—the bounty CTAs align! 🎉

🚥 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 title accurately summarizes the main change: splitting bounty detail CTA components and extracting shared state into a hook.
Linked Issues check ✅ Passed All requirements from issue #209 are met: components split into separate files, shared hook created with all needed state/handlers, no duplicated logic, each file under 300 lines, and bounty-detail-client.tsx updated.
Out of Scope Changes check ✅ Passed All changes directly align with issue #209 objectives: component split, hook extraction, and import updates with no unrelated modifications introduced.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@components/bounty-detail/bounty-detail-mobile-cta.tsx`:
- Around line 142-170: The mobile cancel dialog preserves the previous
cancelReason after closing; update the dialog close flow so cancelReason is
cleared when the dialog closes. In the AlertDialog controlled by
cancelDialogOpen (onOpenChange={setCancelDialogOpen}), detect when open becomes
false and call setCancelReason('') (or reset to initial value); alternatively
add an effect that watches cancelDialogOpen and resets cancelReason when it
transitions to false. Ensure this reset runs only on close and keep existing
isCancelling checks intact so the textarea and buttons behave correctly.
🪄 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: f5935444-4615-42fa-96ff-94c863e25b32

📥 Commits

Reviewing files that changed from the base of the PR and between ede3b20 and 8ae3696.

📒 Files selected for processing (4)
  • components/bounty-detail/bounty-detail-client.tsx
  • components/bounty-detail/bounty-detail-mobile-cta.tsx
  • components/bounty-detail/bounty-detail-sidebar-cta.tsx
  • components/bounty-detail/use-bounty-cta-state.ts

Comment on lines +142 to +170
<AlertDialog open={cancelDialogOpen} onOpenChange={setCancelDialogOpen}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle className="flex items-center gap-2 text-red-400">
<XCircle className="size-5" />
Cancel Bounty
</AlertDialogTitle>
<AlertDialogDescription>
This will cancel the bounty and refund escrowed funds. This action
cannot be undone.
</AlertDialogDescription>
</AlertDialogHeader>
<div className="space-y-2">
<Label htmlFor="mobile-cancel-reason">
Reason <span className="text-red-400">*</span>
</Label>
<Textarea
id="mobile-cancel-reason"
placeholder="Reason for cancellation..."
value={cancelReason}
onChange={(e) => setCancelReason(e.target.value)}
className="min-h-20"
disabled={isCancelling}
/>
</div>
<AlertDialogFooter>
<AlertDialogCancel disabled={isCancelling}>
Keep Bounty
</AlertDialogCancel>

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 | 🟡 Minor | ⚡ Quick win

Reset cancelReason on mobile dialog close to avoid stale destructive state.

The mobile cancel dialog currently preserves the previous reason after close, which can reopen with pre-filled state and an already-enabled destructive button.

Proposed fix
-      <AlertDialog open={cancelDialogOpen} onOpenChange={setCancelDialogOpen}>
+      <AlertDialog
+        open={cancelDialogOpen}
+        onOpenChange={(open) => {
+          setCancelDialogOpen(open);
+          if (!open) setCancelReason("");
+        }}
+      >
@@
-            <AlertDialogCancel disabled={isCancelling}>
+            <AlertDialogCancel
+              disabled={isCancelling}
+              onClick={() => setCancelReason("")}
+            >
🤖 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 `@components/bounty-detail/bounty-detail-mobile-cta.tsx` around lines 142 -
170, The mobile cancel dialog preserves the previous cancelReason after closing;
update the dialog close flow so cancelReason is cleared when the dialog closes.
In the AlertDialog controlled by cancelDialogOpen
(onOpenChange={setCancelDialogOpen}), detect when open becomes false and call
setCancelReason('') (or reset to initial value); alternatively add an effect
that watches cancelDialogOpen and resets cancelReason when it transitions to
false. Ensure this reset runs only on close and keep existing isCancelling
checks intact so the textarea and buttons behave correctly.

@18060910075zx-coder

Copy link
Copy Markdown
Author

Thanks for reviewing. I saw this was closed without a note; I pushed the CodeRabbit fix for the stale mobile cancel reason. If there are project-specific reasons this should stay closed, no worries, but if changes are needed I can adjust quickly.

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.

Split bounty-detail-sidebar-cta.tsx into SidebarCTA and MobileCTA files

2 participants