Integrate treasury management, refactor bounty UI, and enhance crowdfunding features#665
Conversation
…rchestration and API client architecture.
…eceipts/send Winners: new task-first Winners section (pick winner per prize with engine default, inline stacking confirm, deliberate 'Don't award' + unawarded-funds acknowledgement); /rewards redirects to /winners; staged Pick -> Confirm -> Pay. Judging: slimmed Results tab to read-only standings + 'Go to Winners'; criterionId name fix; AI scorecards, recommendation thresholds, CSV judge import, tracks + custom questions wizard sections; validation + empty-state polish. Public: private + password access gate, community links, card private badge. Treasury: receipts + Send funds. Removed the stacking toggle from prize setup. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…599) (#611) The net-new bounty UI with no hackathon analog: the two-axis mode picker and the mode-conditional submission settings that drive all six combinations. - modeSchema.ts: plain taxonomy unions (entryType x claimType), the computeBountyModeLabel helper, and getModeFields — the mode -> field matrix derived functionally from the publish gate (validateTwoAxisMode) so it cannot drift from the backend. - submissionModelSchema.ts: makeSubmissionModelSchema(mode), a mode-aware Zod factory whose required fields and the >=2 floors (maxApplicants for open competition, shortlistSize for application competition) mirror the server gate. - ModeTab.tsx: entry x claim picker, a winners stepper (1-3) for competitions, and a live computed mode label. - SubmissionModelTab.tsx: renders each field per the matrix (required / optional / hidden) and shows submissionVisibility read-only, forced by the mode (HIDDEN_UNTIL_DEADLINE for competitions). Standalone components (props: mode, onSave, onContinue, initialData, isLoading); they wire into the wizard shell + routes in #597 / #598.
…ow) (#596) (#612) Adds the features/bounties/ data layer for the v1 app, mirroring features/hackathons/. REST-only via the typed openapi-fetch client; every server shape is aliased from the backend-generated schema so it cannot drift. - types.ts: aliases the generated draft + escrow DTOs (BountyDraft, UpdateBountyDraftBody, the four section types, BountyEscrowOpResponse, PublishBountyEscrowRequest, ...). Derives the two-axis taxonomy from the generated mode DTO, superseding the local stubs in the ModeTab. - api/keys.ts: bountyKeys factory. - api/draft-client.ts + use-draft.ts: imperative CRUD plus the useDraft / useDraftList / useCreateDraft / useUpdateDraft / useDeleteDraft hooks against /organizations/{organizationId}/bounties/draft[/{id}] + /drafts. - api/escrow-client.ts + use-escrow.ts: organizer escrow calls (publish / cancel / select-winners / submit-signed / poll) plus useEscrowOp + useEscrowOpRunner, mirroring the hackathon machinery (MANAGED polls; EXTERNAL signs -> submit -> poll) bounty-scoped. - index.ts: public surface. Regenerates lib/api/generated/schema.d.ts from the v2 backend so the bounty draft paths/DTOs are present.
* feat(bounty): features/bounties data layer (types, keys, draft + escrow) (#596) Adds the features/bounties/ data layer for the v1 app, mirroring features/hackathons/. REST-only via the typed openapi-fetch client; every server shape is aliased from the backend-generated schema so it cannot drift. - types.ts: aliases the generated draft + escrow DTOs (BountyDraft, UpdateBountyDraftBody, the four section types, BountyEscrowOpResponse, PublishBountyEscrowRequest, ...). Derives the two-axis taxonomy from the generated mode DTO, superseding the local stubs in the ModeTab. - api/keys.ts: bountyKeys factory. - api/draft-client.ts + use-draft.ts: imperative CRUD plus the useDraft / useDraftList / useCreateDraft / useUpdateDraft / useDeleteDraft hooks against /organizations/{organizationId}/bounties/draft[/{id}] + /drafts. - api/escrow-client.ts + use-escrow.ts: organizer escrow calls (publish / cancel / select-winners / submit-signed / poll) plus useEscrowOp + useEscrowOpRunner, mirroring the hackathon machinery (MANAGED polls; EXTERNAL signs -> submit -> poll) bounty-scoped. - index.ts: public surface. Regenerates lib/api/generated/schema.d.ts from the v2 backend so the bounty draft paths/DTOs are present. * feat(bounty): wizard shell + step/draft machinery (#598) Adds the bounty Configure wizard orchestrator and its step + draft state, mirroring the hackathon wizard. No AI assist. - components/organization/bounties/new/constants.ts: StepKey (scope/mode/submission/reward/review), STEP_ORDER, BountyFormData, and isBountyStepDataValid. - hooks/use-bounty-steps.ts: URL ?step= navigation (free-roam) with a presentational step-status map. - hooks/use-bounty-draft.ts: lazy create (ensureDraftId) then per-section PATCH, resume via useDraft, and transformBountyFromApi (sections -> form state; winnerCount derived from prize tiers, ISO dates trimmed for the inputs). - components/organization/bounties/new/NewBountyTab.tsx: orchestrator wiring steps + draft + per-step save, persisting ?draftId= for resume, and threading the chosen mode from ModeTab into SubmissionModelTab. Scope/Reward/Review tabs (#600) and the publish + funding flow (#601) are left as marked placeholders with their save/navigate/draftId seams in place; this satisfies the acceptance criteria (navigate, autosave, resume) without speculative publish UI that depends on the unbuilt publish hook.
Completes the editable surface of the bounty Configure wizard, dropping the three remaining tabs into the seams the shell (#598) left. - tabs/schemas/scopeSchema.ts: title, description, optional GitHub issue url/number, optional project/window. - tabs/schemas/rewardSchema.ts: makeRewardSchema(claimType) — exactly one tier for single claim, 1-3 for a competition; amounts > 0, unique positions including position 1 (mirrors the publish gate's deriveWinnerDistribution). - lib/utils/bounty-escrow.ts: adapts the bounty reward shape to reuse the hackathon prize-pool math (getTotalPrizePoolForFunding, buildWinnerDistribution, 2.5% PLATFORM_FEE) rather than duplicating it. - tabs/ScopeTab.tsx: scope form. - tabs/RewardTab.tsx: currency + mode-driven prize tiers (field array sized to the winner count) with a live prize-pool / fee / total preview. - tabs/ReviewTab.tsx: per-section summary, validation summary, funding totals, and a publish CTA disabled until every section validates. - NewBountyTab.tsx + constants.ts: wire the three tabs into the wizard; the form snapshot now uses the per-tab form schema types. Reward currency is collected in the Reward step (the backend section that persists it) rather than Scope, so it round-trips. The publish action is a placeholder pending the escrow publish flow (#601); the disabled-until-valid gate is wired here.
…601) (#615) * feat(bounty): Scope + Reward + Review tabs and Zod schemas (#600) Completes the editable surface of the bounty Configure wizard, dropping the three remaining tabs into the seams the shell (#598) left. - tabs/schemas/scopeSchema.ts: title, description, optional GitHub issue url/number, optional project/window. - tabs/schemas/rewardSchema.ts: makeRewardSchema(claimType) — exactly one tier for single claim, 1-3 for a competition; amounts > 0, unique positions including position 1 (mirrors the publish gate's deriveWinnerDistribution). - lib/utils/bounty-escrow.ts: adapts the bounty reward shape to reuse the hackathon prize-pool math (getTotalPrizePoolForFunding, buildWinnerDistribution, 2.5% PLATFORM_FEE) rather than duplicating it. - tabs/ScopeTab.tsx: scope form. - tabs/RewardTab.tsx: currency + mode-driven prize tiers (field array sized to the winner count) with a live prize-pool / fee / total preview. - tabs/ReviewTab.tsx: per-section summary, validation summary, funding totals, and a publish CTA disabled until every section validates. - NewBountyTab.tsx + constants.ts: wire the three tabs into the wizard; the form snapshot now uses the per-tab form schema types. Reward currency is collected in the Reward step (the backend section that persists it) rather than Scope, so it round-trips. The publish action is a placeholder pending the escrow publish flow (#601); the disabled-until-valid gate is wired here. * feat(bounty): use-bounty-publish (escrow publish via shared runner) (#601) Wires the bounty publish action, mirroring use-hackathon-publish. - hooks/use-bounty-publish.ts: builds PublishBountyEscrowDto (ownerAddress, tokenAddress via getTokenAddress('USDC'), budget = sum of tier amounts, submissionDeadline as unix from the draft deadline, applicationCreditCost, winnerDistribution via the shared buildBountyWinnerDistribution, fundingMode) and drives it with useEscrowOpRunner: MANAGED returns PENDING_CONFIRM then polls; EXTERNAL signs the returned XDR via signXdrWithKit then submits + polls. On COMPLETED the bounty has moved draft_awaiting_funding -> open. Pre-flight resumes an in-flight op, short-circuits an already-published bounty, and runs a MANAGED USDC balance check (pool + 2.5% fee). - NewBountyTab.tsx: replace the Review placeholder with the real publish() and wire isPublishing into the CTA. Treasury funding (sourceWalletId) is omitted until the backend treasury-parity issue (boundless-nestjs #314) lands; MANAGED + EXTERNAL are supported. The funding-source picker + progress modal remain a follow-up; the hook exposes the escrow phase/error/txHash they need.
Adds the organizer bounty routes, mirroring the hackathon route tree, and the
published-list data needed by the list page.
- app/(landing)/organizations/[id]/bounties/page.tsx: list page with a Drafts
section (resume links + status badges + mode label / section count) and a
Published section (status badges + reward), plus a "Host a bounty" CTA.
- .../bounties/new/page.tsx: renders <NewBountyTab organizationId={id} />.
- .../bounties/drafts/[draftId]/page.tsx: renders
<NewBountyTab organizationId={id} draftId={draftId} />.
- features/bounties/api/core.ts + use-bounties.ts: listOrganizationBounties +
useOrganizationBounties for the root list (the backend root GET has no
response DTO, so the row shape is projected to OrganizationBountyListItem).
The pages mount the existing wizard shell (#598); the list separates drafts
(draft / draft_awaiting_funding) from published bounties so they don't
double-list.
Adds a Bounties menu item (/organizations/{orgId}/bounties) and a Post Bounty
quick action (/organizations/{orgId}/bounties/new) to OrganizationSidebar, so
organizers can reach the bounty list + Configure wizard.
Codegen reconcile: re-ran npm run codegen against the v2 backend; the committed
lib/api/generated/schema.d.ts already matches (BountyDraftResponseDto +
UpdateBountyDraftDto present, no drift), so no schema change is needed.
…618) * feat(bounty): wizard enhancements (resources step, currency, reputation, nav) - Resources: new optional Resources step (links + PDF/DOC/PPT/MD uploads), mirroring the hackathon resources tab; never blocks publish. Reuses a now configurable ResourceFileUpload (folder/tags/accepted types props; unique input id per row). - Reward currency: dropdown of USDC (default) / XLM (disabled) with real token logos, replacing the free-text field. - Reputation: per-category minimum floor (development highest); the organizer can raise it but not drop below the category baseline. - Navigation: Back button on every step after the first. - Scope: category chips + searchable country dropdown with flags + markdown description; GitHub issue URL required only for development. - Publish: redirect to the organizer's bounty list once publish finalizes. - Dev-only "Fill with mock" button to populate every section at once. * feat(bounty): hackathon-style org bounty list + delete-draft confirm - Rebuild the organization bounty list page in the hackathon style: sticky header with stats, Published/Drafts tabs, search + sort, and a banner-less reward-focused card grid (draft cards show a progress bar + resume link). - Deleting a draft now opens a confirmation modal (DeleteBountyDraftDialog) instead of deleting on the first click. - Expose `_count.submissions` on the org bounty list item for the cards.
* feat(bounty): features/bounties data layer (types, keys, draft + escrow) (#596) Adds the features/bounties/ data layer for the v1 app, mirroring features/hackathons/. REST-only via the typed openapi-fetch client; every server shape is aliased from the backend-generated schema so it cannot drift. - types.ts: aliases the generated draft + escrow DTOs (BountyDraft, UpdateBountyDraftBody, the four section types, BountyEscrowOpResponse, PublishBountyEscrowRequest, ...). Derives the two-axis taxonomy from the generated mode DTO, superseding the local stubs in the ModeTab. - api/keys.ts: bountyKeys factory. - api/draft-client.ts + use-draft.ts: imperative CRUD plus the useDraft / useDraftList / useCreateDraft / useUpdateDraft / useDeleteDraft hooks against /organizations/{organizationId}/bounties/draft[/{id}] + /drafts. - api/escrow-client.ts + use-escrow.ts: organizer escrow calls (publish / cancel / select-winners / submit-signed / poll) plus useEscrowOp + useEscrowOpRunner, mirroring the hackathon machinery (MANAGED polls; EXTERNAL signs -> submit -> poll) bounty-scoped. - index.ts: public surface. Regenerates lib/api/generated/schema.d.ts from the v2 backend so the bounty draft paths/DTOs are present. * feat(bounty): wizard shell + step/draft machinery (#598) Adds the bounty Configure wizard orchestrator and its step + draft state, mirroring the hackathon wizard. No AI assist. - components/organization/bounties/new/constants.ts: StepKey (scope/mode/submission/reward/review), STEP_ORDER, BountyFormData, and isBountyStepDataValid. - hooks/use-bounty-steps.ts: URL ?step= navigation (free-roam) with a presentational step-status map. - hooks/use-bounty-draft.ts: lazy create (ensureDraftId) then per-section PATCH, resume via useDraft, and transformBountyFromApi (sections -> form state; winnerCount derived from prize tiers, ISO dates trimmed for the inputs). - components/organization/bounties/new/NewBountyTab.tsx: orchestrator wiring steps + draft + per-step save, persisting ?draftId= for resume, and threading the chosen mode from ModeTab into SubmissionModelTab. Scope/Reward/Review tabs (#600) and the publish + funding flow (#601) are left as marked placeholders with their save/navigate/draftId seams in place; this satisfies the acceptance criteria (navigate, autosave, resume) without speculative publish UI that depends on the unbuilt publish hook. * feat: implement multi-step crowdfunding campaign wizard with milestone management * feat(crowdfunding): v2 public pages, builder dashboard, milestone tracking - Redesigned public listing (ProjectCard) and detail page with proper lifecycle states, voting panel, contributor list, and fully-funded detection - Added public milestone list + detail pages under /crowdfunding/[slug]/milestones - Builder per-campaign management: tabbed layout (overview / milestones / contributions) with shared header showing milestone X/Y progress and Fully Funded badge once fundingRaised >= fundingGoal - Milestone status sourced from milestoneState() utility: claimedAt-based "paid out" detection replaces stale reviewStatus === 'completed' checks - CampaignStatusBanner: shows milestone delivery bar and Fully Funded label during the FUNDING phase when goal is reached - milestones-metrics: completedAmount correctly sums paid-out milestones; inProgress checks SUBMITTED/UNDER_REVIEW enum values - ProjectCard: switches from funding bar to milestone X/Y bar on fully funded; footer and status badge update to Fully Funded (green) - lib/crowdfunding/status.ts: single source of truth for all campaign and milestone status copy and tone Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: update lockfile dependencies for package-lock.json --------- Co-authored-by: Benjtalkshow <chinedubenj@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(bounty): features/bounties data layer (types, keys, draft + escrow) (#596) Adds the features/bounties/ data layer for the v1 app, mirroring features/hackathons/. REST-only via the typed openapi-fetch client; every server shape is aliased from the backend-generated schema so it cannot drift. - types.ts: aliases the generated draft + escrow DTOs (BountyDraft, UpdateBountyDraftBody, the four section types, BountyEscrowOpResponse, PublishBountyEscrowRequest, ...). Derives the two-axis taxonomy from the generated mode DTO, superseding the local stubs in the ModeTab. - api/keys.ts: bountyKeys factory. - api/draft-client.ts + use-draft.ts: imperative CRUD plus the useDraft / useDraftList / useCreateDraft / useUpdateDraft / useDeleteDraft hooks against /organizations/{organizationId}/bounties/draft[/{id}] + /drafts. - api/escrow-client.ts + use-escrow.ts: organizer escrow calls (publish / cancel / select-winners / submit-signed / poll) plus useEscrowOp + useEscrowOpRunner, mirroring the hackathon machinery (MANAGED polls; EXTERNAL signs -> submit -> poll) bounty-scoped. - index.ts: public surface. Regenerates lib/api/generated/schema.d.ts from the v2 backend so the bounty draft paths/DTOs are present. * feat(bounty): wizard shell + step/draft machinery (#598) Adds the bounty Configure wizard orchestrator and its step + draft state, mirroring the hackathon wizard. No AI assist. - components/organization/bounties/new/constants.ts: StepKey (scope/mode/submission/reward/review), STEP_ORDER, BountyFormData, and isBountyStepDataValid. - hooks/use-bounty-steps.ts: URL ?step= navigation (free-roam) with a presentational step-status map. - hooks/use-bounty-draft.ts: lazy create (ensureDraftId) then per-section PATCH, resume via useDraft, and transformBountyFromApi (sections -> form state; winnerCount derived from prize tiers, ISO dates trimmed for the inputs). - components/organization/bounties/new/NewBountyTab.tsx: orchestrator wiring steps + draft + per-step save, persisting ?draftId= for resume, and threading the chosen mode from ModeTab into SubmissionModelTab. Scope/Reward/Review tabs (#600) and the publish + funding flow (#601) are left as marked placeholders with their save/navigate/draftId seams in place; this satisfies the acceptance criteria (navigate, autosave, resume) without speculative publish UI that depends on the unbuilt publish hook. * feat: implement multi-step crowdfunding campaign wizard with milestone management * feat(crowdfunding): v2 public pages, builder dashboard, milestone tracking - Redesigned public listing (ProjectCard) and detail page with proper lifecycle states, voting panel, contributor list, and fully-funded detection - Added public milestone list + detail pages under /crowdfunding/[slug]/milestones - Builder per-campaign management: tabbed layout (overview / milestones / contributions) with shared header showing milestone X/Y progress and Fully Funded badge once fundingRaised >= fundingGoal - Milestone status sourced from milestoneState() utility: claimedAt-based "paid out" detection replaces stale reviewStatus === 'completed' checks - CampaignStatusBanner: shows milestone delivery bar and Fully Funded label during the FUNDING phase when goal is reached - milestones-metrics: completedAmount correctly sums paid-out milestones; inProgress checks SUBMITTED/UNDER_REVIEW enum values - ProjectCard: switches from funding bar to milestone X/Y bar on fully funded; footer and status badge update to Fully Funded (green) - lib/crowdfunding/status.ts: single source of truth for all campaign and milestone status copy and tone Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: update lockfile dependencies for package-lock.json * refactor: standardize API error extraction to support array-based messages across crowdfunding components * refactor: restructure StoryStep inputs, enable sidebar navigation, and update campaign wizard validation logic --------- Co-authored-by: Benjtalkshow <chinedubenj@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(bounty): features/bounties data layer (types, keys, draft + escrow) (#596) Adds the features/bounties/ data layer for the v1 app, mirroring features/hackathons/. REST-only via the typed openapi-fetch client; every server shape is aliased from the backend-generated schema so it cannot drift. - types.ts: aliases the generated draft + escrow DTOs (BountyDraft, UpdateBountyDraftBody, the four section types, BountyEscrowOpResponse, PublishBountyEscrowRequest, ...). Derives the two-axis taxonomy from the generated mode DTO, superseding the local stubs in the ModeTab. - api/keys.ts: bountyKeys factory. - api/draft-client.ts + use-draft.ts: imperative CRUD plus the useDraft / useDraftList / useCreateDraft / useUpdateDraft / useDeleteDraft hooks against /organizations/{organizationId}/bounties/draft[/{id}] + /drafts. - api/escrow-client.ts + use-escrow.ts: organizer escrow calls (publish / cancel / select-winners / submit-signed / poll) plus useEscrowOp + useEscrowOpRunner, mirroring the hackathon machinery (MANAGED polls; EXTERNAL signs -> submit -> poll) bounty-scoped. - index.ts: public surface. Regenerates lib/api/generated/schema.d.ts from the v2 backend so the bounty draft paths/DTOs are present. * feat(bounty): wizard shell + step/draft machinery (#598) Adds the bounty Configure wizard orchestrator and its step + draft state, mirroring the hackathon wizard. No AI assist. - components/organization/bounties/new/constants.ts: StepKey (scope/mode/submission/reward/review), STEP_ORDER, BountyFormData, and isBountyStepDataValid. - hooks/use-bounty-steps.ts: URL ?step= navigation (free-roam) with a presentational step-status map. - hooks/use-bounty-draft.ts: lazy create (ensureDraftId) then per-section PATCH, resume via useDraft, and transformBountyFromApi (sections -> form state; winnerCount derived from prize tiers, ISO dates trimmed for the inputs). - components/organization/bounties/new/NewBountyTab.tsx: orchestrator wiring steps + draft + per-step save, persisting ?draftId= for resume, and threading the chosen mode from ModeTab into SubmissionModelTab. Scope/Reward/Review tabs (#600) and the publish + funding flow (#601) are left as marked placeholders with their save/navigate/draftId seams in place; this satisfies the acceptance criteria (navigate, autosave, resume) without speculative publish UI that depends on the unbuilt publish hook. * feat: implement multi-step crowdfunding campaign wizard with milestone management * feat(crowdfunding): v2 public pages, builder dashboard, milestone tracking - Redesigned public listing (ProjectCard) and detail page with proper lifecycle states, voting panel, contributor list, and fully-funded detection - Added public milestone list + detail pages under /crowdfunding/[slug]/milestones - Builder per-campaign management: tabbed layout (overview / milestones / contributions) with shared header showing milestone X/Y progress and Fully Funded badge once fundingRaised >= fundingGoal - Milestone status sourced from milestoneState() utility: claimedAt-based "paid out" detection replaces stale reviewStatus === 'completed' checks - CampaignStatusBanner: shows milestone delivery bar and Fully Funded label during the FUNDING phase when goal is reached - milestones-metrics: completedAmount correctly sums paid-out milestones; inProgress checks SUBMITTED/UNDER_REVIEW enum values - ProjectCard: switches from funding bar to milestone X/Y bar on fully funded; footer and status badge update to Fully Funded (green) - lib/crowdfunding/status.ts: single source of truth for all campaign and milestone status copy and tone Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: update lockfile dependencies for package-lock.json * refactor: standardize API error extraction to support array-based messages across crowdfunding components * refactor: restructure StoryStep inputs, enable sidebar navigation, and update campaign wizard validation logic * feat: replace textarea with AnnouncementEditor and add markdown rendering for campaign project details --------- Co-authored-by: Benjtalkshow <chinedubenj@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(bounty): features/bounties data layer (types, keys, draft + escrow) (#596) Adds the features/bounties/ data layer for the v1 app, mirroring features/hackathons/. REST-only via the typed openapi-fetch client; every server shape is aliased from the backend-generated schema so it cannot drift. - types.ts: aliases the generated draft + escrow DTOs (BountyDraft, UpdateBountyDraftBody, the four section types, BountyEscrowOpResponse, PublishBountyEscrowRequest, ...). Derives the two-axis taxonomy from the generated mode DTO, superseding the local stubs in the ModeTab. - api/keys.ts: bountyKeys factory. - api/draft-client.ts + use-draft.ts: imperative CRUD plus the useDraft / useDraftList / useCreateDraft / useUpdateDraft / useDeleteDraft hooks against /organizations/{organizationId}/bounties/draft[/{id}] + /drafts. - api/escrow-client.ts + use-escrow.ts: organizer escrow calls (publish / cancel / select-winners / submit-signed / poll) plus useEscrowOp + useEscrowOpRunner, mirroring the hackathon machinery (MANAGED polls; EXTERNAL signs -> submit -> poll) bounty-scoped. - index.ts: public surface. Regenerates lib/api/generated/schema.d.ts from the v2 backend so the bounty draft paths/DTOs are present. * feat(bounty): wizard shell + step/draft machinery (#598) Adds the bounty Configure wizard orchestrator and its step + draft state, mirroring the hackathon wizard. No AI assist. - components/organization/bounties/new/constants.ts: StepKey (scope/mode/submission/reward/review), STEP_ORDER, BountyFormData, and isBountyStepDataValid. - hooks/use-bounty-steps.ts: URL ?step= navigation (free-roam) with a presentational step-status map. - hooks/use-bounty-draft.ts: lazy create (ensureDraftId) then per-section PATCH, resume via useDraft, and transformBountyFromApi (sections -> form state; winnerCount derived from prize tiers, ISO dates trimmed for the inputs). - components/organization/bounties/new/NewBountyTab.tsx: orchestrator wiring steps + draft + per-step save, persisting ?draftId= for resume, and threading the chosen mode from ModeTab into SubmissionModelTab. Scope/Reward/Review tabs (#600) and the publish + funding flow (#601) are left as marked placeholders with their save/navigate/draftId seams in place; this satisfies the acceptance criteria (navigate, autosave, resume) without speculative publish UI that depends on the unbuilt publish hook. * feat: implement multi-step crowdfunding campaign wizard with milestone management * feat(crowdfunding): v2 public pages, builder dashboard, milestone tracking - Redesigned public listing (ProjectCard) and detail page with proper lifecycle states, voting panel, contributor list, and fully-funded detection - Added public milestone list + detail pages under /crowdfunding/[slug]/milestones - Builder per-campaign management: tabbed layout (overview / milestones / contributions) with shared header showing milestone X/Y progress and Fully Funded badge once fundingRaised >= fundingGoal - Milestone status sourced from milestoneState() utility: claimedAt-based "paid out" detection replaces stale reviewStatus === 'completed' checks - CampaignStatusBanner: shows milestone delivery bar and Fully Funded label during the FUNDING phase when goal is reached - milestones-metrics: completedAmount correctly sums paid-out milestones; inProgress checks SUBMITTED/UNDER_REVIEW enum values - ProjectCard: switches from funding bar to milestone X/Y bar on fully funded; footer and status badge update to Fully Funded (green) - lib/crowdfunding/status.ts: single source of truth for all campaign and milestone status copy and tone Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: update lockfile dependencies for package-lock.json * refactor: standardize API error extraction to support array-based messages across crowdfunding components * refactor: restructure StoryStep inputs, enable sidebar navigation, and update campaign wizard validation logic * feat: replace textarea with AnnouncementEditor and add markdown rendering for campaign project details * fix: useCampaign routes UUID params to fetchCampaignById Post-create redirect lands on /me/crowdfunding/{uuid}. The hook was always calling the slug endpoint which rejected UUIDs. Now detects UUID format and uses the correct /api/crowdfunding/{id} endpoint. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: auth-gate voting/contribute + branded fallback banner - VotePanel: unauthenticated users see "Sign in to vote" instead of the yes/no buttons - Public page: "Back this project" replaced with "Sign in to back this project" link for unauthenticated visitors - Fallback banner (no banner set): full-height Boundless-branded SVG with dot grid, concentric arcs in brand colour, and faint wordmark instead of the flat zinc gradient div Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Benjtalkshow <chinedubenj@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(bounty): features/bounties data layer (types, keys, draft + escrow) (#596) Adds the features/bounties/ data layer for the v1 app, mirroring features/hackathons/. REST-only via the typed openapi-fetch client; every server shape is aliased from the backend-generated schema so it cannot drift. - types.ts: aliases the generated draft + escrow DTOs (BountyDraft, UpdateBountyDraftBody, the four section types, BountyEscrowOpResponse, PublishBountyEscrowRequest, ...). Derives the two-axis taxonomy from the generated mode DTO, superseding the local stubs in the ModeTab. - api/keys.ts: bountyKeys factory. - api/draft-client.ts + use-draft.ts: imperative CRUD plus the useDraft / useDraftList / useCreateDraft / useUpdateDraft / useDeleteDraft hooks against /organizations/{organizationId}/bounties/draft[/{id}] + /drafts. - api/escrow-client.ts + use-escrow.ts: organizer escrow calls (publish / cancel / select-winners / submit-signed / poll) plus useEscrowOp + useEscrowOpRunner, mirroring the hackathon machinery (MANAGED polls; EXTERNAL signs -> submit -> poll) bounty-scoped. - index.ts: public surface. Regenerates lib/api/generated/schema.d.ts from the v2 backend so the bounty draft paths/DTOs are present. * feat(bounty): wizard shell + step/draft machinery (#598) Adds the bounty Configure wizard orchestrator and its step + draft state, mirroring the hackathon wizard. No AI assist. - components/organization/bounties/new/constants.ts: StepKey (scope/mode/submission/reward/review), STEP_ORDER, BountyFormData, and isBountyStepDataValid. - hooks/use-bounty-steps.ts: URL ?step= navigation (free-roam) with a presentational step-status map. - hooks/use-bounty-draft.ts: lazy create (ensureDraftId) then per-section PATCH, resume via useDraft, and transformBountyFromApi (sections -> form state; winnerCount derived from prize tiers, ISO dates trimmed for the inputs). - components/organization/bounties/new/NewBountyTab.tsx: orchestrator wiring steps + draft + per-step save, persisting ?draftId= for resume, and threading the chosen mode from ModeTab into SubmissionModelTab. Scope/Reward/Review tabs (#600) and the publish + funding flow (#601) are left as marked placeholders with their save/navigate/draftId seams in place; this satisfies the acceptance criteria (navigate, autosave, resume) without speculative publish UI that depends on the unbuilt publish hook. * feat: implement multi-step crowdfunding campaign wizard with milestone management * feat(crowdfunding): v2 public pages, builder dashboard, milestone tracking - Redesigned public listing (ProjectCard) and detail page with proper lifecycle states, voting panel, contributor list, and fully-funded detection - Added public milestone list + detail pages under /crowdfunding/[slug]/milestones - Builder per-campaign management: tabbed layout (overview / milestones / contributions) with shared header showing milestone X/Y progress and Fully Funded badge once fundingRaised >= fundingGoal - Milestone status sourced from milestoneState() utility: claimedAt-based "paid out" detection replaces stale reviewStatus === 'completed' checks - CampaignStatusBanner: shows milestone delivery bar and Fully Funded label during the FUNDING phase when goal is reached - milestones-metrics: completedAmount correctly sums paid-out milestones; inProgress checks SUBMITTED/UNDER_REVIEW enum values - ProjectCard: switches from funding bar to milestone X/Y bar on fully funded; footer and status badge update to Fully Funded (green) - lib/crowdfunding/status.ts: single source of truth for all campaign and milestone status copy and tone Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: update lockfile dependencies for package-lock.json * refactor: standardize API error extraction to support array-based messages across crowdfunding components * refactor: restructure StoryStep inputs, enable sidebar navigation, and update campaign wizard validation logic * feat: replace textarea with AnnouncementEditor and add markdown rendering for campaign project details * fix: useCampaign routes UUID params to fetchCampaignById Post-create redirect lands on /me/crowdfunding/{uuid}. The hook was always calling the slug endpoint which rejected UUIDs. Now detects UUID format and uses the correct /api/crowdfunding/{id} endpoint. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: auth-gate voting/contribute + branded fallback banner - VotePanel: unauthenticated users see "Sign in to vote" instead of the yes/no buttons - Public page: "Back this project" replaced with "Sign in to back this project" link for unauthenticated visitors - Fallback banner (no banner set): full-height Boundless-branded SVG with dot grid, concentric arcs in brand colour, and faint wordmark instead of the flat zinc gradient div Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor: unify campaign description rendering logic to prioritize details over description fields across project components --------- Co-authored-by: Benjtalkshow <chinedubenj@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…, and supporters sections
… views and improved header metadata
…ross crowdfunding hooks
Add the builder/participant data layer to features/bounties, mirroring the
hackathon participant scope and reusing the shared escrow runner. The visible
builder UI (marketplace, detail, apply/submit/withdraw, my-bounties) consumes
this.
- participant-escrow-client: on-chain apply/submit/withdraw-application/
withdraw-submission/contribute + participant op poll + submit-signed
(the no-org-prefix /api/bounties/{id}/escrow/* routes)
- participant-client: public list/detail, v2 application records
(apply/edit/withdraw/me), competition join/leave
- use-participant hooks: useBountiesList/useBounty/useMyBountyApplication,
useApply/Edit/WithdrawApplication, useJoin/LeaveCompetition, and escrow-op
hooks (useSubmitBounty/useWithdrawSubmission/useContributeToBounty/
useApplyToBountyEscrow/useWithdrawApplicationEscrow) driven through the
runner, default MANAGED
- use-escrow: EscrowOpScope is now organizer | participant; the runner routes
op-poll/submit-signed to the participant URLs
- keys/types/index: participant query keys, type aliases, public exports
MyBountyApplication is hand-typed until boundless-nestjs #331 lands and codegen
runs; useMyBountyActivity is deferred until the participant dashboard (#332).
Closes #621
* feat(bounty): participant data layer (escrow client + hooks)
Add the builder/participant data layer to features/bounties, mirroring the
hackathon participant scope and reusing the shared escrow runner. The visible
builder UI (marketplace, detail, apply/submit/withdraw, my-bounties) consumes
this.
- participant-escrow-client: on-chain apply/submit/withdraw-application/
withdraw-submission/contribute + participant op poll + submit-signed
(the no-org-prefix /api/bounties/{id}/escrow/* routes)
- participant-client: public list/detail, v2 application records
(apply/edit/withdraw/me), competition join/leave
- use-participant hooks: useBountiesList/useBounty/useMyBountyApplication,
useApply/Edit/WithdrawApplication, useJoin/LeaveCompetition, and escrow-op
hooks (useSubmitBounty/useWithdrawSubmission/useContributeToBounty/
useApplyToBountyEscrow/useWithdrawApplicationEscrow) driven through the
runner, default MANAGED
- use-escrow: EscrowOpScope is now organizer | participant; the runner routes
op-poll/submit-signed to the participant URLs
- keys/types/index: participant query keys, type aliases, public exports
MyBountyApplication is hand-typed until boundless-nestjs #331 lands and codegen
runs; useMyBountyActivity is deferred until the participant dashboard (#332).
Closes #621
* feat(bounty): public bounty marketplace (discover/list)
Replace the /coming-soon placeholder at /bounties with a real public
marketplace, mirroring the hackathon browse and wired to the participant
data layer (#621).
- route app/(landing)/bounties/page.tsx + bounties metadata entry
- BountiesPage: search + status + mode filters, infinite scroll,
loading/empty/error states
- BountyCard: mode badge (plain label), status, reward, organization,
application-window date; links to /bounties/[id]
- BountiesFiltersHeader + colocated useInfiniteBounties (infinite query
over listBounties)
Status + search filter server-side; mode narrows client-side (the public
list endpoint doesn't filter on mode). Category filter and a card submission
deadline are omitted because BountyPublicDto exposes neither — small backend
follow-ups.
Closes #622
* feat(bounty): participant data layer (escrow client + hooks)
Add the builder/participant data layer to features/bounties, mirroring the
hackathon participant scope and reusing the shared escrow runner. The visible
builder UI (marketplace, detail, apply/submit/withdraw, my-bounties) consumes
this.
- participant-escrow-client: on-chain apply/submit/withdraw-application/
withdraw-submission/contribute + participant op poll + submit-signed
(the no-org-prefix /api/bounties/{id}/escrow/* routes)
- participant-client: public list/detail, v2 application records
(apply/edit/withdraw/me), competition join/leave
- use-participant hooks: useBountiesList/useBounty/useMyBountyApplication,
useApply/Edit/WithdrawApplication, useJoin/LeaveCompetition, and escrow-op
hooks (useSubmitBounty/useWithdrawSubmission/useContributeToBounty/
useApplyToBountyEscrow/useWithdrawApplicationEscrow) driven through the
runner, default MANAGED
- use-escrow: EscrowOpScope is now organizer | participant; the runner routes
op-poll/submit-signed to the participant URLs
- keys/types/index: participant query keys, type aliases, public exports
MyBountyApplication is hand-typed until boundless-nestjs #331 lands and codegen
runs; useMyBountyActivity is deferred until the participant dashboard (#332).
Closes #621
* feat(bounty): public bounty marketplace (discover/list)
Replace the /coming-soon placeholder at /bounties with a real public
marketplace, mirroring the hackathon browse and wired to the participant
data layer (#621).
- route app/(landing)/bounties/page.tsx + bounties metadata entry
- BountiesPage: search + status + mode filters, infinite scroll,
loading/empty/error states
- BountyCard: mode badge (plain label), status, reward, organization,
application-window date; links to /bounties/[id]
- BountiesFiltersHeader + colocated useInfiniteBounties (infinite query
over listBounties)
Status + search filter server-side; mode narrows client-side (the public
list endpoint doesn't filter on mode). Category filter and a card submission
deadline are omitted because BountyPublicDto exposes neither — small backend
follow-ups.
Closes #622
* feat(bounty): bounty detail page (/bounties/[id])
The builder hub: shows the bounty, the caller's status, and a mode-aware
entry CTA. Wired to the participant data layer (#621).
- route app/(landing)/bounties/[id]/page.tsx
- BountyDetail: markdown description, prize tiers, mode/status badges,
organization, reward pool + eligibility sidebar (reputation minimum /
application window / max applicants / shortlist); loading + not-found
- BountyEntryCta: mode-aware CTA — Claim (open+single), Join (open+
competition), Apply (application). Gated/explained when not accepting,
the application window closed, or already applied; shows the caller's
application status via useMyBountyApplication
The actual entry execution (forms / on-chain op) ships in #624; the CTA is
gated + labeled and hands off to it. applicationCreditCost is not in
BountyPublicDto so it's omitted from the eligibility panel.
Closes #623
…647) Fill the entry execution the detail-page CTA hands off to (#623), wired to the participant data layer (#621). Covers all six modes. - applicationSchema: mode-aware zod validation + body builders (light: proposalShort 100-300 words + estimatedDays + <=3 links; full: proposalFull 500-2000 words + qualifications >=50 chars + <=6 links + optional video) - BountyApplicationForm: conditional fields per entry type with live word count; reused for create + edit - BountyEntryDialog: mode-aware modal — Apply (POST v2/applications) / Edit (PATCH); Join (POST v2/competition/join); Claim (on-chain apply escrow op, MANAGED, with progress + reputation pre-check). Wallet-gated. - BountyEntryCta: opens the dialog and, for an active application, exposes Edit + Withdraw (application), Leave (competition), or on-chain Withdraw (single claim) behind a two-step confirm Closes #624
After entry (claim/join/selection) the builder submits their deliverable, anchored on-chain via the participant escrow runner (#621). Mirrors the hackathon submission anchor. - BountySubmitPanel (detail sidebar, shown when eligible: claimed/joined/ SELECTED/SHORTLISTED): contentUri deliverable input -> submit escrow op (useSubmitBounty, MANAGED) with anchor progress (preparing -> anchoring -> confirmed) + tx-hash explorer link - Withdraw submission via useWithdrawSubmission behind a two-step confirm - Wallet-gated; guarded by entry eligibility Persistent submission state across reloads is session-local until the #332 my-submission read lands in the schema; the submission-deadline gate is enforced on-chain (not in BountyPublicDto). Closes #625
The builder's /me surfaces for bounty applications, submissions, and reward receipts, consuming the participant dashboard (#332) + earnings (#335). - data layer: useMyBountyApplications / useMyBountySubmissions (the deferred useMyBountyActivity) via the legacy axios api (hand-typed rows, retry:false, degrading to empty until #332 lands in the schema) - /me/bounties page: Applications + Submissions tabs with status/progress badges; won submissions show the reward amount + a payout tx-hash link; rows link to the detail page - sidebar: "My Bounties" nav entry - /me/earnings: the page already renders breakdown.bounties + activities generically (so #335 surfaces them); add a "View tx" link to reward activities (txHash cast until codegen) Closes #626
GitHub's built-in Closes/Fixes/Resolves auto-close only fires for PRs merged into the default branch. Feature PRs here merge into integration branches (feat/t-replace, etc.), leaving linked issues open. This adds a pull_request_target workflow that parses the merged PR body and closes the referenced same-repo issues on any base branch.
…627) (#653) The participant gap endpoints (applications/me, my-activity, results) have landed in v2, so regenerate the OpenAPI schema and replace the two hand-typed casts (MyBountyApplication, my-activity dashboard rows) with their generated DTO aliases. Refresh openapi.snapshot.json so offline/CI codegen matches. Nav entries (marketplace + /me sidebar) already shipped.
…hook and UI component
…quirements (#662) * feat(bounty): submission metadata types, category filter, and wizard requirement toggles Refresh the generated OpenAPI schema for the new public-bounty fields (claimedBy, category, submissionDeadline, submissionRequirements) and the submit-op metadata. Add the category query param to the marketplace list client, the per-bounty my-submission read + hook, and the organizer requirement toggles in the Configure wizard's submission step. Flatten the category reputation baseline to 0 for testing and let the wizard accept a 0 floor. * feat(bounty): marketplace card redesign, category tabs, and detail display Bounty cards now show the organizer logo, category, a live due-date countdown, and the USDC token logo (title only, no markdown bleed). Add a category tab bar to the marketplace and mirror the same details on the detail page, plus a mode-explainer tooltip. Single-claim bounties render a 'Claimed by' card linking to the claimant profile, and the application withdraw button is gated while a submission is anchored. * feat(bounty): dedicated submit page with metadata and media upload Replace the single-input submit panel with a /bounties/[id]/submit page: primary submission link plus optional documentation, tweet, and demo video links and a drag-and-drop media uploader. Required fields follow the bounty's organizer-configured requirements; on success it returns to the detail page. The sidebar panel now routes here (new tab) and reflects the submitted/withdraw state.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (30)
Disabled knowledge base sources:
📝 WalkthroughWalkthroughAdds AI-assisted draft generation (streaming SSE, clarify gating, per-section regeneration) for both hackathons and bounties. Introduces a shared streaming client, six reusable AI UI components, bounty AI API hooks, and OTP-based escrow funding with treasury-wallet support. Generalizes funding modals to support entity-agnostic wording. ChangesOrganizer Assist AI Drafting + Bounty Funding Flow
Sequence Diagram(s)sequenceDiagram
participant Organizer
participant GenerateDialog as GenerateWithAi(Bounty/Hackathon)Dialog
participant useClarify as useClarifyDraft
participant streamDraft
participant Backend
participant ReactQuery
Organizer->>GenerateDialog: submit brief
GenerateDialog->>useClarify: mutateAsync(brief)
useClarify->>Backend: POST /draft/clarify
Backend-->>useClarify: {ready, questions}
alt not ready (questions present)
GenerateDialog-->>Organizer: render AiClarifyQuestions
Organizer->>GenerateDialog: submit answers (or skip)
end
GenerateDialog->>streamDraft: POST /draft/from-brief/stream (augmented brief)
loop SSE frames
Backend-->>streamDraft: partial frame → suggestion
streamDraft-->>GenerateDialog: onPartial → AiStreamPreview updates
end
Backend-->>streamDraft: done frame {draftId, draft}
streamDraft-->>GenerateDialog: onDone
GenerateDialog->>ReactQuery: setQueryData(draft) + invalidate drafts list
GenerateDialog-->>Organizer: toast + navigate to draft page
sequenceDiagram
participant Organizer
participant NewBountyTab
participant FundingConfirmationModal
participant useBountyPublish
participant Backend
participant FundingProgressModal
Organizer->>NewBountyTab: select funding source (treasury vs external)
NewBountyTab->>FundingConfirmationModal: open (entityNoun='bounty', source, balance)
Organizer->>FundingConfirmationModal: confirm + OTP verify
FundingConfirmationModal->>useBountyPublish: runFunding()
useBountyPublish->>Backend: POST escrow (sourceWalletId when treasury)
Backend-->>useBountyPublish: escrowPhase updates
useBountyPublish-->>FundingProgressModal: phase=completed
FundingProgressModal-->>Organizer: "View bounty" button
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Suggested reviewers
Poem
✨ Finishing Touches📝 Generate docstrings
🧪 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 |
Integrate main (#663 bounty UI + data layers, DTCC blog post, dependency bumps) with the Organizer Assist (AI drafting), shared funding modal, and bounty reset-to-draft work on this branch. Resolution notes: - Bounty/hackathon wizard files (NewBountyTab, NewHackathonTab, ScopeTab, RewardTab, SubmissionModelTab, GenerateWithAiDialog, RegenerateSectionButton): kept this branch's versions, which evolve the same code #663 touched — AI drafting, streaming reveal, clarify gate, example reference, the shared funding-source picker (treasury + external), and OTP step-up. - use-bounty-publish: kept treasury funding + reset-to-draft recovery and dropped applicationCreditCost (no longer on PublishBountyEscrowDto per the regenerated schema). - Funding modals: removed the duplicate copies #663 left under hackathons/new/; the canonical shared copies live in organization/funding/. - schema.d.ts: regenerated via npm run codegen against the live backend. - package-lock.json: reconciled against the merged package.json. Verified: tsc --noEmit and eslint both pass on the merged tree. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reconcile production (#664 hackathon track-based prizes + UI updates) with main. main already contains #664's substance (track-based prizes landed via the prize overhaul) plus the AI drafting, shared funding modal, treasury, and bounty reset-to-draft work, so the merge is a content no-op against main. Conflicts resolved by keeping main's versions (the AI/funding/treasury files that supersede production's pre-#665 base); removed the duplicate funding modals production carried under hackathons/new/ (canonical copies live in organization/funding/); kept main's generated schema.d.ts. Verified: tsc --noEmit and eslint both pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Summary by CodeRabbit
New Features
Bug Fixes