diff --git a/.env.example b/.env.example
index bd0cd9e2b..8db3c9007 100644
--- a/.env.example
+++ b/.env.example
@@ -1,53 +1,23 @@
-# Stellar Network Configuration
-NEXT_PUBLIC_STELLAR_NETWORK=testnet
-# Options: testnet, public
-
-# Application Configuration
-NEXT_PUBLIC_APP_URL=http://localhost:3000
-# Your application's public URL
-
-# API Configuration
-NEXT_PUBLIC_API_URL=http://localhost:8000/api
-# Your backend API URL
-
-# WalletConnect Configuration
-NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=your_wallet_connect_project_id
-# Get this from https://cloud.walletconnect.com/
-
-# Stellar Horizon URLs (optional - defaults will be used)
-NEXT_PUBLIC_HORIZON_TESTNET_URL=https://horizon-testnet.stellar.org
-NEXT_PUBLIC_HORIZON_PUBLIC_URL=https://horizon.stellar.org
-
-# Application Metadata
-NEXT_PUBLIC_APP_NAME=Boundless
-NEXT_PUBLIC_APP_DESCRIPTION=Stellar-based application
-NEXT_PUBLIC_APP_ICON=/logo.svg
-
-# Development Settings
-NEXT_PUBLIC_DEBUG_MODE=false
-# Enable debug logging for wallet operations
-
-# Feature Flags
-NEXT_PUBLIC_ENABLE_WALLET_CONNECT=true
-NEXT_PUBLIC_ENABLE_MULTI_WALLET=true
-NEXT_PUBLIC_ENABLE_NETWORK_SWITCHING=true
-
-# NextAuth Configuration
-NEXTAUTH_SECRET=your_nextauth_secret_here
-# Generate a random string for this secret
-# You can use: openssl rand -base64 32
-
-NEXTAUTH_URL=http://localhost:3000
-# Your application's public URL (same as NEXT_PUBLIC_APP_URL)
-
-# Google OAuth Configuration
-GOOGLE_CLIENT_ID=your_google_client_id
-# Get this from Google Cloud Console
-
-GOOGLE_CLIENT_SECRET=your_google_client_secret
-# Get this from Google Cloud Console
-
-# Environment
-NODE_ENV=development
-# Options: development, production, test
-
+# Created by Vercel CLI
+GOOGLE_CLIENT_ID=""
+GOOGLE_CLIENT_SECRET="your_google_client_secret"
+NEXTAUTH_SECRET="PiRlq+7IyU5QJuCiVwjiuwZUGCqc/3qw1QPgLOt2AFg="
+NEXTAUTH_URL="http://localhost:3000"
+NEXT_PUBLIC_API_URL="https://stage-api.boundlessfi.xyz/api"
+NEXT_PUBLIC_APP_DESCRIPTION="Stellar-based application"
+NEXT_PUBLIC_APP_ICON="/logo.svg"
+NEXT_PUBLIC_APP_NAME="Boundless"
+NEXT_PUBLIC_APP_URL="http://localhost:3000"
+NEXT_PUBLIC_BETTER_AUTH_URL="https://stage-api.boundlessfi.xyz"
+NEXT_PUBLIC_BOUNDLESS_PLATFORM_ADDRESS=""
+NEXT_PUBLIC_DEBUG_MODE="false"
+NEXT_PUBLIC_ENABLE_MULTI_WALLET="true"
+NEXT_PUBLIC_ENABLE_NETWORK_SWITCHING="true"
+NEXT_PUBLIC_ENABLE_WALLET_CONNECT="true"
+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"
+NEXT_PUBLIC_TRUSTLESS_WORK_API_KEY=""
+NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID="your_wallet_connect_project_id"
+NODE_ENV="dev"
\ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 53a07fc36..aaa770101 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -123,7 +123,7 @@ jobs:
run: |
echo "๐ Checking for known vulnerabilities..."
npm audit --audit-level=moderate --json > audit-report.json
- if jq -e '.metadata.vulnerabilities.total > 0' audit-report.json; then
+ if jq -e '(.metadata.vulnerabilities.moderate + .metadata.vulnerabilities.high + .metadata.vulnerabilities.critical) > 0' audit-report.json; then
echo "โ Found security vulnerabilities. Please fix them before merging."
cat audit-report.json | jq '.metadata.vulnerabilities'
exit 1
@@ -158,7 +158,12 @@ jobs:
while IFS= read -r commit; do
hash=$(echo "$commit" | cut -d' ' -f1)
message=$(echo "$commit" | cut -d' ' -f2-)
-
+
+ # Skip git-generated merge commits
+ if echo "$message" | grep -qE "^Merge (branch|pull request|remote-tracking branch|[0-9a-f]{7,40}) "; then
+ continue
+ fi
+
if ! echo "$message" | grep -qE "$commit_regex"; then
invalid_commits="$invalid_commits\n$hash: $message"
fi
diff --git a/.github/workflows/pre-commit-validation.yml b/.github/workflows/pre-commit-validation.yml
index a7c115934..1f9e02324 100644
--- a/.github/workflows/pre-commit-validation.yml
+++ b/.github/workflows/pre-commit-validation.yml
@@ -55,7 +55,11 @@ jobs:
invalid_commits=""
while IFS= read -r message; do
- if [ -n "$message" ] && ! echo "$message" | grep -qE "$commit_regex"; then
+ # Skip empty lines and git-generated merge commits
+ if [ -z "$message" ] || echo "$message" | grep -qE "^Merge (branch|pull request|remote-tracking branch|[0-9a-f]{7,40}) "; then
+ continue
+ fi
+ if ! echo "$message" | grep -qE "$commit_regex"; then
invalid_commits="$invalid_commits\n$message"
fi
done <<< "$commits"
@@ -85,7 +89,7 @@ jobs:
console_log_found=false
for file in $changed_files; do
- if [[ "$file" =~ \.(ts|tsx|js|jsx)$ ]]; then
+ if [[ "$file" =~ \.(ts|tsx|js|jsx)$ ]] && [ -f "$file" ]; then
if grep -q "console\.log" "$file"; then
echo "โ Found console.log in $file"
console_log_found=true
@@ -115,7 +119,7 @@ jobs:
todo_found=false
for file in $changed_files; do
- if [[ "$file" =~ \.(ts|tsx|js|jsx)$ ]]; then
+ if [[ "$file" =~ \.(ts|tsx|js|jsx)$ ]] && [ -f "$file" ]; then
if grep -q "TODO\|FIXME" "$file"; then
echo "โ ๏ธ Found TODO/FIXME in $file"
todo_found=true
diff --git a/.husky/pre-push b/.husky/pre-push
index a4447e2ce..a0b25c772 100755
--- a/.husky/pre-push
+++ b/.husky/pre-push
@@ -8,7 +8,7 @@ echo "๐ Running pre-push checks..."
# Run security audit
echo "๐ Running security audit..."
-npm audit --audit-level=moderate
+npm audit --omit=dev --audit-level=high
# Run build check one more time
# echo "๐๏ธ Final build check..."
diff --git a/COMMENT_SYSTEM_README.md b/COMMENT_SYSTEM_README.md
deleted file mode 100644
index e6b5de847..000000000
--- a/COMMENT_SYSTEM_README.md
+++ /dev/null
@@ -1,571 +0,0 @@
-# ๐ฃ๏ธ Comment System Implementation
-
-A comprehensive, production-ready comment system built with React/Next.js, featuring real-time updates, advanced moderation, and rich user interactions.
-
-## ๐ Table of Contents
-
-- [Features](#features)
-- [Architecture](#architecture)
-- [API Integration](#api-integration)
-- [Components](#components)
-- [Hooks](#hooks)
-- [Usage Examples](#usage-examples)
-- [Testing](#testing)
-- [Migration Guide](#migration-guide)
-
-## โจ Features
-
-### Core Features
-
-- โ
**Multi-entity Support**: Comments on Projects, Bounties, Hackathons, Grants, etc.
-- โ
**Threaded Comments**: Nested replies with configurable depth
-- โ
**8 Reaction Types**: LIKE, DISLIKE, LOVE, LAUGH, THUMBS_UP, THUMBS_DOWN, FIRE, ROCKET
-- โ
**Real-time Updates**: WebSocket integration for live comment updates
-- โ
**Content Validation**: Client-side validation with spam detection
-- โ
**Advanced Moderation**: Report system with resolution workflow
-
-### User Experience
-
-- โ
**Optimistic Updates**: Instant UI feedback
-- โ
**Loading States**: Proper loading indicators
-- โ
**Error Handling**: Comprehensive error states
-- โ
**Responsive Design**: Mobile-first responsive UI
-- โ
**Accessibility**: WCAG compliant components
-
-### Developer Experience
-
-- โ
**TypeScript**: Full type safety
-- โ
**Modular Hooks**: Reusable, composable hooks
-- โ
**Generic Components**: Entity-agnostic components
-- โ
**Comprehensive Testing**: Test page with all features
-
-## ๐๏ธ Architecture
-
-### Data Flow
-
-```
-User Action โ Hook โ API โ Backend โ WebSocket โ UI Update
-```
-
-### Component Hierarchy
-
-```
-GenericCommentThread
-โโโ CommentInput (with validation)
-โโโ CommentItem[]
-โ โโโ CommentReactions
-โ โโโ CommentReplyInput
-โ โโโ CommentReportForm
-โโโ LoadMoreButton
-```
-
-### Hook Architecture
-
-```
-useCommentSystem (main orchestrator)
-โโโ useComments (data fetching)
-โโโ useCreateComment (create operations)
-โโโ useUpdateComment (update operations)
-โโโ useDeleteComment (delete operations)
-โโโ useReportComment (reporting)
-โโโ useCommentReactions (reactions)
-```
-
-## ๐ API Integration
-
-### Base URL
-
-```
-/api/comments
-```
-
-### Endpoints Used
-
-- `GET /api/comments` - Fetch comments with filtering
-- `POST /api/comments` - Create new comment
-- `PUT /api/comments/:id` - Update comment
-- `DELETE /api/comments/:id` - Delete comment
-- `POST /api/comments/:id/reactions` - Add reaction
-- `DELETE /api/comments/:id/reactions/:type` - Remove reaction
-- `POST /api/comments/:id/report` - Report comment
-- `GET /api/comments/:id/reactions` - Get reactions
-
-### Query Parameters
-
-```typescript
-interface GetCommentsQuery {
- entityType: CommentEntityType;
- entityId: string;
- authorId?: string;
- parentId?: string;
- status?: CommentStatus;
- includeReactions?: boolean;
- includeReports?: boolean;
- page?: number;
- limit?: number;
- sortBy?: string;
- sortOrder?: 'asc' | 'desc';
-}
-```
-
-## ๐งฉ Components
-
-### GenericCommentThread
-
-Main comment thread component that works with any entity type.
-
-```tsx
-
{error}
-+ The hackathon you're looking for doesn't exist. +
++ {error || "We couldn't find the announcement you're looking for."} +
++ This announcement was published by the hackathon organizers. +
+- The hackathon you're looking for doesn't exist. -
-Organization not found
++ {profile.description} +
+ )} +- Share important updates, reminders, or announcements with the - community. -
++ {editingId + ? 'Update your announcement details.' + : 'Share important updates, reminders, or announcements with the community.'} +
++ Manage and grade shortlisted submissions +
+ {judge.name} +
++ Judge {index + 1} +
++ Select members from your organization to assign them as + judges. +
++ {member.name || member.username} +
++ {member.email} +
++ Winner rankings are live. This hackathon's results + have been finalized. +
++ Publish the current rankings to name the winners. +
+Join us for an exciting hackathon...
', - category: ['DeFi' as const], - venueType: 'virtual' as const, - country: '', - state: '', - city: '', - venueName: '', - venueAddress: '', - }, - timeline: { - startDate: new Date('2025-01-15'), - endDate: new Date('2025-01-20'), - registrationDeadline: new Date('2025-01-10'), - submissionDeadline: new Date('2025-01-18'), - timezone: 'UTC', - phases: [], - }, - participant: { - participantType: 'team_or_individual' as const, - teamMin: 2, - teamMax: 5, - about: '', - require_github: true, - require_demo_video: true, - require_other_links: false, - details_tab: true, - schedule_tab: true, - rules_tab: true, - reward_tab: true, - announcements_tab: true, - partners_tab: true, - join_a_team_tab: true, - projects_tab: true, - participants_tab: true, - }, - rewards: { - prizeTiers: [ - { - id: '1', - place: '1st', - prizeAmount: '10000', - currency: 'USDC', - description: '', - passMark: 80, - }, - { - id: '2', - place: '2nd', - prizeAmount: '5000', - currency: 'USDC', - description: '', - passMark: 70, - }, - { - id: '3', - place: '3rd', - prizeAmount: '3000', - currency: 'USDC', - description: '', - passMark: 60, - }, - ], - }, - collaboration: { - contactEmail: 'contact@example.com', - telegram: '', - discord: '', - socialLinks: [], - sponsorsPartners: [], - }, + // Mapping functions to convert Hackathon to tab data types + const getGeneralData = (h: Hackathon | null) => { + if (!h) return undefined; + return { + name: h.name, + tagline: h.tagline, + slug: h.slug, + banner: h.banner, + description: h.description, + categories: h.categories, + venueType: h.venueType.toLowerCase() as any, + country: h.country, + state: h.state, + city: h.city, + venueName: h.venueName, + venueAddress: h.venueAddress, + }; + }; + + const getTimelineData = (h: Hackathon | null) => { + if (!h) return undefined; + return { + startDate: h.startDate ? new Date(h.startDate) : undefined, + submissionDeadline: h.submissionDeadline + ? new Date(h.submissionDeadline) + : undefined, + timezone: h.timezone || 'UTC', + registrationDeadline: h.registrationDeadline + ? new Date(h.registrationDeadline) + : undefined, + judgingDeadline: h.judgingDeadline + ? new Date(h.judgingDeadline) + : undefined, + phases: h.phases?.map(p => ({ + ...p, + startDate: p.startDate ? new Date(p.startDate) : undefined, + endDate: p.endDate ? new Date(p.endDate) : undefined, + })) as any, + }; + }; + + const getParticipantData = (h: Hackathon | null) => { + if (!h) return undefined; + return { + participantType: h.participantType.toLowerCase() as any, + teamMin: h.teamMin, + teamMax: h.teamMax, + require_github: h.requireGithub, + require_demo_video: h.requireDemoVideo, + require_other_links: h.requireOtherLinks, + detailsTab: h.enabledTabs.includes('detailsTab'), + participantsTab: h.enabledTabs.includes('participantsTab'), + resourcesTab: h.enabledTabs.includes('resourcesTab'), + submissionTab: h.enabledTabs.includes('submissionTab'), + announcementsTab: h.enabledTabs.includes('announcementsTab'), + discussionTab: h.enabledTabs.includes('discussionTab'), + winnersTab: h.enabledTabs.includes('winnersTab'), + sponsorsTab: h.enabledTabs.includes('sponsorsTab'), + joinATeamTab: h.enabledTabs.includes('joinATeamTab'), + rulesTab: h.enabledTabs.includes('rulesTab'), + }; + }; + + const getAdvancedData = (h: Hackathon | null) => { + if (!h) return undefined; + const adv = h.metadata?.advancedSettings; + return { + isPublic: adv?.isPublic ?? true, + allowLateRegistration: adv?.allowLateRegistration ?? false, + requireApproval: adv?.requireApproval ?? false, + maxParticipants: adv?.maxParticipants, + customDomain: adv?.customDomain || '', + enableDiscord: adv?.enableDiscord ?? !!h.discord, + discordInviteLink: adv?.discordInviteLink || h.discord || '', + enableTelegram: adv?.enableTelegram ?? !!h.telegram, + telegramInviteLink: adv?.telegramInviteLink || h.telegram || '', + }; }; const handleSave = async (section: string, data: unknown) => { setIsSaving(true); try { - await api.patch( - `/organizations/${organizationId}/hackathons/${hackathonId}/settings/${section.toLowerCase()}`, - data - ); + if (section === 'General') { + await api.patch( + `/organizations/${organizationId}/hackathons/${hackathonId}/content`, + { information: data } + ); + } else if (section === 'Collaboration') { + await api.patch( + `/organizations/${organizationId}/hackathons/${hackathonId}/content`, + { collaboration: data } + ); + } else if (section === 'Participants') { + await api.patch( + `/organizations/${organizationId}/hackathons/${hackathonId}/schedule`, + { participation: data } + ); + } else if (section === 'Rewards') { + await api.patch( + `/organizations/${organizationId}/hackathons/${hackathonId}/financial`, + { rewards: data } + ); + } else { + await api.patch( + `/organizations/${organizationId}/hackathons/${hackathonId}/settings/${section.toLowerCase()}`, + data + ); + } toast.success(`${section} settings saved successfully!`); - } catch { - toast.error(`Failed to save ${section} settings`); + await fetchHackathon(); // Call fetchHackathon after successful save + } catch (error: any) { + const message = + error.response?.data?.message || `Failed to save ${section} settings`; + const errorMessage = Array.isArray(message) ? message[0] : message; + toast.error(errorMessage); + throw error; // Re-throw to let callers know it failed } finally { setIsSaving(false); } }; + if (isLoading) return- Get started by hosting your first hackathon -
- -+ Get started by hosting your first hackathon +
+ -+ Start a new draft to host your first hackathon +
+ ++ {description} +
++ Your personal growth dashboard across the platform. +
+Your Project contact information will be used for Project - verification and for Boundless staff to contact you. The contact - information can only be accessed by Boundless staff. + verification and for Boundless team to contact you. The contact + information can only be accessed by Boundless team.
{description}
++ ${(activity.amount ?? 0).toLocaleString()} +
+ {activity.currency && ( +{activity.currency}
+ )} ++ No earnings data found. +
++ Manage and track your rewards across the platform. +
++ No recent activity found. +
+ ) : ( + data.activities.map(activity => ( ++ Track the full lifecycle of every hackathon submission you've + made. +
+
+
Hackathon Start
++ {formatDate(submission.hackathon.startDate)} +
+Submission Deadline
++ {formatDate(submission.hackathon.submissionDeadline)} +
++ {submission.description} +
++ {submission.introduction} +
++ {submission.disqualificationReason} +
++ {notification.message} +
++ {notification.message} +
+ + {notification.data.amount && ( +{emptyMessage}
+{emptySubMessage}
++ Error loading notifications +
+{error.message}
++ {loading ? ( + + ) : ( + <> + {unreadCount > 0 + ? `${unreadCount} unread of ${total} total` + : `${total} notifications`} + > + )} +
++ No notifications yet +
++ When you receive notifications about your projects, hackathons, or + account activity, they will appear here. +
++ Track your active hackathons, projects, and pending submissions. +
++ {description} +
++ Weโre building foundational systems to power a more transparent, + efficient grant and bounty ecosystem. +
+| Metric | +Value | +Trend | +
|---|---|---|
| {t.label} | +{t.value.toLocaleString()} | ++ {t.trend.direction === 'flat' + ? 'No change' + : `${t.trend.direction === 'up' ? 'Up' : 'Down'} ${t.trend.percentage}%`} + | +
{label}
++ {payload[0].value}{' '} + activities +
+| Date | +Activity Count | +
|---|---|
| {d.label} | +{d.count} | +
+ {error} +
+ )} ++ You have not completed identity verification yet. +
+ )} + + {(status !== 'Approved' || !status) && ( + <> ++ Using localhost? If verification is blocked by the browser, use + a tunnel (e.g. ngrok) and set your backend FRONTEND_URL or + DIDIT_CALLBACK_URL to the tunnel URL. See DIDIT_INTEGRATION.md โ + Troubleshooting. +
+ )} + > + )} ++ {announcement.content.replace(/<[^>]*>/g, '')} +
+ +- {participant.projects || 0} + {profileData?.stats?.projectsCreated ?? participant.projects ?? 0}
Projects
- {participant.followers || 0} + {followStats?.followers ?? participant.followers ?? 0}
Followers
- {participant.following || 0} + {followStats?.following ?? participant.following ?? 0}
Following