From d390c137bae948d22db6d808394f9163ce282022 Mon Sep 17 00:00:00 2001 From: Collins Ikechukwu Date: Wed, 24 Jun 2026 21:58:39 +0100 Subject: [PATCH] Revert "Feat/crowdfunding (#640)" This reverts commit 52be58c7540a7dbc0207095b995232522221ad67. --- .claude/launch.json | 11 - .env.example | 10 +- .husky/pre-push | 21 +- .../[slug]/milestones/[id]/page.tsx | 383 - .../crowdfunding/[slug]/milestones/page.tsx | 189 - app/(landing)/crowdfunding/[slug]/page.tsx | 625 - app/(landing)/crowdfunding/new/page.tsx | 22 - app/(landing)/crowdfunding/page.tsx | 15 - .../[slug]/components/AccessGate.tsx | 83 - .../RegistrationQuestionsDialog.tsx | 191 - .../[slug]/components/SponsorsSection.tsx | 30 +- .../components/header/ActionButtons.tsx | 40 +- .../components/sidebar/CommunityLinks.tsx | 143 - .../components/sidebar/MySubmissionPanel.tsx | 2 +- .../components/sidebar/PoolAndAction.tsx | 274 +- .../[slug]/components/sidebar/index.tsx | 4 - .../components/tabs/contents/Overview.tsx | 182 +- .../[slug]/components/tabs/contents/index.tsx | 0 .../contents/submissions/SubmissionCard.tsx | 2 +- app/(landing)/hackathons/[slug]/page.tsx | 19 +- .../hackathons/[slug]/submit/page.tsx | 2 +- app/(landing)/hackathons/layout.tsx | 13 +- .../preview/[orgId]/[draftId]/page.tsx | 7 +- .../[id]/bounties/drafts/[draftId]/page.tsx | 25 - .../organizations/[id]/bounties/new/page.tsx | 25 - .../organizations/[id]/bounties/page.tsx | 405 - .../hackathons/[hackathonId]/judging/page.tsx | 152 +- .../[id]/hackathons/[hackathonId]/page.tsx | 62 +- .../[hackathonId]/participants/page.tsx | 12 - .../hackathons/[hackathonId]/rewards/page.tsx | 163 +- .../[hackathonId]/settings/page.tsx | 37 +- .../hackathons/[hackathonId]/winners/page.tsx | 338 - .../[id]/hackathons/drafts/[draftId]/page.tsx | 6 +- .../[id]/hackathons/new/page.tsx | 6 +- .../organizations/[id]/hackathons/page.tsx | 90 +- .../organizations/[id]/treasury/page.tsx | 78 - .../treasury/receipts/[receiptId]/page.tsx | 197 - app/(landing)/organizations/layout.tsx | 15 +- app/(landing)/projects/[slug]/page.tsx | 17 +- .../submissions/[submissionId]/page.tsx | 37 - app/layout.tsx | 4 +- .../[slug]/components/CampaignBanner.tsx | 27 + .../[slug]/components/CampaignTabs.tsx | 48 +- .../[slug]/components/FundingProgress.tsx | 76 + .../[slug]/components/ProjectDetails.tsx | 83 +- .../crowdfunding/[slug]/components/index.ts | 2 + .../[slug]/contributions/page.tsx | 109 +- .../edit/components/BasicInfoSection.tsx | 233 + .../components/ContactSocialSection.old.tsx | 165 + .../edit/components/ContactSocialSection.tsx | 249 + .../edit/components/DetailsFundingSection.tsx | 82 + .../edit/components/MilestonesSection.tsx | 364 + .../edit/components/ProjectLinksSection.tsx | 57 + .../edit/components/RepoLinksSection.tsx | 75 + .../[slug]/edit/components/TeamSection.tsx | 243 + .../[slug]/edit/components/index.ts | 7 + .../edit/components/md-editor-custom.css | 98 + app/me/crowdfunding/[slug]/edit/page.tsx | 316 +- app/me/crowdfunding/[slug]/layout.tsx | 146 - .../milestones/[milestoneIndex]/page.tsx | 366 +- .../crowdfunding/[slug]/milestones/page.tsx | 72 +- app/me/crowdfunding/[slug]/page.tsx | 101 +- app/me/crowdfunding/new/page.tsx | 5 - app/me/crowdfunding/page.tsx | 127 +- app/me/layout.tsx | 20 + app/partners/contribute/[token]/page.tsx | 34 +- app/providers.tsx | 39 +- components/app-sidebar.tsx | 46 +- components/auth/LoginWrapper.tsx | 30 + components/auth/OtpForm.tsx | 33 +- components/crowdfunding-table-columns.tsx | 41 +- components/crowdfunding-table-toolbar.tsx | 2 +- .../crowdfunding/CampaignStatusBanner.tsx | 436 - components/crowdfunding/ContributeSheet.tsx | 325 - .../crowdfunding/MilestoneSubmitForm.tsx | 279 - components/crowdfunding/VotePanel.tsx | 109 - .../crowdfunding/campaign-funding-tab.tsx | 186 + .../crowdfunding/campaign-milestones-tab.tsx | 153 + components/crowdfunding/campaign-stats.tsx | 132 + components/crowdfunding/milestone-card.tsx | 152 +- .../crowdfunding/milestones-metrics.tsx | 10 +- .../crowdfunding/new/NewCampaignSidebar.tsx | 187 - .../crowdfunding/new/NewCampaignWizard.tsx | 524 - .../crowdfunding/new/WizardHelpButton.tsx | 78 - components/crowdfunding/new/constants.ts | 64 - components/crowdfunding/new/fee.ts | 46 - .../crowdfunding/new/milestone-templates.ts | 216 - .../crowdfunding/new/steps/BasicsStep.tsx | 213 - .../crowdfunding/new/steps/FundingStep.tsx | 106 - .../crowdfunding/new/steps/LinksStep.tsx | 262 - .../crowdfunding/new/steps/MilestonesStep.tsx | 368 - .../crowdfunding/new/steps/ReviewStep.tsx | 224 - .../crowdfunding/new/steps/StoryStep.tsx | 89 - .../crowdfunding/new/steps/TeamStep.tsx | 191 - components/crowdfunding/quick-links.tsx | 82 + .../crowdfunding/submit-evidence-modal.tsx | 450 + components/hackathons/HackathonsPage.tsx | 6 +- .../overview/RegisterHackathonModal.tsx | 92 + .../submissions/SubmissionAnchorProgress.tsx | 258 - .../hackathons/submissions/SubmissionForm.tsx | 279 +- components/judge/JudgeAiAssist.tsx | 167 - .../landing-page/hackathon/HackathonCard.tsx | 32 +- components/landing-page/navbar.tsx | 2 +- components/me-dashboard.tsx | 218 +- .../organization/OrganizationSettings.tsx | 13 +- .../organization/OrganizationSidebar.tsx | 21 - .../bounties/DeleteBountyDraftDialog.tsx | 72 - .../bounties/new/NewBountyTab.tsx | 313 - .../organization/bounties/new/constants.ts | 81 - .../organization/bounties/new/mock-data.ts | 66 - .../bounties/new/tabs/ModeTab.tsx | 354 - .../bounties/new/tabs/ResourcesTab.tsx | 316 - .../bounties/new/tabs/ReviewTab.tsx | 347 - .../bounties/new/tabs/RewardTab.tsx | 278 - .../bounties/new/tabs/ScopeTab.tsx | 373 - .../bounties/new/tabs/SubmissionModelTab.tsx | 381 - .../bounties/new/tabs/schemas/modeSchema.ts | 144 - .../new/tabs/schemas/resourcesSchema.ts | 42 - .../bounties/new/tabs/schemas/rewardSchema.ts | 70 - .../bounties/new/tabs/schemas/scopeSchema.ts | 74 - .../new/tabs/schemas/submissionModelSchema.ts | 107 - .../SubmissionModalHeader.tsx | 8 + .../HackathonPublishStatusBanner.tsx | 146 - .../hackathons/ParticipantsGrid.tsx | 8 +- .../hackathons/ParticipantsTable.tsx | 9 +- .../hackathons/details/HackathonSidebar.tsx | 415 +- .../hackathons/judging/AiScorecardsPanel.tsx | 299 - .../judging/AllocationPreviewCard.tsx | 160 +- .../judging/ImportJudgesCsvDialog.tsx | 292 - .../judging/JudgingResultsTable.tsx | 8 - .../judging/OrganizerJudgesPanel.tsx | 32 +- .../judging/RecommendationThresholdsCard.tsx | 211 - .../new/FundingConfirmationModal.tsx | 524 - .../hackathons/new/FundingProgressModal.tsx | 248 - .../hackathons/new/GenerateWithAiDialog.tsx | 254 - .../new/HackathonTabsNavigation.tsx | 22 +- .../hackathons/new/NewHackathonTab.tsx | 444 +- .../new/PrePublishAnnounceDialog.tsx | 2 +- .../new/RegenerateSectionButton.tsx | 80 - .../organization/hackathons/new/constants.ts | 4 - .../new/tabs/CustomQuestionsTab.tsx | 348 - .../hackathons/new/tabs/InfoTab.tsx | 24 +- .../hackathons/new/tabs/JudgingTab.tsx | 28 +- .../hackathons/new/tabs/ReviewTab.tsx | 6 +- .../hackathons/new/tabs/RewardsTab.tsx | 2090 +- .../hackathons/new/tabs/TimelineTab.tsx | 23 - .../hackathons/new/tabs/TracksTab.tsx | 316 - .../new/tabs/components/CategorySelection.tsx | 198 +- .../tabs/components/ResourceFileUpload.tsx | 56 +- .../tabs/components/review/EscrowSummary.tsx | 10 +- .../review/HackathonPublishedModal.tsx | 24 +- .../tabs/components/review/PublishSection.tsx | 9 +- .../review/WalletConnectionWarning.tsx | 4 +- .../new/tabs/schemas/rewardsSchema.ts | 65 +- .../rewards/CreateMilestonesDialog.tsx | 122 + .../hackathons/rewards/EscrowStatusCard.tsx | 28 + .../rewards/PublishWinnersWizard.tsx | 176 +- .../RewardDistributionStatusBanner.tsx | 254 + .../rewards/RewardPayoutProgressModal.tsx | 240 - .../hackathons/rewards/RewardsPageContent.tsx | 381 +- .../hackathons/rewards/RewardsPageHeader.tsx | 6 +- .../hackathons/rewards/SubmissionListItem.tsx | 133 +- .../hackathons/rewards/SubmissionsList.tsx | 9 +- .../hackathons/rewards/WinnerFormItem.tsx | 75 + .../hackathons/rewards/WinnersBoard.tsx | 327 - .../settings/AdvancedSettingsTab.tsx | 454 +- .../settings/AllocateContributionModal.tsx | 214 +- .../settings/PartnersSettingsTab.tsx | 33 +- .../settings/RewardsSettingsTab.tsx | 2 +- .../hackathons/settings/TracksSettingsTab.tsx | 2 +- components/organization/tabs/MembersTab.tsx | 3 +- .../tabs/MembersTab/MemberCard.tsx | 142 +- .../tabs/MembersTab/PermissionsTable.tsx | 608 +- components/organization/treasury/AuditLog.tsx | 193 - components/organization/treasury/Receipts.tsx | 125 - .../organization/treasury/SendFunds.tsx | 698 - .../organization/treasury/WalletsSection.tsx | 584 - .../project-sidebar/ProjectSidebarLinks.tsx | 33 +- components/providers/auth-provider.tsx | 94 + features/bounties/api/core.ts | 39 - features/bounties/api/draft-client.ts | 74 - features/bounties/api/escrow-client.ts | 93 - features/bounties/api/keys.ts | 13 - features/bounties/api/use-bounties.ts | 19 - features/bounties/api/use-draft.ts | 94 - features/bounties/api/use-escrow.ts | 321 - features/bounties/index.ts | 88 - features/bounties/types.ts | 76 - features/crowdfunding/api/campaign-client.ts | 212 - features/crowdfunding/api/keys.ts | 27 - features/crowdfunding/api/milestone-client.ts | 60 - features/crowdfunding/api/use-campaign.ts | 184 - features/crowdfunding/api/use-milestone.ts | 86 - .../components/CrowdfundingExplore.tsx | 98 - .../components/CrowdfundingPageHero.tsx | 72 - features/crowdfunding/index.ts | 72 - features/crowdfunding/types.ts | 106 - features/hackathons/api/draft-client.ts | 51 - features/hackathons/api/escrow-client.ts | 194 - features/hackathons/api/keys.ts | 14 - features/hackathons/api/use-draft.ts | 117 - features/hackathons/api/use-escrow.ts | 343 - .../hackathons/api/use-generate-from-brief.ts | 42 - .../hackathons/api/use-regenerate-section.ts | 43 - .../hackathons/api/use-submission-anchor.ts | 98 - features/hackathons/index.ts | 113 - features/hackathons/types.ts | 101 - features/projects/api/index.ts | 113 - features/projects/components/ProjectCard.tsx | 104 +- features/projects/types/index.ts | 33 - features/treasury/api.ts | 346 - features/treasury/index.ts | 33 - features/treasury/keys.ts | 24 - features/treasury/types.ts | 178 - features/treasury/use-treasury-audit.ts | 14 - features/treasury/use-treasury-policy.ts | 29 - features/treasury/use-treasury-receipts.ts | 68 - features/treasury/use-treasury-spend.ts | 145 - features/treasury/use-treasury-wallets.ts | 107 - hooks/hackathon/use-cancel-hackathon.ts | 78 - hooks/hackathon/use-delete-hackathon.ts | 2 +- hooks/hackathon/use-hackathon-queries.ts | 3 +- hooks/hackathon/use-hackathons-list.ts | 338 +- hooks/hackathon/use-register-hackathon.ts | 130 + .../api => hooks/hackathon}/use-submission.ts | 95 +- hooks/hackathon/use-team-posts.ts | 4 +- hooks/use-auth.ts | 9 +- hooks/use-bounty-draft.ts | 237 - hooks/use-bounty-publish.ts | 271 - hooks/use-bounty-steps.ts | 131 - hooks/use-follow.ts | 50 +- hooks/use-hackathon-draft.ts | 203 +- hooks/use-hackathon-publish.ts | 343 +- hooks/use-hackathon-rewards.ts | 75 +- hooks/use-hackathon-step-save.ts | 2 - hooks/use-hackathon-steps.ts | 122 +- hooks/use-hackathons.ts | 89 +- hooks/use-publish-winners.ts | 145 +- hooks/use-rank-assignment.ts | 96 + hooks/use-reward-distribution-status.ts | 79 + hooks/use-winners-board.ts | 101 - hooks/use-wizard-steps.ts | 6 +- instrumentation-client.ts | 25 + instrumentation.ts | 13 + lib/api/api.ts | 83 +- lib/api/auth.ts | 25 +- lib/api/client.ts | 166 - lib/api/generated/schema.d.ts | 38604 ------------- lib/api/hackathon.ts | 21 +- lib/api/hackathons.ts | 282 +- lib/api/hackathons/custom-questions.ts | 68 - lib/api/hackathons/draft.ts | 171 + lib/api/hackathons/index.ts | 7 +- lib/api/hackathons/judging.ts | 5 - lib/api/hackathons/participants.ts | 9 +- lib/api/hackathons/partners.ts | 66 +- lib/api/hackathons/rewards.ts | 117 +- lib/api/hackathons/tracks.ts | 83 +- lib/api/hackathons/winners.ts | 107 - lib/api/index.ts | 22 - lib/api/judge.ts | 194 - lib/api/openapi.ts | 28 - lib/api/organization.ts | 14 +- lib/api/types.ts | 52 +- lib/api/user/earnings.ts | 51 +- lib/api/wallet.ts | 22 +- lib/auth/logger.ts | 4 +- lib/config/tokens.ts | 89 - lib/config/wallet-kit.ts | 22 +- lib/crowdfunding/status.ts | 145 - lib/error-reporting.ts | 87 +- lib/providers/OrganizationProvider.tsx | 617 +- lib/providers/hackathonProvider.tsx | 2 +- lib/stores/auth-store.ts | 422 + lib/utils/bounty-escrow.ts | 58 - lib/utils/effective-prize-tiers.ts | 46 - lib/utils/hackathon-escrow.ts | 194 +- lib/utils/hackathon-form-transforms.ts | 243 +- lib/utils/hackathon-step-validation.ts | 63 +- lib/utils/hackathon-winner-distribution.ts | 163 + lib/utils/prize-tier-matcher.ts | 146 + lib/utils/publish-op-storage.ts | 39 - lib/wallet/wallet-kit.ts | 114 - next.config.ts | 9 +- openapi.snapshot.json | 44641 ---------------- package-lock.json | 12899 ++--- package.json | 6 +- sentry.edge.config.ts | 12 + sentry.server.config.ts | 12 + types/earnings.ts | 20 +- types/hackathon/core.ts | 38 +- types/hackathon/draft.ts | 5 +- types/hackathon/index.ts | 1 + types/hackathon/rewards.ts | 75 + 294 files changed, 15361 insertions(+), 119223 deletions(-) delete mode 100644 .claude/launch.json delete mode 100644 app/(landing)/crowdfunding/[slug]/milestones/[id]/page.tsx delete mode 100644 app/(landing)/crowdfunding/[slug]/milestones/page.tsx delete mode 100644 app/(landing)/crowdfunding/[slug]/page.tsx delete mode 100644 app/(landing)/crowdfunding/new/page.tsx delete mode 100644 app/(landing)/crowdfunding/page.tsx delete mode 100644 app/(landing)/hackathons/[slug]/components/AccessGate.tsx delete mode 100644 app/(landing)/hackathons/[slug]/components/RegistrationQuestionsDialog.tsx delete mode 100644 app/(landing)/hackathons/[slug]/components/sidebar/CommunityLinks.tsx create mode 100644 app/(landing)/hackathons/[slug]/components/tabs/contents/index.tsx delete mode 100644 app/(landing)/organizations/[id]/bounties/drafts/[draftId]/page.tsx delete mode 100644 app/(landing)/organizations/[id]/bounties/new/page.tsx delete mode 100644 app/(landing)/organizations/[id]/bounties/page.tsx delete mode 100644 app/(landing)/organizations/[id]/hackathons/[hackathonId]/winners/page.tsx delete mode 100644 app/(landing)/organizations/[id]/treasury/page.tsx delete mode 100644 app/(landing)/organizations/[id]/treasury/receipts/[receiptId]/page.tsx create mode 100644 app/me/crowdfunding/[slug]/components/CampaignBanner.tsx create mode 100644 app/me/crowdfunding/[slug]/components/FundingProgress.tsx create mode 100644 app/me/crowdfunding/[slug]/edit/components/BasicInfoSection.tsx create mode 100644 app/me/crowdfunding/[slug]/edit/components/ContactSocialSection.old.tsx create mode 100644 app/me/crowdfunding/[slug]/edit/components/ContactSocialSection.tsx create mode 100644 app/me/crowdfunding/[slug]/edit/components/DetailsFundingSection.tsx create mode 100644 app/me/crowdfunding/[slug]/edit/components/MilestonesSection.tsx create mode 100644 app/me/crowdfunding/[slug]/edit/components/ProjectLinksSection.tsx create mode 100644 app/me/crowdfunding/[slug]/edit/components/RepoLinksSection.tsx create mode 100644 app/me/crowdfunding/[slug]/edit/components/TeamSection.tsx create mode 100644 app/me/crowdfunding/[slug]/edit/components/index.ts create mode 100644 app/me/crowdfunding/[slug]/edit/components/md-editor-custom.css delete mode 100644 app/me/crowdfunding/[slug]/layout.tsx delete mode 100644 app/me/crowdfunding/new/page.tsx delete mode 100644 components/crowdfunding/CampaignStatusBanner.tsx delete mode 100644 components/crowdfunding/ContributeSheet.tsx delete mode 100644 components/crowdfunding/MilestoneSubmitForm.tsx delete mode 100644 components/crowdfunding/VotePanel.tsx create mode 100644 components/crowdfunding/campaign-funding-tab.tsx create mode 100644 components/crowdfunding/campaign-milestones-tab.tsx create mode 100644 components/crowdfunding/campaign-stats.tsx delete mode 100644 components/crowdfunding/new/NewCampaignSidebar.tsx delete mode 100644 components/crowdfunding/new/NewCampaignWizard.tsx delete mode 100644 components/crowdfunding/new/WizardHelpButton.tsx delete mode 100644 components/crowdfunding/new/constants.ts delete mode 100644 components/crowdfunding/new/fee.ts delete mode 100644 components/crowdfunding/new/milestone-templates.ts delete mode 100644 components/crowdfunding/new/steps/BasicsStep.tsx delete mode 100644 components/crowdfunding/new/steps/FundingStep.tsx delete mode 100644 components/crowdfunding/new/steps/LinksStep.tsx delete mode 100644 components/crowdfunding/new/steps/MilestonesStep.tsx delete mode 100644 components/crowdfunding/new/steps/ReviewStep.tsx delete mode 100644 components/crowdfunding/new/steps/StoryStep.tsx delete mode 100644 components/crowdfunding/new/steps/TeamStep.tsx create mode 100644 components/crowdfunding/quick-links.tsx create mode 100644 components/crowdfunding/submit-evidence-modal.tsx create mode 100644 components/hackathons/overview/RegisterHackathonModal.tsx delete mode 100644 components/hackathons/submissions/SubmissionAnchorProgress.tsx delete mode 100644 components/judge/JudgeAiAssist.tsx delete mode 100644 components/organization/bounties/DeleteBountyDraftDialog.tsx delete mode 100644 components/organization/bounties/new/NewBountyTab.tsx delete mode 100644 components/organization/bounties/new/constants.ts delete mode 100644 components/organization/bounties/new/mock-data.ts delete mode 100644 components/organization/bounties/new/tabs/ModeTab.tsx delete mode 100644 components/organization/bounties/new/tabs/ResourcesTab.tsx delete mode 100644 components/organization/bounties/new/tabs/ReviewTab.tsx delete mode 100644 components/organization/bounties/new/tabs/RewardTab.tsx delete mode 100644 components/organization/bounties/new/tabs/ScopeTab.tsx delete mode 100644 components/organization/bounties/new/tabs/SubmissionModelTab.tsx delete mode 100644 components/organization/bounties/new/tabs/schemas/modeSchema.ts delete mode 100644 components/organization/bounties/new/tabs/schemas/resourcesSchema.ts delete mode 100644 components/organization/bounties/new/tabs/schemas/rewardSchema.ts delete mode 100644 components/organization/bounties/new/tabs/schemas/scopeSchema.ts delete mode 100644 components/organization/bounties/new/tabs/schemas/submissionModelSchema.ts delete mode 100644 components/organization/hackathons/HackathonPublishStatusBanner.tsx delete mode 100644 components/organization/hackathons/judging/AiScorecardsPanel.tsx delete mode 100644 components/organization/hackathons/judging/ImportJudgesCsvDialog.tsx delete mode 100644 components/organization/hackathons/judging/RecommendationThresholdsCard.tsx delete mode 100644 components/organization/hackathons/new/FundingConfirmationModal.tsx delete mode 100644 components/organization/hackathons/new/FundingProgressModal.tsx delete mode 100644 components/organization/hackathons/new/GenerateWithAiDialog.tsx delete mode 100644 components/organization/hackathons/new/RegenerateSectionButton.tsx delete mode 100644 components/organization/hackathons/new/tabs/CustomQuestionsTab.tsx delete mode 100644 components/organization/hackathons/new/tabs/TracksTab.tsx create mode 100644 components/organization/hackathons/rewards/CreateMilestonesDialog.tsx create mode 100644 components/organization/hackathons/rewards/EscrowStatusCard.tsx create mode 100644 components/organization/hackathons/rewards/RewardDistributionStatusBanner.tsx delete mode 100644 components/organization/hackathons/rewards/RewardPayoutProgressModal.tsx create mode 100644 components/organization/hackathons/rewards/WinnerFormItem.tsx delete mode 100644 components/organization/hackathons/rewards/WinnersBoard.tsx delete mode 100644 components/organization/treasury/AuditLog.tsx delete mode 100644 components/organization/treasury/Receipts.tsx delete mode 100644 components/organization/treasury/SendFunds.tsx delete mode 100644 components/organization/treasury/WalletsSection.tsx create mode 100644 components/providers/auth-provider.tsx delete mode 100644 features/bounties/api/core.ts delete mode 100644 features/bounties/api/draft-client.ts delete mode 100644 features/bounties/api/escrow-client.ts delete mode 100644 features/bounties/api/keys.ts delete mode 100644 features/bounties/api/use-bounties.ts delete mode 100644 features/bounties/api/use-draft.ts delete mode 100644 features/bounties/api/use-escrow.ts delete mode 100644 features/bounties/index.ts delete mode 100644 features/bounties/types.ts delete mode 100644 features/crowdfunding/api/campaign-client.ts delete mode 100644 features/crowdfunding/api/keys.ts delete mode 100644 features/crowdfunding/api/milestone-client.ts delete mode 100644 features/crowdfunding/api/use-campaign.ts delete mode 100644 features/crowdfunding/api/use-milestone.ts delete mode 100644 features/crowdfunding/components/CrowdfundingExplore.tsx delete mode 100644 features/crowdfunding/components/CrowdfundingPageHero.tsx delete mode 100644 features/crowdfunding/index.ts delete mode 100644 features/crowdfunding/types.ts delete mode 100644 features/hackathons/api/draft-client.ts delete mode 100644 features/hackathons/api/escrow-client.ts delete mode 100644 features/hackathons/api/keys.ts delete mode 100644 features/hackathons/api/use-draft.ts delete mode 100644 features/hackathons/api/use-escrow.ts delete mode 100644 features/hackathons/api/use-generate-from-brief.ts delete mode 100644 features/hackathons/api/use-regenerate-section.ts delete mode 100644 features/hackathons/api/use-submission-anchor.ts delete mode 100644 features/hackathons/index.ts delete mode 100644 features/hackathons/types.ts delete mode 100644 features/treasury/api.ts delete mode 100644 features/treasury/index.ts delete mode 100644 features/treasury/keys.ts delete mode 100644 features/treasury/types.ts delete mode 100644 features/treasury/use-treasury-audit.ts delete mode 100644 features/treasury/use-treasury-policy.ts delete mode 100644 features/treasury/use-treasury-receipts.ts delete mode 100644 features/treasury/use-treasury-spend.ts delete mode 100644 features/treasury/use-treasury-wallets.ts delete mode 100644 hooks/hackathon/use-cancel-hackathon.ts create mode 100644 hooks/hackathon/use-register-hackathon.ts rename {features/hackathons/api => hooks/hackathon}/use-submission.ts (78%) delete mode 100644 hooks/use-bounty-draft.ts delete mode 100644 hooks/use-bounty-publish.ts delete mode 100644 hooks/use-bounty-steps.ts create mode 100644 hooks/use-rank-assignment.ts create mode 100644 hooks/use-reward-distribution-status.ts delete mode 100644 hooks/use-winners-board.ts create mode 100644 instrumentation-client.ts create mode 100644 instrumentation.ts delete mode 100644 lib/api/client.ts delete mode 100644 lib/api/generated/schema.d.ts delete mode 100644 lib/api/hackathons/custom-questions.ts create mode 100644 lib/api/hackathons/draft.ts delete mode 100644 lib/api/hackathons/winners.ts delete mode 100644 lib/api/index.ts delete mode 100644 lib/api/openapi.ts delete mode 100644 lib/config/tokens.ts delete mode 100644 lib/crowdfunding/status.ts create mode 100644 lib/stores/auth-store.ts delete mode 100644 lib/utils/bounty-escrow.ts delete mode 100644 lib/utils/effective-prize-tiers.ts create mode 100644 lib/utils/hackathon-winner-distribution.ts create mode 100644 lib/utils/prize-tier-matcher.ts delete mode 100644 lib/utils/publish-op-storage.ts delete mode 100644 lib/wallet/wallet-kit.ts delete mode 100644 openapi.snapshot.json create mode 100644 sentry.edge.config.ts create mode 100644 sentry.server.config.ts create mode 100644 types/hackathon/rewards.ts diff --git a/.claude/launch.json b/.claude/launch.json deleted file mode 100644 index cab285df2..000000000 --- a/.claude/launch.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "0.0.1", - "configurations": [ - { - "name": "boundless-v1", - "runtimeExecutable": "npm", - "runtimeArgs": ["run", "dev"], - "port": 3000 - } - ] -} diff --git a/.env.example b/.env.example index 34910cd13..50e04a865 100644 --- a/.env.example +++ b/.env.example @@ -22,10 +22,12 @@ NEXT_PUBLIC_GOOGLE_CLIENT_ID="" NEXT_PUBLIC_HORIZON_PUBLIC_URL="https://horizon.stellar.org" NEXT_PUBLIC_HORIZON_TESTNET_URL="https://horizon-testnet.stellar.org" NEXT_PUBLIC_STELLAR_NETWORK="testnet" -# Whitelisted USDC SAC (Soroban contract C-address) used as the escrow tokenAddress. -# Must match the boundless-events contract's whitelisted token (see backend admin runbook). -NEXT_PUBLIC_USDC_TOKEN_CONTRACT_TESTNET="CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA" -NEXT_PUBLIC_USDC_TOKEN_CONTRACT_PUBLIC="" NEXT_PUBLIC_TRUSTLESS_WORK_API_KEY="" NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID="your_wallet_connect_project_id" +# Error reporting (optional). When set, errors are sent to Sentry. +NEXT_PUBLIC_SENTRY_DSN="" +SENTRY_DSN="" +SENTRY_ORG="" +SENTRY_PROJECT="boundless-next" +SENTRY_AUTH_TOKEN="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" NODE_ENV="dev" \ No newline at end of file diff --git a/.husky/pre-push b/.husky/pre-push index abfcad5e9..a0b25c772 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -1,14 +1,23 @@ -#!/usr/bin/env sh -set -e + echo "๐Ÿš€ Running pre-push checks..." +# Run all tests (if you have them) +# echo "๐Ÿงช Running tests..." +# npm test + +# Run security audit +echo "๐Ÿ”’ Running security audit..." +npm audit --omit=dev --audit-level=high -echo "๐Ÿ”’ Auditing dependencies (non-blocking)..." -npm audit --omit=dev --audit-level=high || true +# Run build check one more time +# echo "๐Ÿ—๏ธ Final build check..." +# npm run build +# Check for any uncommitted changes if ! git diff-index --quiet HEAD --; then - echo "โš ๏ธ You have uncommitted changes โ€” they won't be included in this push." + echo "โš ๏ธ Warning: You have uncommitted changes." + echo " Consider committing them before pushing." fi -echo "โœ… Pre-push checks passed!" +echo "โœ… Pre-push checks completed!" diff --git a/app/(landing)/crowdfunding/[slug]/milestones/[id]/page.tsx b/app/(landing)/crowdfunding/[slug]/milestones/[id]/page.tsx deleted file mode 100644 index c022905fb..000000000 --- a/app/(landing)/crowdfunding/[slug]/milestones/[id]/page.tsx +++ /dev/null @@ -1,383 +0,0 @@ -'use client'; - -import { use } from 'react'; -import Link from 'next/link'; -import { - ArrowLeft, - CalendarDays, - CheckCircle2, - Clock, - ExternalLink, - FileText, - AlertTriangle, - RefreshCw, -} from 'lucide-react'; - -import { useCampaign, useMilestone } from '@/features/crowdfunding'; -import { Badge } from '@/components/ui/badge'; -import { cn } from '@/lib/utils'; -import { milestoneState, TONE_PILL } from '@/lib/crowdfunding/status'; - -interface PageProps { - params: Promise<{ slug: string; id: string }>; -} - -interface MilestoneDetail { - id: string; - title?: string | null; - name?: string | null; - description?: string | null; - deliverable?: string | null; - successCriteria?: string | null; - fundingPercentage?: number | null; - amount?: number | null; - expectedDeliveryDate?: string | null; - endDate?: string | null; - startDate?: string | null; - orderIndex?: number | null; - reviewStatus?: string | null; - submittedAt?: string | null; - proofOfWorkFiles?: string[]; - proofOfWorkLinks?: string[]; - submissionNotes?: string | null; - reviewedAt?: string | null; - rejectionReason?: string | null; - rejectionFeedback?: string | null; - resubmissionDeadline?: string | null; - completedAt?: string | null; - claimedAt?: string | null; - isOverdue?: boolean; - daysRemaining?: number | null; -} - -function formatDate(dateStr?: string | null): string | null { - if (!dateStr) return null; - const d = new Date(dateStr); - if (Number.isNaN(d.getTime())) return null; - return d.toLocaleDateString('en-US', { - month: 'long', - day: 'numeric', - year: 'numeric', - }); -} - -function Section({ - title, - children, -}: { - title: string; - children: React.ReactNode; -}) { - return ( -
-

- {title} -

- {children} -
- ); -} - -function MetaRow({ label, value }: { label: string; value: React.ReactNode }) { - return ( -
- {label} - {value} -
- ); -} - -export default function PublicMilestoneDetailPage({ params }: PageProps) { - const { slug, id } = use(params); - const { data: campaign, isLoading: campaignLoading } = useCampaign(slug); - const { data: milestoneRaw, isLoading: milestoneLoading } = useMilestone( - campaign?.id ?? null, - id - ); - - const isLoading = campaignLoading || (!!campaign?.id && milestoneLoading); - - if (isLoading) { - return ( -
- Loading... -
- ); - } - - if (!campaign || !milestoneRaw) { - return ( -
- Milestone not found. -
- ); - } - - const m = milestoneRaw as MilestoneDetail; - const milestones = campaign.milestones ?? []; - const idx = milestones.findIndex(ms => ms.id === id); - const orderNumber = idx >= 0 ? idx + 1 : null; - - const st = milestoneState(m.reviewStatus, m.claimedAt); - const dueDate = formatDate(m.expectedDeliveryDate ?? m.endDate); - const submittedAt = formatDate(m.submittedAt); - const reviewedAt = formatDate(m.reviewedAt); - - const totalAmount = milestones.reduce((s, ms) => s + (ms.amount ?? 0), 0); - const pct = - totalAmount > 0 && m.amount != null - ? Math.round((m.amount / totalAmount) * 100) - : null; - - const hasEvidence = - m.submittedAt || - (m.proofOfWorkLinks?.length ?? 0) > 0 || - (m.proofOfWorkFiles?.length ?? 0) > 0 || - m.submissionNotes; - - const hasReviewOutcome = - m.reviewedAt || m.rejectionFeedback || m.rejectionReason || m.claimedAt; - - const isRejected = - m.reviewStatus === 'REJECTED' || m.reviewStatus === 'RESUBMISSION_REQUIRED'; - - return ( -
- {/* Nav bar */} -
-
- - - All milestones - -
-
- -
- {/* Header */} -
-
-
- {campaign.project.title} - {orderNumber && ( - <> - / - Milestone {orderNumber} - - )} -
-

- {m.title ?? m.name ?? 'Untitled milestone'} -

-
- - {st.label} - -
- - {/* Key facts */} -
-
- {m.amount != null && ( - - ${m.amount.toLocaleString()} USDC - {pct != null && ( - - {pct}% of total - - )} - - } - /> - )} - {dueDate && ( - - - {dueDate} - {m.isOverdue && ( - Overdue - )} - - } - /> - )} - {submittedAt && ( - - - {submittedAt} - - } - /> - )} - {reviewedAt && ( - - - {reviewedAt} - - } - /> - )} -
-
- - {/* Description */} - {m.description && ( -
-

- {m.description} -

-
- )} - - {/* Deliverable */} - {m.deliverable && ( -
-

- {m.deliverable} -

-
- )} - - {/* Success criteria */} - {m.successCriteria && ( -
-

- {m.successCriteria} -

-
- )} - - {/* Evidence submitted by the builder */} - {hasEvidence && ( -
- {m.submissionNotes && ( -
-

Notes

-

- {m.submissionNotes} -

-
- )} - - {(m.proofOfWorkLinks?.length ?? 0) > 0 && ( -
-

Links

-
    - {m.proofOfWorkLinks!.map((link, i) => ( -
  • - - - {link} - -
  • - ))} -
-
- )} - - {(m.proofOfWorkFiles?.length ?? 0) > 0 && ( -
-

Files

- -
- )} -
- )} - - {/* Review outcome */} - {hasReviewOutcome && ( -
- {m.claimedAt && ( -
- -
-

- Paid out -

- {m.amount != null && ( -

- ${m.amount.toLocaleString()} USDC -

- )} - {formatDate(m.claimedAt) && ( -

- {formatDate(m.claimedAt)} -

- )} -
-
- )} - - {isRejected && (m.rejectionReason || m.rejectionFeedback) && ( -
- -
-

- {m.reviewStatus === 'RESUBMISSION_REQUIRED' - ? 'Resubmission required' - : 'Not accepted'} -

- {m.rejectionReason && ( -

- {m.rejectionReason} -

- )} - {m.rejectionFeedback && ( -

- {m.rejectionFeedback} -

- )} - {m.resubmissionDeadline && ( -
- - Resubmit by {formatDate(m.resubmissionDeadline)} -
- )} -
-
- )} -
- )} -
-
- ); -} diff --git a/app/(landing)/crowdfunding/[slug]/milestones/page.tsx b/app/(landing)/crowdfunding/[slug]/milestones/page.tsx deleted file mode 100644 index 815b8e66c..000000000 --- a/app/(landing)/crowdfunding/[slug]/milestones/page.tsx +++ /dev/null @@ -1,189 +0,0 @@ -'use client'; - -import { use } from 'react'; -import Link from 'next/link'; -import { ArrowLeft, CalendarDays, ChevronRight } from 'lucide-react'; - -import { useCampaign } from '@/features/crowdfunding'; -import { Badge } from '@/components/ui/badge'; -import { cn } from '@/lib/utils'; -import { - campaignStatus, - milestoneState, - TONE_PILL, -} from '@/lib/crowdfunding/status'; - -interface PageProps { - params: Promise<{ slug: string }>; -} - -function formatDate(dateStr?: string): string | null { - if (!dateStr) return null; - const d = new Date(dateStr); - if (Number.isNaN(d.getTime())) return null; - return d.toLocaleDateString('en-US', { - month: 'long', - day: 'numeric', - year: 'numeric', - }); -} - -export default function PublicMilestonesPage({ params }: PageProps) { - const { slug } = use(params); - const { data: campaign, isLoading } = useCampaign(slug); - - if (isLoading) { - return ( -
- Loading... -
- ); - } - - if (!campaign) { - return ( -
- Campaign not found. -
- ); - } - - const status = campaignStatus(campaign.v2Status); - const milestones = campaign.milestones ?? []; - const totalAmount = milestones.reduce((s, m) => s + (m.amount ?? 0), 0); - - return ( -
-
-
- - - Back to campaign - -
-
- -
- {/* Campaign header */} -
- {campaign.project.logo && ( - // eslint-disable-next-line @next/next/no-img-element - {campaign.project.title} - )} -
-

- {campaign.project.title} -

-
- - {status.label} - -
- -
-

- Milestones{' '} - - ({milestones.length}) - -

-

- Funds are released one stage at a time as each milestone is - delivered and approved. -

-
- - {milestones.length === 0 ? ( -

No milestones listed.

- ) : ( -
- {milestones.map((m, idx) => { - const st = milestoneState(m.reviewStatus); - const planned = formatDate(m.endDate); - const pct = - totalAmount > 0 - ? Math.round(((m.amount ?? 0) / totalAmount) * 100) - : 0; - - return m.id ? ( - - {/* Number chip */} -
- {idx + 1} -
- -
-

- {m.title || m.name} -

- {m.description && ( -

- {m.description} -

- )} -
- {m.amount != null && ( - ${m.amount.toLocaleString()} USDC - )} - {pct > 0 && {pct}% of total} - {planned && ( - - - {planned} - - )} -
-
- -
- - {st.label} - - -
- - ) : ( -
-
- {idx + 1} -
-
-

- {m.title || m.name} -

-
- - {st.label} - -
- ); - })} -
- )} -
-
- ); -} diff --git a/app/(landing)/crowdfunding/[slug]/page.tsx b/app/(landing)/crowdfunding/[slug]/page.tsx deleted file mode 100644 index 17aacf54f..000000000 --- a/app/(landing)/crowdfunding/[slug]/page.tsx +++ /dev/null @@ -1,625 +0,0 @@ -'use client'; - -import { useState, use } from 'react'; -import Image from 'next/image'; -import Link from 'next/link'; -import { - ArrowLeft, - Users, - Github, - Globe, - Video, - ExternalLink, - ShieldCheck, - CalendarDays, -} from 'lucide-react'; - -import { useCampaign } from '@/features/crowdfunding'; -import type { CrowdfundingContributor } from '@/features/crowdfunding'; -import { - ContributeSheet, - MIN_CONTRIBUTION, -} from '@/components/crowdfunding/ContributeSheet'; -import { VotePanel } from '@/components/crowdfunding/VotePanel'; -import { Button } from '@/components/ui/button'; -import { Badge } from '@/components/ui/badge'; -import { cn } from '@/lib/utils'; -import { - campaignStatus, - milestoneState, - TONE_PILL, -} from '@/lib/crowdfunding/status'; -import { getTransactionExplorerUrl } from '@/lib/wallet-utils'; -import { useAuthStatus } from '@/hooks/use-auth'; - -interface PageProps { - params: Promise<{ slug: string }>; -} - -function daysLeft(dateStr?: string): number | null { - if (!dateStr) return null; - const diff = new Date(dateStr).getTime() - Date.now(); - return Math.max(0, Math.ceil(diff / 86_400_000)); -} - -function formatDate(dateStr?: string): string | null { - if (!dateStr) return null; - const d = new Date(dateStr); - if (Number.isNaN(d.getTime())) return null; - return d.toLocaleDateString('en-US', { - month: 'long', - day: 'numeric', - year: 'numeric', - }); -} - -function pct(raised: number, goal: number): number { - if (!goal) return 0; - return Math.min(100, Math.round((raised / goal) * 100)); -} - -function SupporterRow({ c }: { c: CrowdfundingContributor }) { - const isAnon = !c.username && !c.name; - const dateLabel = new Date(c.date).toLocaleDateString('en-US', { - month: 'short', - day: 'numeric', - }); - return ( -
-
- {c.image ? ( - {c.name - ) : ( -
- {isAnon - ? '?' - : (c.name || c.username || 'S').charAt(0).toUpperCase()} -
- )} -
-
-

- {isAnon ? 'Anonymous supporter' : c.name || c.username} -

- {c.message && ( -

{c.message}

- )} -
-
-

- ${c.amount.toLocaleString()} -

- {c.transactionHash ? ( - - {dateLabel} - - - ) : ( -

{dateLabel}

- )} -
-
- ); -} - -function Section({ - title, - children, -}: { - title: string; - children: React.ReactNode; -}) { - return ( -
-

{title}

- {children} -
- ); -} - -export default function PublicCampaignPage({ params }: PageProps) { - const { slug } = use(params); - const { data: campaign, isLoading } = useCampaign(slug); - const [sheetOpen, setSheetOpen] = useState(false); - const { user } = useAuthStatus(); - - if (isLoading) { - return ( -
- Loading... -
- ); - } - - if (!campaign) { - return ( -
- Campaign not found. -
- ); - } - - const project = campaign.project; - const raised = campaign.fundingRaised ?? 0; - const goal = campaign.fundingGoal ?? 0; - const progress = pct(raised, goal); - const days = daysLeft(campaign.fundingEndDate); - const closeDate = formatDate(campaign.fundingEndDate); - const supporters = campaign.contributors ?? []; - - const isFunding = campaign.v2Status === 'FUNDING'; - const isVoting = campaign.v2Status === 'VOTING'; - const isComplete = campaign.v2Status === 'COMPLETED'; - const showFundingStats = isFunding || isComplete; - // Funded once less than the contract minimum remains (the last sliver can't - // be filled per the on-chain floor), so we stop offering "Back this project". - const isFullyFunded = - isFunding && goal > 0 && goal - raised < MIN_CONTRIBUTION; - - const completedMilestones = campaign.milestones.filter(m => - Boolean(m.claimedAt) - ).length; - - const baseStatus = campaignStatus(campaign.v2Status); - const status = isFullyFunded - ? { - label: 'Fully Funded', - tone: 'success' as const, - description: baseStatus.description, - } - : baseStatus; - - const isOwnerOrTeam = - !!user?.id && - (user.id === project.creatorId || - campaign.team.some(m => m.id === user.id)); - // Statuses the public is allowed to observe. All others are pre-launch or - // terminal-negative and should not expose internal status copy to strangers. - const isPublicStatus = - campaign.v2Status === 'VOTING' || - campaign.v2Status === 'FUNDING' || - campaign.v2Status === 'PAUSED' || - campaign.v2Status === 'COMPLETED'; - - return ( -
- {/* Back link */} -
-
- - - All campaigns - -
-
- - {/* Hero */} - {project.banner ? ( -
- {project.title} -
-
- ) : ( -
- )} - -
- {/* Title row */} -
- {project.logo && ( -
- {project.title} -
- )} -
-
-

- {project.title} -

- - {status.label} - -
- {project.tagline && ( -

{project.tagline}

- )} -
-
- -
- {/* Main content โ€” single scroll */} -
- {/* Story */} -
-
- {project.vision || project.description || ( - - No description provided. - - )} -
- {(project.githubUrl || - project.projectWebsite || - project.demoVideo) && ( -
- {project.githubUrl && ( - - - Code - - - )} - {project.projectWebsite && ( - - - Website - - - )} - {project.demoVideo && ( - - - )} -
- )} -
- - {/* Milestones */} -
0 - ? `Milestones (${completedMilestones} / ${campaign.milestones.length} delivered)` - : 'Milestones' - } - > -

- The plan is delivered in stages. Funds are released to the team - one stage at a time, as each is delivered and approved by a - reviewer. -

- {campaign.milestones.length === 0 ? ( -

No milestones listed.

- ) : ( -
- {campaign.milestones.map((m, idx) => { - const st = milestoneState(m.reviewStatus, m.claimedAt); - const planned = formatDate(m.endDate); - const inner = ( - <> -
-
-

- {idx + 1}. {m.title || m.name} -

- {m.description && ( -

- {m.description} -

- )} -
-
- {showFundingStats && m.amount != null && ( - - ${m.amount.toLocaleString()} - - )} - - {st.label} - -
-
- {planned && ( -

- - Planned for {planned} -

- )} - - ); - return m.id ? ( - - {inner} - - ) : ( -
- {inner} -
- ); - })} -
- )} -
- - {/* Team */} - {campaign.team.length > 0 && ( -
-
- {campaign.team.map((m, idx) => ( -
-
- {m.image ? ( - {m.name} - ) : ( -
- {m.name.charAt(0).toUpperCase()} -
- )} -
-
-

- {m.name} -

-

{m.role}

-
-
- ))} -
-
- )} - - {/* Supporters */} -
- {supporters.length === 0 ? ( -
- -

- No supporters yet. - {isFunding ? ' Be the first to back this.' : ''} -

-
- ) : ( -
- {supporters.map((c, i) => ( - - ))} -
- )} -
-
- - {/* Sticky sidebar โ€” funding + action */} -
-
-
- {showFundingStats ? ( - <> -
-
-
-
-
- {progress}% funded - {isFunding && days !== null && ( - - {days} {days === 1 ? 'day' : 'days'} left - - )} -
-
-
-

- ${raised.toLocaleString()} -

-

- raised of ${goal.toLocaleString()} goal -

-
-

- {supporters.length}{' '} - {supporters.length === 1 ? 'supporter' : 'supporters'} - {isFunding && closeDate ? ` ยท closes ${closeDate}` : ''} -

- - ) : ( -
-
-

- ${goal.toLocaleString()}{' '} - - {campaign.fundingCurrency ?? 'USDC'} - -

-

funding goal

-
- {campaign.milestones.length > 0 && ( -

- {campaign.milestones.length}{' '} - {campaign.milestones.length === 1 - ? 'milestone' - : 'milestones'}{' '} - planned -

- )} -
- )} - - {/* Primary action by state */} - {isOwnerOrTeam ? ( - // Owner/team: show their private status info; no voting or funding actions. -
-

{status.label}

-

- {status.description} -

-
- ) : isFunding && !isFullyFunded ? ( - <> - -

- - Your support is held safely and released to the team as - each milestone is delivered and approved. -

- - ) : isFullyFunded ? ( -
-

- Fully funded -

-

- This campaign reached its goal. Thanks to all{' '} - {supporters.length}{' '} - {supporters.length === 1 ? 'supporter' : 'supporters'}. -

-
- ) : isVoting ? ( - - ) : isPublicStatus ? ( -
-

{status.label}

-

- {status.description} -

-
- ) : ( - // Pre-launch or terminal state accessed via direct URL; not in public listing. -
-

- Not yet open -

-

- This campaign is not yet available to the public. -

-
- )} -
- - {/* Creator */} - {project.creator && ( -
-

- Creator -

-
-
- {project.creator.image ? ( - {project.creator.name} - ) : ( -
- {(project.creator.name || 'C') - .charAt(0) - .toUpperCase()} -
- )} -
-
-

- {project.creator.name} -

- {project.creator.username && ( -

- @{project.creator.username} -

- )} -
-
-
- )} -
-
-
-
- - {!isOwnerOrTeam && ( - - )} -
- ); -} diff --git a/app/(landing)/crowdfunding/new/page.tsx b/app/(landing)/crowdfunding/new/page.tsx deleted file mode 100644 index 639161779..000000000 --- a/app/(landing)/crowdfunding/new/page.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { Metadata } from 'next'; -import { AuthGuard } from '@/components/auth'; -import { Suspense } from 'react'; -import NewCampaignWizard from '@/components/crowdfunding/new/NewCampaignWizard'; - -export const metadata: Metadata = { - title: 'New Campaign | Boundless', - description: 'Create a new crowdfunding campaign on Boundless', -}; - -export default function NewCampaignPage() { - return ( - Authenticating...
} - > - Loading...
}> - - - - ); -} diff --git a/app/(landing)/crowdfunding/page.tsx b/app/(landing)/crowdfunding/page.tsx deleted file mode 100644 index b46b0855b..000000000 --- a/app/(landing)/crowdfunding/page.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import CrowdfundingExplore from '@/features/crowdfunding/components/CrowdfundingExplore'; -import CrowdfundingPageHero from '@/features/crowdfunding/components/CrowdfundingPageHero'; - -export default function CrowdfundingPage() { - return ( -
-
-
- - -
-
-
- ); -} diff --git a/app/(landing)/hackathons/[slug]/components/AccessGate.tsx b/app/(landing)/hackathons/[slug]/components/AccessGate.tsx deleted file mode 100644 index 47821b75f..000000000 --- a/app/(landing)/hackathons/[slug]/components/AccessGate.tsx +++ /dev/null @@ -1,83 +0,0 @@ -'use client'; - -import { useState } from 'react'; -import { useRouter } from 'next/navigation'; -import { Loader2, Lock } from 'lucide-react'; -import { toast } from 'sonner'; -import { BoundlessButton } from '@/components/buttons'; -import { Input } from '@/components/ui/input'; -import { verifyHackathonAccess } from '@/lib/api/hackathon'; - -/** - * Shown when a private hackathon's public page is opened without access. On a - * correct password we store a slug-keyed cookie and refresh; the server then - * reads the cookie, forwards the token, and renders the unlocked page. - */ -export default function AccessGate({ - slug, - name, - description, -}: { - slug: string; - name: string; - description?: string | null; -}) { - const router = useRouter(); - const [password, setPassword] = useState(''); - const [submitting, setSubmitting] = useState(false); - - const submit = async (e: React.FormEvent) => { - e.preventDefault(); - if (!password.trim()) return; - setSubmitting(true); - try { - const { accessToken } = await verifyHackathonAccess( - slug, - password.trim() - ); - if (!accessToken) throw new Error('No access token'); - document.cookie = `hx_access_${slug}=${accessToken}; path=/; max-age=86400; samesite=lax`; - router.refresh(); - } catch (err) { - const msg = (err as { response?: { data?: { message?: string } } }) - ?.response?.data?.message; - toast.error(msg || 'That password is not right. Try again.'); - setSubmitting(false); - } - }; - - return ( -
-
-
- -
-

{name}

-

- {description || 'This hackathon is private.'} Enter the password to - view it. -

-
- setPassword(e.target.value)} - placeholder='Password' - autoFocus - className='border-gray-700 bg-black text-center text-white' - /> - - - {submitting ? : null} - Unlock - - -
-
-
- ); -} diff --git a/app/(landing)/hackathons/[slug]/components/RegistrationQuestionsDialog.tsx b/app/(landing)/hackathons/[slug]/components/RegistrationQuestionsDialog.tsx deleted file mode 100644 index fc78e0540..000000000 --- a/app/(landing)/hackathons/[slug]/components/RegistrationQuestionsDialog.tsx +++ /dev/null @@ -1,191 +0,0 @@ -'use client'; - -import { useEffect, useState } from 'react'; -import { useQuery } from '@tanstack/react-query'; -import { toast } from 'sonner'; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from '@/components/ui/dialog'; -import { Input } from '@/components/ui/input'; -import { Textarea } from '@/components/ui/textarea'; -import { BoundlessButton } from '@/components/buttons'; -import { cn } from '@/lib/utils'; -import { - listPublicCustomQuestions, - type CustomQuestion, -} from '@/lib/api/hackathons/custom-questions'; - -/** - * Cached fetch of a hackathon's REGISTRATION-scope custom questions. The - * register buttons use this to decide whether registration needs a form - * (questions present) or can join directly (none). - */ -export function useRegistrationQuestions(slug: string) { - return useQuery({ - queryKey: ['hackathon', 'custom-questions', slug, 'REGISTRATION'], - queryFn: () => listPublicCustomQuestions(slug, 'REGISTRATION'), - enabled: !!slug, - staleTime: 60_000, - }); -} - -interface RegistrationQuestionsDialogProps { - open: boolean; - onOpenChange: (open: boolean) => void; - questions: CustomQuestion[]; - submitting?: boolean; - /** Persist + join. Resolve to close the dialog; reject to keep it open. */ - onSubmit: (answers: Record) => Promise; -} - -export default function RegistrationQuestionsDialog({ - open, - onOpenChange, - questions, - submitting, - onSubmit, -}: RegistrationQuestionsDialogProps) { - const [answers, setAnswers] = useState>({}); - - // Reset the form each time the dialog opens so a cancelled attempt does not - // leak into the next one. - useEffect(() => { - if (open) setAnswers({}); - }, [open]); - - const setAnswer = (id: string, val: string | string[]) => - setAnswers(prev => ({ ...prev, [id]: val })); - - const handleSubmit = async () => { - for (const q of questions) { - if (!q.required) continue; - const v = answers[q.id]; - const empty = Array.isArray(v) - ? v.length === 0 - : !v || String(v).trim() === ''; - if (empty) { - toast.error(`"${q.label}" is required.`); - return; - } - } - await onSubmit(answers); - }; - - return ( - - - - A few questions before you register - - The organizer asks these when you join. - - - -
- {questions.map(q => { - const options = Array.isArray(q.options) ? q.options : []; - const raw = answers[q.id]; - const strVal = typeof raw === 'string' ? raw : ''; - const arrVal = Array.isArray(raw) ? raw : []; - return ( -
- - {q.type === 'LONG' ? ( -