Feat/bounty selection flow model 2#200
Conversation
|
@legend4tech is attempting to deploy a commit to the Threadflow Team on Vercel. A member of the Team first needs to authorize it. |
|
@legend4tech 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! 🚀 |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughIntegrates a Model‑2 application flow for MILESTONE_BASED bounties: structured application/dialog with preview, creator review dashboard with comparison and selection, contributor submit-work panel, approval panel, and React Query hooks that call contract methods (apply/select/submit/approve). Changes
Sequence Diagram(s)sequenceDiagram
participant Contributor
participant Frontend
participant Contract as BountyRegistry
participant Creator
rect rgba(100, 150, 200, 0.5)
Note over Contributor,Frontend: Application Phase (OPEN)
Contributor->>Frontend: Open ApplicationDialog & submit proposal
Frontend->>Contract: apply(applicantAddress, bountyId, proposal)
Contract-->>Frontend: tx result / event
end
rect rgba(100, 200, 150, 0.5)
Note over Creator,Frontend: Review & Select Phase (OPEN)
Creator->>Frontend: Open ApplicationReviewDashboard
Creator->>Frontend: Select applicant (possibly compare two)
Frontend->>Contract: select_applicant(creatorAddress, bountyId, applicantAddress)
Contract-->>Frontend: tx result / event (assign + lock escrow)
end
rect rgba(200, 150, 100, 0.5)
Note over Contributor,Frontend: Submit Work (IN_PROGRESS)
Contributor->>Frontend: Open ApplicationSubmitWorkPanel, submit work CID
Frontend->>Contract: submit_work(contributorAddress, bountyId, workCid)
Contract-->>Frontend: tx result / event (status -> UNDER_REVIEW)
end
rect rgba(200, 100, 150, 0.5)
Note over Creator,Frontend: Approval Phase (UNDER_REVIEW)
Creator->>Frontend: Open SubmissionApprovalPanel, approve with points
Frontend->>Contract: approve_submission(creatorAddress, bountyId, points)
Contract-->>Frontend: tx result / event (release escrow / COMPLETED)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 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. Review rate limit: 0/1 reviews remaining, refill in 60 minutes.Comment |
There was a problem hiding this comment.
Actionable comments posted: 10
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
components/bounty/application-dialog.tsx (1)
33-40:⚠️ Potential issue | 🟠 MajorHarden portfolio URL validation to
http/httpsonly.Current validation accepts any URL scheme; for user-generated links, restrict protocols before rendering anchor tags.
Also applies to: 158-165
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/bounty/application-dialog.tsx` around lines 33 - 40, The portfolioUrl Zod schema currently allows any URL scheme; update its refine predicate (the portfolioUrl field in the z.string() schema) to only accept empty string or URLs whose protocol is either "http:" or "https:"—for example by parsing with the URL constructor and checking url.protocol === "http:" || url.protocol === "https:" or by explicitly validating startsWith("http://")/startsWith("https://"); apply the same change to the duplicate schema instance referenced around the 158-165 area so both validations consistently restrict to http/https before rendering anchor tags.
🧹 Nitpick comments (1)
components/bounty-detail/bounty-detail-sidebar-cta.tsx (1)
95-104: Consider deduplicating apply mutation wiring between desktop/mobile.
useApplyToBounty+handleApplyare repeated almost verbatim in both components. Extracting shared logic would reduce drift.Also applies to: 426-435
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/bounty-detail/bounty-detail-sidebar-cta.tsx` around lines 95 - 104, Duplicate wiring of the apply mutation occurs in both components: the useApplyToBounty hook + handleApply logic (using symbols useApplyToBounty, handleApply, ApplicationFormValues, applyToBounty, walletAddress, bounty.id). Extract this into a shared helper hook (e.g., useBountyApply or useApplyHandler) that calls useApplyToBounty internally and returns a memoized apply function (or mutateAsync) which accepts ApplicationFormValues and handles the walletAddress/bounty.id checks and JSON.stringify(proposal); replace the inline handleApply implementations in both desktop and mobile components with the shared hook to remove duplication and keep behavior identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@components/bounty-detail/bounty-detail-client.tsx`:
- Around line 182-185: The current fallback sets walletAddress using
session.user.id which can pass non-wallet IDs into contract actions; update the
logic so walletAddress is strictly derived from an actual wallet field (e.g.,
(session?.user as { walletAddress?: string })?.walletAddress) and remove the
fallback to session?.user?.id, and then gate UI/actions that call contract
mutations (places using creatorAddress/contributorAddress and functions that use
walletAddress in bounty actions) to require a non-empty walletAddress before
enabling or invoking contract calls.
- Around line 266-273: The submit-work panel is currently shown to any
non-creator while a bounty is IN_PROGRESS; restrict it to the actual selected
applicant by adding a check that the viewer's walletAddress matches the bounty's
selected applicant address before rendering ApplicationSubmitWorkPanel. Update
the condition that now uses bounty.type, !isCreator and bounty.status to also
require walletAddress === bounty.selectedApplicantAddress (or the actual
property name that holds the selected contributor, e.g.,
bounty.selectedApplicant or bounty.selectedContributor) so only the selected
contributor sees the submit-work UI for the given bountyId.
- Around line 71-109: The code is still using the MOCK_APPLICATIONS constant for
creator review/approval flows; replace uses of MOCK_APPLICATIONS in
bounty-detail-client.tsx (including the creator review/approval code paths
referenced around lines 71-109, 259-263, 281-283) with real
application/submission data from the app's data layer: call the appropriate
loader or hook (e.g., a function like loadApplicationsForBounty(bountyId) or
useBountyApplications(bountyId)) to fetch on-chain/off-chain state, map that
response into the Application shape used by the UI, and remove or gate the
MOCK_APPLICATIONS fallback so production uses live data only. Ensure components
that reference MOCK_APPLICATIONS (creator review UI, approval handlers) accept
the fetched data and handle loading/error states.
In `@components/bounty-detail/bounty-detail-sidebar-cta.tsx`:
- Around line 222-236: The "Apply for Bounty" milestone branch currently allows
creators to open the applicant flow; update the conditional around
ApplicationDialog (and the similar block later) to prevent bounty creators from
applying by adding an explicit creator check (e.g., && !isCreator or
walletAddress !== bounty.creatorAddress). Locate the branch using bounty.type
=== "MILESTONE_BASED" && canAct and modify it to require that the current
walletAddress is not the bounty owner (or use an existing isCreator boolean)
before rendering ApplicationDialog/trigger with handleApply and walletAddress.
In `@components/bounty/application-review-dashboard.tsx`:
- Around line 147-153: The portfolioUrl is used directly in the anchor href
(app.proposal.portfolioUrl) so validate its protocol before rendering to avoid
unsafe schemes; update the JSX around the anchor in
application-review-dashboard.tsx to parse/check the URL (e.g., using URL
constructor or a simple protocol regex) and only render the <a> tag when the
protocol is http: or https:, otherwise render a safe fallback (plain text or
nothing). Ensure you reference app.proposal.portfolioUrl in the check and keep
target="_blank" rel="noreferrer" only for validated links.
- Around line 117-123: The Decline button currently renders without any click
handler; wire it to the application-decline flow by adding an onClick that calls
the decline mutation (e.g., use the existing declineApplication or similar
mutation hook) with the application's id and handle UI state (disable while
loading, show toast/error). Update the Button in
components/bounty/application-review-dashboard.tsx (the element with <Button
...><XCircle ... /> Decline</Button>) to invoke the mutation, pass the correct
application identifier from the component props/state, and ensure you either
refetch or update the application list cache/optimistically remove the
application on success and surface errors to the user.
In `@components/bounty/application-submit-work-panel.tsx`:
- Around line 27-40: The form captures a description in the description state
but never sends it — causing silent loss; update the handleSubmit flow so that
the mutate returned from useSubmitApplicationWork (submitWork) is called with
the description included (e.g., add description to the payload alongside
bountyId, contributorAddress, workCid), and ensure any backend/contract
submission path used by submitWork (or its implementation in
useSubmitApplicationWork) is updated to accept and persist the description so
notes are actually stored and displayed.
In `@components/bounty/submission-approval-panel.tsx`:
- Around line 49-54: The approveSubmission call uses the raw points value from
the form which can be 0 or out-of-range; update the handlers (e.g.,
handleApprove and the other similar handlers around lines 117-124 and 130-137)
to parse the points as a number, clamp it to the allowed range (min > 0 and max
as defined by the UI or constants), and replace the direct points variable with
this validated/clamped value before calling approveSubmission (or the equivalent
mutation). Ensure you also enforce integer conversion (Math.floor or equivalent)
and use the same clamped value in the mutation payload so no invalid points are
submitted.
- Around line 57-63: The handleRequestRevisions function is currently a no-op;
replace the console-only behavior by calling a request revision mutation hook
(e.g., requestRevision or useRequestRevisionMutation) to persist the status
"REVISION_REQUESTED" and feedback, update local UI state
(setIsRequestingRevisions(false), clear feedback) on success, and handle errors
(show toast/error state) on failure; locate and wire the same mutation in the
other panel instance referenced around the block at lines ~187-195 so both
places call the mutation and update the submission status and UI consistently.
In `@hooks/use-bounty-application.ts`:
- Around line 178-188: The optimistic update in the onMutate handler of
useSubmitApplicationWork (in use-bounty-application.ts) sets bounty.status to
"IN_REVIEW", but the UI in components/bounty-detail/bounty-detail-client.tsx
checks for "UNDER_REVIEW"; change the optimistic status to "UNDER_REVIEW" so the
optimistic state matches downstream UI checks (update the status string in the
qc.setQueryData call for bounty.status and verify any other places in
useSubmitApplicationWork that reference the same status).
---
Outside diff comments:
In `@components/bounty/application-dialog.tsx`:
- Around line 33-40: The portfolioUrl Zod schema currently allows any URL
scheme; update its refine predicate (the portfolioUrl field in the z.string()
schema) to only accept empty string or URLs whose protocol is either "http:" or
"https:"—for example by parsing with the URL constructor and checking
url.protocol === "http:" || url.protocol === "https:" or by explicitly
validating startsWith("http://")/startsWith("https://"); apply the same change
to the duplicate schema instance referenced around the 158-165 area so both
validations consistently restrict to http/https before rendering anchor tags.
---
Nitpick comments:
In `@components/bounty-detail/bounty-detail-sidebar-cta.tsx`:
- Around line 95-104: Duplicate wiring of the apply mutation occurs in both
components: the useApplyToBounty hook + handleApply logic (using symbols
useApplyToBounty, handleApply, ApplicationFormValues, applyToBounty,
walletAddress, bounty.id). Extract this into a shared helper hook (e.g.,
useBountyApply or useApplyHandler) that calls useApplyToBounty internally and
returns a memoized apply function (or mutateAsync) which accepts
ApplicationFormValues and handles the walletAddress/bounty.id checks and
JSON.stringify(proposal); replace the inline handleApply implementations in both
desktop and mobile components with the shared hook to remove duplication and
keep behavior identical.
🪄 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: 3d6addd9-8622-477e-8968-918df3d66609
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (7)
components/bounty-detail/bounty-detail-client.tsxcomponents/bounty-detail/bounty-detail-sidebar-cta.tsxcomponents/bounty/application-dialog.tsxcomponents/bounty/application-review-dashboard.tsxcomponents/bounty/application-submit-work-panel.tsxcomponents/bounty/submission-approval-panel.tsxhooks/use-bounty-application.ts
| <Button | ||
| size="sm" | ||
| variant="outline" | ||
| className="border-red-500/30 text-red-400 hover:bg-red-500/10" | ||
| > | ||
| <XCircle className="size-4 mr-1" /> Decline | ||
| </Button> |
There was a problem hiding this comment.
Decline action is non-functional.
The Decline button is rendered but has no onClick/mutation wiring, so creators cannot reject applications from this dashboard.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@components/bounty/application-review-dashboard.tsx` around lines 117 - 123,
The Decline button currently renders without any click handler; wire it to the
application-decline flow by adding an onClick that calls the decline mutation
(e.g., use the existing declineApplication or similar mutation hook) with the
application's id and handle UI state (disable while loading, show toast/error).
Update the Button in components/bounty/application-review-dashboard.tsx (the
element with <Button ...><XCircle ... /> Decline</Button>) to invoke the
mutation, pass the correct application identifier from the component
props/state, and ensure you either refetch or update the application list
cache/optimistically remove the application on success and surface errors to the
user.
| const [workCid, setWorkCid] = useState(""); | ||
| const [description, setDescription] = useState(""); | ||
|
|
||
| const { mutate: submitWork, isPending } = useSubmitApplicationWork(); | ||
|
|
||
| const handleSubmit = (e: React.FormEvent) => { | ||
| e.preventDefault(); | ||
| if (!workCid.trim()) return; | ||
|
|
||
| submitWork({ | ||
| bountyId, | ||
| contributorAddress, | ||
| workCid, | ||
| }); |
There was a problem hiding this comment.
“Notes for the Creator” is currently discarded.
The component captures description, but submitWork(...) only sends workCid. This creates silent data loss and misleading UI.
Suggested direction
- const [description, setDescription] = useState("");
+ // Remove notes field until a persistence path existsor extend the submission payload path (contract/off-chain) so notes are actually persisted/displayed.
Also applies to: 79-90
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@components/bounty/application-submit-work-panel.tsx` around lines 27 - 40,
The form captures a description in the description state but never sends it —
causing silent loss; update the handleSubmit flow so that the mutate returned
from useSubmitApplicationWork (submitWork) is called with the description
included (e.g., add description to the payload alongside bountyId,
contributorAddress, workCid), and ensure any backend/contract submission path
used by submitWork (or its implementation in useSubmitApplicationWork) is
updated to accept and persist the description so notes are actually stored and
displayed.
| const handleRequestRevisions = () => { | ||
| // In a full implementation, this would trigger a different mutation | ||
| // that sets the status to "REVISION_REQUESTED" and records the feedback | ||
| console.log("Requesting revisions with feedback:", feedback); | ||
| setIsRequestingRevisions(false); | ||
| setFeedback(""); | ||
| }; |
There was a problem hiding this comment.
Revision request flow is still a no-op.
handleRequestRevisions only logs feedback and resets local state. This does not transition status or persist feedback, so the revision workflow is not actually implemented.
I can draft a request_revision mutation hook + panel wiring if you want me to open a follow-up issue template.
Also applies to: 187-195
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@components/bounty/submission-approval-panel.tsx` around lines 57 - 63, The
handleRequestRevisions function is currently a no-op; replace the console-only
behavior by calling a request revision mutation hook (e.g., requestRevision or
useRequestRevisionMutation) to persist the status "REVISION_REQUESTED" and
feedback, update local UI state (setIsRequestingRevisions(false), clear
feedback) on success, and handle errors (show toast/error state) on failure;
locate and wire the same mutation in the other panel instance referenced around
the block at lines ~187-195 so both places call the mutation and update the
submission status and UI consistently.
Benjtalkshow
left a comment
There was a problem hiding this comment.
Solid architecture overall. The contract hooks mirror the use-competition-bounty.ts pattern, the application dialog uses FormFieldWrapper and the preview step is a nice touch, and the optimistic updates with rollback are clean. CI green and typecheck clean.
A few items before merge.
The review dashboard is fed by a hardcoded MOCK_APPLICATIONS array at bounty-detail-client.tsx:72-109. So a creator opening any MILESTONE_BASED bounty in OPEN will always see the same two fake Alice/Bob entries no matter what. Same anti-pattern PRs #178 and #186 had to remove. Either source the list from bounty.submissions (or whichever GraphQL field will hold applications once the contract events sync), or render an empty state until that's wired. Don't ship hardcoded fake data into the production UI.
Same goes for the approval panel: submittedWorkCid="QmHash123MockedWorkCid" and submissionDescription="I have completed the feature..." are passed as literal props at bounty-detail-client.tsx:281-282. Pull these from the real submission record or block the panel from rendering until they exist.
Decline button at application-review-dashboard.tsx:117-123 has no onClick. Either wire it to a real mutation or label it [Coming soon] and disable it.
Request Revisions at submission-approval-panel.tsx:57-63 only does console.log and resets local state. The // In a full implementation... comment confirms it's a stub. Same pattern, please disable with [Coming soon] or hide until the mutation exists.
The optimistic update on submit_work writes status "IN_REVIEW" at use-bounty-application.ts:186, but the repo's BountyStatus enum uses "UNDER_REVIEW". The optimistic state will diverge from what the backend returns. Use UNDER_REVIEW.
Minor: PR title formatting Feat/bounty selection flow model 2 — please clean it up. And the points field at submission-approval-panel.tsx defaults to 5 with no tier guidance, leaving the creator guessing what's typical. A small hint or a tier-based default would help.
Please address all CodeRabbit findings as well.
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
components/bounty-detail/bounty-detail-client.tsx (1)
155-161:⚠️ Potential issue | 🟠 Major
isAssignedApplicantlogic is unreliable and overly permissive.The predicate has multiple issues:
assignedContributorIddoes not exist on theBountytype (seetypes/bounty.ts:86-119), so the type assertion silently fails.- The final fallback
(!isCreator && bounty.status === "IN_PROGRESS")allows any non-creator to pass when the bounty is in progress, not just the selected contributor.This means the
ApplicationSubmitWorkPanelat lines 242-250 may render for users who aren't the assigned applicant.🛠️ Suggested approach
Add
assignedContributorId(or similar) to theBountytype and ensure the backend populates it. Until then, consider a stricter fallback:- const isAssignedApplicant = - (bounty as BountyData & { assignedContributorId?: string }) - ?.assignedContributorId === session?.user?.id || - bounty.submissions?.some((s) => s.submittedBy === session?.user?.id) || - (!isCreator && bounty.status === "IN_PROGRESS"); + // Require explicit assignment data; fallback to submissions check only + const assignedContributorId = (bounty as BountyData & { assignedContributorId?: string }) + ?.assignedContributorId; + const isAssignedApplicant = + (assignedContributorId && assignedContributorId === session?.user?.id) || + bounty.submissions?.some((s) => s.submittedBy === session?.user?.id);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/bounty-detail/bounty-detail-client.tsx` around lines 155 - 161, The isAssignedApplicant predicate is too permissive and uses a silent type assertion for a non-existent assignedContributorId on Bounty; update the Bounty type to include assignedContributorId (or a backend-populated equivalent) and ensure the backend returns it, then change the isAssignedApplicant logic (used to gate ApplicationSubmitWorkPanel and related UI) to: 1) avoid casting (remove the (bounty as BountyData & { assignedContributorId?: string }) assertion), 2) check assignedContributorId strictly against session.user.id if present, and 3) remove the broad fallback that treats any non-creator as assigned when bounty.status === "IN_PROGRESS" (or replace it with a conservative check such as membership in bounty.submissions or an explicit contributor list).
🧹 Nitpick comments (1)
components/bounty/application-review-dashboard.tsx (1)
51-57: Add user feedback for applicant selection outcome.
handleSelectApplicantfires the mutation but provides no success/error feedback to the user. For a critical action like selecting a contributor, users should see confirmation (toast/alert) on success or an error message on failure.💡 Example with toast feedback
+ import { toast } from "@/components/ui/use-toast"; // or your toast library const handleSelectApplicant = (applicantAddress: string) => { selectApplicant( { bountyId, creatorAddress, applicantAddress, }, + { + onSuccess: () => { + toast({ title: "Applicant selected", description: "The bounty is now in progress." }); + }, + onError: (error) => { + toast({ title: "Selection failed", description: error.message, variant: "destructive" }); + }, + } ); };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/bounty/application-review-dashboard.tsx` around lines 51 - 57, handleSelectApplicant currently fires the selectApplicant mutation without user feedback; update it to await the mutation call (selectApplicant) and show a success toast/alert on resolved promise (including context like applicantAddress and bountyId) and show an error toast/alert when the mutation rejects (displaying the error message). Use any existing UI toast/notification helper in the component (or add one) and ensure you handle loading state (disable UI while pending) so users get clear success/error feedback for the selectApplicant({ bountyId, creatorAddress, applicantAddress }) action.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@components/bounty-detail/bounty-detail-client.tsx`:
- Around line 231-240: The creator-only panels render even when walletAddress is
empty; update the gating conditions for ApplicationReviewDashboard and
SubmissionApprovalPanel to require a non-empty walletAddress (e.g., add
walletAddress && to the existing conditional that checks bounty.type, isCreator,
and bounty.status) so they only render when a connected wallet exists, and
continue passing walletAddress as creatorAddress into those components
(ApplicationReviewDashboard, SubmissionApprovalPanel).
- Around line 258-260: The prop submittedWorkCid is receiving
githubPullRequestUrl (a URL) causing an IPFS CID/type mismatch; add a new field
workCid to the BountySubmission type in types/bounty.ts, populate it wherever
BountySubmission instances are created/returned, and update the component usage
in bounty-detail-client.tsx to pass bounty.submissions?.[0]?.workCid (not
githubPullRequestUrl) into SubmissionApprovalPanel's submittedWorkCid prop; also
audit any consumers (e.g., SubmissionApprovalPanel prop types/usage) and
submission creation code to ensure workCid is typed/filled and
githubPullRequestUrl remains unchanged.
---
Duplicate comments:
In `@components/bounty-detail/bounty-detail-client.tsx`:
- Around line 155-161: The isAssignedApplicant predicate is too permissive and
uses a silent type assertion for a non-existent assignedContributorId on Bounty;
update the Bounty type to include assignedContributorId (or a backend-populated
equivalent) and ensure the backend returns it, then change the
isAssignedApplicant logic (used to gate ApplicationSubmitWorkPanel and related
UI) to: 1) avoid casting (remove the (bounty as BountyData & {
assignedContributorId?: string }) assertion), 2) check assignedContributorId
strictly against session.user.id if present, and 3) remove the broad fallback
that treats any non-creator as assigned when bounty.status === "IN_PROGRESS" (or
replace it with a conservative check such as membership in bounty.submissions or
an explicit contributor list).
---
Nitpick comments:
In `@components/bounty/application-review-dashboard.tsx`:
- Around line 51-57: handleSelectApplicant currently fires the selectApplicant
mutation without user feedback; update it to await the mutation call
(selectApplicant) and show a success toast/alert on resolved promise (including
context like applicantAddress and bountyId) and show an error toast/alert when
the mutation rejects (displaying the error message). Use any existing UI
toast/notification helper in the component (or add one) and ensure you handle
loading state (disable UI while pending) so users get clear success/error
feedback for the selectApplicant({ bountyId, creatorAddress, applicantAddress })
action.
🪄 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: 2753e918-2a68-4706-9bbc-41346ebcfffc
📒 Files selected for processing (7)
components/bounty-detail/bounty-detail-client.tsxcomponents/bounty-detail/bounty-detail-sidebar-cta.tsxcomponents/bounty/application-dialog.tsxcomponents/bounty/application-review-dashboard.tsxcomponents/bounty/application-submit-work-panel.tsxcomponents/bounty/submission-approval-panel.tsxhooks/use-bounty-application.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- components/bounty/application-submit-work-panel.tsx
- components/bounty-detail/bounty-detail-sidebar-cta.tsx
- components/bounty/submission-approval-panel.tsx
- hooks/use-bounty-application.ts
| {/* Model 2 Application Flow integration */} | ||
| {bounty.type === "MILESTONE_BASED" && | ||
| isCreator && | ||
| bounty.status === "OPEN" && ( | ||
| <ApplicationReviewDashboard | ||
| bountyId={bountyId} | ||
| creatorAddress={walletAddress} | ||
| applications={getApplications(bounty)} | ||
| /> | ||
| )} |
There was a problem hiding this comment.
Gate creator panels on non-empty walletAddress to prevent invalid contract calls.
ApplicationReviewDashboard (line 237) and SubmissionApprovalPanel (line 257) receive walletAddress as creatorAddress without verifying it's non-empty. If the user's wallet isn't connected, these panels will render but contract mutations will fail or behave unexpectedly.
🔧 Proposed fix
{bounty.type === "MILESTONE_BASED" &&
isCreator &&
+ walletAddress &&
bounty.status === "OPEN" && (
<ApplicationReviewDashboard
...
/>
)}
{bounty.type === "MILESTONE_BASED" &&
isCreator &&
+ walletAddress &&
bounty.status === "UNDER_REVIEW" && (
<SubmissionApprovalPanel
...
/>
)}Also applies to: 252-262
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@components/bounty-detail/bounty-detail-client.tsx` around lines 231 - 240,
The creator-only panels render even when walletAddress is empty; update the
gating conditions for ApplicationReviewDashboard and SubmissionApprovalPanel to
require a non-empty walletAddress (e.g., add walletAddress && to the existing
conditional that checks bounty.type, isCreator, and bounty.status) so they only
render when a connected wallet exists, and continue passing walletAddress as
creatorAddress into those components (ApplicationReviewDashboard,
SubmissionApprovalPanel).
| submittedWorkCid={ | ||
| bounty.submissions?.[0]?.githubPullRequestUrl || undefined | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if BountySubmission type has a dedicated CID field
rg -n 'workCid|ipfsCid|deliverableCid' --type=ts types/Repository: boundlessfi/bounties
Length of output: 46
🏁 Script executed:
# Find and examine the BountySubmission type definition
fd -t f 'bounty.ts' types/Repository: boundlessfi/bounties
Length of output: 80
🏁 Script executed:
# Check the context around the submittedWorkCid prop in the component
rg -B5 -A5 'submittedWorkCid=' components/bounty-detail/bounty-detail-client.tsxRepository: boundlessfi/bounties
Length of output: 400
🏁 Script executed:
# Search for BountySubmission type definition and related fields
rg -n 'type BountySubmission|interface BountySubmission' --type=tsRepository: boundlessfi/bounties
Length of output: 310
🏁 Script executed:
# Search for githubPullRequestUrl usage to understand the field's purpose
rg -n 'githubPullRequestUrl' --type=ts -B2 -A2 | head -50Repository: boundlessfi/bounties
Length of output: 2507
🏁 Script executed:
# Read the full BountySubmission interface
sed -n '51,65p' types/bounty.tsRepository: boundlessfi/bounties
Length of output: 509
🏁 Script executed:
# Find and examine the SubmissionApprovalPanel component
fd -t f 'SubmissionApprovalPanel' components/Repository: boundlessfi/bounties
Length of output: 46
🏁 Script executed:
# Search for IPFS or CID references in the codebase
rg -n 'ipfs|cid|CID' --type=ts components/ -i | head -30Repository: boundlessfi/bounties
Length of output: 2654
🏁 Script executed:
# Search for SubmissionApprovalPanel component definition
rg -n 'SubmissionApprovalPanel' --type=ts -A 20 | head -50Repository: boundlessfi/bounties
Length of output: 4534
🏁 Script executed:
# Search for submittedWorkCid prop usage throughout codebase
rg -n 'submittedWorkCid' --type=ts -B 2 -A 2Repository: boundlessfi/bounties
Length of output: 1841
🏁 Script executed:
# Look for where githubPullRequestUrl is actually used/set to understand field purpose
rg -n 'githubPullRequestUrl' --type=ts -B 3 -A 3 | head -100Repository: boundlessfi/bounties
Length of output: 5494
submittedWorkCid receives githubPullRequestUrl — incompatible types.
The SubmissionApprovalPanel expects submittedWorkCid to be an IPFS CID (it constructs https://ipfs.io/ipfs/${submittedWorkCid}), but the code passes bounty.submissions?.[0]?.githubPullRequestUrl, which is a GitHub PR URL. This mismatch breaks the IPFS link rendering.
Add a dedicated workCid field to BountySubmission in types/bounty.ts to store the actual IPFS CID separately from githubPullRequestUrl.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@components/bounty-detail/bounty-detail-client.tsx` around lines 258 - 260,
The prop submittedWorkCid is receiving githubPullRequestUrl (a URL) causing an
IPFS CID/type mismatch; add a new field workCid to the BountySubmission type in
types/bounty.ts, populate it wherever BountySubmission instances are
created/returned, and update the component usage in bounty-detail-client.tsx to
pass bounty.submissions?.[0]?.workCid (not githubPullRequestUrl) into
SubmissionApprovalPanel's submittedWorkCid prop; also audit any consumers (e.g.,
SubmissionApprovalPanel prop types/usage) and submission creation code to ensure
workCid is typed/filled and githubPullRequestUrl remains unchanged.
|
@Benjtalkshow can u review again? made a new commit |
On it |
Leftover from before Request Revisions was replaced with the disabled Coming Soon button.
Benjtalkshow
left a comment
There was a problem hiding this comment.
All five items from the previous round are clean. Mock data gone, hardcoded submission gone, Decline removed, Request Revisions disabled with Coming Soon, status enum fixed. The bonus fixes are nice too.
Pushed a small cleanup (69e6e82) on your branch removing the unused feedback / isRequestingRevisions state in submission-approval-panel.tsx left over from the rewrite. Lint is clean now.
Merging this in.
Feature: Complete Application-Based Bounty Selection Flow (Model 2)
Closes #146
Overview
This PR completes the frontend implementation for the Application-Based Bounty Selection Flow (Model 2). It builds upon the partial implementation to introduce a robust, end-to-end lifecycle for contributors applying to a bounty and creators reviewing, selecting, and approving those applications.
Key Changes
Expanded Application Form (
application-dialog.tsx)Creator Review Dashboard (
application-review-dashboard.tsx)select_applicantcontract call.Work Submission (
application-submit-work-panel.tsx)submit_workon-chain interaction.Creator Approval Panel (
submission-approval-panel.tsx)approve_submissioncontract call to release the escrow.Contract Hooks (
use-bounty-application.ts)useMutationwrappers forapply,select_applicant,submit_work, andapprove_submission.Bounty Detail Integration
BountyDetailClientand theSidebarCTA/MobileCTAto ensure the correct views render based on the current user's role (Creator vs. Applicant) and the bounty's status.Testing Instructions
MILESTONE_BASED) bounty in theOPENstate.Summary by CodeRabbit
New Features
Bug Fixes / UX