diff --git a/app/(landing)/organizations/[id]/hackathons/[hackathonId]/settings/page.tsx b/app/(landing)/organizations/[id]/hackathons/[hackathonId]/settings/page.tsx index ca7ad3513..c31993f62 100644 --- a/app/(landing)/organizations/[id]/hackathons/[hackathonId]/settings/page.tsx +++ b/app/(landing)/organizations/[id]/hackathons/[hackathonId]/settings/page.tsx @@ -37,7 +37,7 @@ export default function SettingsPage() { name: 'Web3 Innovation Hackathon', banner: 'https://example.com/banner.jpg', description: '
Join us for an exciting hackathon...
', - category: 'DeFi', + category: ['DeFi' as const], venueType: 'virtual' as const, country: '', state: '', diff --git a/components/organization/hackathons/new/tabs/InfoTab.tsx b/components/organization/hackathons/new/tabs/InfoTab.tsx index 6c2260285..6292bde18 100644 --- a/components/organization/hackathons/new/tabs/InfoTab.tsx +++ b/components/organization/hackathons/new/tabs/InfoTab.tsx @@ -53,8 +53,10 @@ export default function InfoTab({ banner: initialData?.banner || '', description: initialData?.description || '', category: Array.isArray(initialData?.category) - ? (initialData.category[0] as string) || '' - : (initialData?.category as string) || '', + ? initialData.category + : initialData?.category + ? [initialData.category] + : [], venueType: initialData?.venueType || 'physical', country: initialData?.country || '', state: initialData?.state || '', diff --git a/components/organization/hackathons/new/tabs/schemas/infoSchema.ts b/components/organization/hackathons/new/tabs/schemas/infoSchema.ts index 64d4de426..75162d924 100644 --- a/components/organization/hackathons/new/tabs/schemas/infoSchema.ts +++ b/components/organization/hackathons/new/tabs/schemas/infoSchema.ts @@ -20,26 +20,24 @@ export const infoSchema = z .max(5000, 'Description must be less than 5000 characters'), category: z - .string() - .min(1, 'Category is required') - .refine( - val => - [ - 'DeFi', - 'NFTs', - 'DAOs', - 'Layer 2', - 'Cross-chain', - 'Web3 Gaming', - 'Social Tokens', - 'Infrastructure', - 'Privacy', - 'Sustainability', - 'Real World Assets', - 'Other', - ].includes(val), - 'Please select a valid category' - ), + .array( + z.enum([ + 'DeFi', + 'NFTs', + 'DAOs', + 'Layer 2', + 'Cross-chain', + 'Web3 Gaming', + 'Social Tokens', + 'Infrastructure', + 'Privacy', + 'Sustainability', + 'Real World Assets', + 'Other', + ]) + ) + .min(1, 'At least one category is required') + .refine(val => val.length > 0, 'Please select at least one category'), venueType: z.enum(['virtual', 'physical'], { message: 'Venue type is required', diff --git a/components/organization/hackathons/settings/GeneralSettingsTab.tsx b/components/organization/hackathons/settings/GeneralSettingsTab.tsx index 8553eb38c..f98481b00 100644 --- a/components/organization/hackathons/settings/GeneralSettingsTab.tsx +++ b/components/organization/hackathons/settings/GeneralSettingsTab.tsx @@ -78,7 +78,11 @@ export default function GeneralSettingsTab({ name: initialData?.name || '', banner: initialData?.banner || '', description: initialData?.description || '', - category: initialData?.category || '', + category: Array.isArray(initialData?.category) + ? initialData.category + : initialData?.category + ? [initialData.category] + : [], venueType: initialData?.venueType || 'virtual', country: initialData?.country || '', state: initialData?.state || '', diff --git a/lib/api/api.ts b/lib/api/api.ts index 30a99fc7d..7a7c69cee 100644 --- a/lib/api/api.ts +++ b/lib/api/api.ts @@ -2,8 +2,8 @@ import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'; import Cookies from 'js-cookie'; import { useAuthStore } from '@/lib/stores/auth-store'; -// const API_BASE_URL = 'https://staging-api.boundlessfi.xyz/api'; -const API_BASE_URL = 'http://localhost:8000/api'; +const API_BASE_URL = 'https://staging-api.boundlessfi.xyz/api'; +// const API_BASE_URL = 'http://localhost:8000/api'; // const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL; if (!API_BASE_URL) { throw new Error('NEXT_PUBLIC_API_URL environment variable is not defined'); diff --git a/lib/api/hackathons.ts b/lib/api/hackathons.ts index 504f93f31..81439687a 100644 --- a/lib/api/hackathons.ts +++ b/lib/api/hackathons.ts @@ -42,7 +42,8 @@ export interface HackathonInformation { title: string; banner: string; description: string; - category: HackathonCategory; + category?: HackathonCategory; // Legacy format (single category) + categories?: HackathonCategory[]; // New format (array of categories) venue: HackathonVenue; } @@ -698,7 +699,8 @@ interface FlatHackathonData { // Flat fields that map to nested structure banner?: string; description?: string; - category?: string | HackathonCategory; + category?: string | HackathonCategory; // Legacy format + categories?: HackathonCategory[]; // New format venue?: HackathonVenue; startDate?: string; submissionDeadline?: string; @@ -769,6 +771,12 @@ const transformHackathonResponse = ( title: flat.title || '', banner: flat.banner || '', description: flat.description || '', + // Support both new format (categories) and legacy format (category) + categories: Array.isArray(flat.categories) + ? (flat.categories as HackathonCategory[]) + : flat.category + ? [flat.category as HackathonCategory] + : [HackathonCategory.OTHER], category: (flat.category as HackathonCategory) || HackathonCategory.OTHER, venue: flat.venue || { type: VenueType.VIRTUAL, diff --git a/lib/config.ts b/lib/config.ts index d25ff6183..ebee5fc50 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -1,5 +1,7 @@ export const config = { - apiUrl: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000/api', + apiUrl: + process.env.NEXT_PUBLIC_API_URL || + 'https://staging-api.boundlessfi.xyz/api', }; export const socialLinks = { diff --git a/lib/utils/hackathon-form-transforms.ts b/lib/utils/hackathon-form-transforms.ts index 80112fe27..c4e9096bc 100644 --- a/lib/utils/hackathon-form-transforms.ts +++ b/lib/utils/hackathon-form-transforms.ts @@ -28,15 +28,30 @@ export const transformToApiFormat = (stepData: { const judging = stepData.judging; const collaboration = stepData.collaboration; + // Convert form category array to API format + const categoriesArray: HackathonCategory[] = Array.isArray(info?.category) + ? (info.category as HackathonCategory[]).filter(cat => + Object.values(HackathonCategory).includes(cat) + ) + : info?.category && typeof info.category === 'string' + ? [info.category as HackathonCategory] + : []; + return { information: { title: info?.name || '', banner: info?.banner || '', description: info?.description || '', + // Send categories array (new format, recommended) + categories: + categoriesArray.length > 0 + ? categoriesArray + : [HackathonCategory.OTHER], + // Also include legacy category for backward compatibility (first category) category: - Array.isArray(info?.category) && info.category.length > 0 - ? (info.category[0] as HackathonCategory) - : (info?.category as HackathonCategory) || HackathonCategory.OTHER, + categoriesArray.length > 0 + ? categoriesArray[0] + : HackathonCategory.OTHER, venue: { type: (info?.venueType as VenueType) || VenueType.VIRTUAL, country: info?.country, @@ -128,16 +143,19 @@ export const transformFromApiFormat = (draft: HackathonDraft) => { const judging = draft.judging; const collaboration = draft.collaboration; + // Handle both new format (categories array) and legacy format (category string) + const categoriesArray: string[] = info?.categories + ? info.categories + : info?.category + ? [info.category] + : []; + return { information: { name: info?.title || '', banner: info?.banner || '', description: info?.description || '', - category: Array.isArray(info?.category) - ? info.category - : info?.category - ? [info.category] - : [], + category: categoriesArray, venueType: info?.venue?.type || 'physical', country: info?.venue?.country || '', state: info?.venue?.state || '',