Skip to content

Commit 07ca664

Browse files
authored
Feat/hackthon features (#343)
* feat: implemented hackathon features * fix: update * fix: added the staging api * fix: update API base URL to use environment variable * fix: correct API_BASE_URL assignment and comment out unused variables * feat: enhance infoSchema to support multiple categories and validation
1 parent d9ee18b commit 07ca664

6 files changed

Lines changed: 64 additions & 34 deletions

File tree

app/(landing)/organizations/[id]/hackathons/[hackathonId]/settings/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export default function SettingsPage() {
3737
name: 'Web3 Innovation Hackathon',
3838
banner: 'https://example.com/banner.jpg',
3939
description: '<p>Join us for an exciting hackathon...</p>',
40-
category: 'DeFi',
40+
category: ['DeFi' as const],
4141
venueType: 'virtual' as const,
4242
country: '',
4343
state: '',

components/organization/hackathons/new/tabs/InfoTab.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,10 @@ export default function InfoTab({
5353
banner: initialData?.banner || '',
5454
description: initialData?.description || '',
5555
category: Array.isArray(initialData?.category)
56-
? (initialData.category[0] as string) || ''
57-
: (initialData?.category as string) || '',
56+
? initialData.category
57+
: initialData?.category
58+
? [initialData.category]
59+
: [],
5860
venueType: initialData?.venueType || 'physical',
5961
country: initialData?.country || '',
6062
state: initialData?.state || '',

components/organization/hackathons/new/tabs/schemas/infoSchema.ts

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,26 +20,24 @@ export const infoSchema = z
2020
.max(5000, 'Description must be less than 5000 characters'),
2121

2222
category: z
23-
.string()
24-
.min(1, 'Category is required')
25-
.refine(
26-
val =>
27-
[
28-
'DeFi',
29-
'NFTs',
30-
'DAOs',
31-
'Layer 2',
32-
'Cross-chain',
33-
'Web3 Gaming',
34-
'Social Tokens',
35-
'Infrastructure',
36-
'Privacy',
37-
'Sustainability',
38-
'Real World Assets',
39-
'Other',
40-
].includes(val),
41-
'Please select a valid category'
42-
),
23+
.array(
24+
z.enum([
25+
'DeFi',
26+
'NFTs',
27+
'DAOs',
28+
'Layer 2',
29+
'Cross-chain',
30+
'Web3 Gaming',
31+
'Social Tokens',
32+
'Infrastructure',
33+
'Privacy',
34+
'Sustainability',
35+
'Real World Assets',
36+
'Other',
37+
])
38+
)
39+
.min(1, 'At least one category is required')
40+
.refine(val => val.length > 0, 'Please select at least one category'),
4341

4442
venueType: z.enum(['virtual', 'physical'], {
4543
message: 'Venue type is required',

components/organization/hackathons/settings/GeneralSettingsTab.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,11 @@ export default function GeneralSettingsTab({
7878
name: initialData?.name || '',
7979
banner: initialData?.banner || '',
8080
description: initialData?.description || '',
81-
category: initialData?.category || '',
81+
category: Array.isArray(initialData?.category)
82+
? initialData.category
83+
: initialData?.category
84+
? [initialData.category]
85+
: [],
8286
venueType: initialData?.venueType || 'virtual',
8387
country: initialData?.country || '',
8488
state: initialData?.state || '',

lib/api/hackathons.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ export interface HackathonInformation {
4242
title: string;
4343
banner: string;
4444
description: string;
45-
category: HackathonCategory;
45+
category?: HackathonCategory; // Legacy format (single category)
46+
categories?: HackathonCategory[]; // New format (array of categories)
4647
venue: HackathonVenue;
4748
}
4849

@@ -698,7 +699,8 @@ interface FlatHackathonData {
698699
// Flat fields that map to nested structure
699700
banner?: string;
700701
description?: string;
701-
category?: string | HackathonCategory;
702+
category?: string | HackathonCategory; // Legacy format
703+
categories?: HackathonCategory[]; // New format
702704
venue?: HackathonVenue;
703705
startDate?: string;
704706
submissionDeadline?: string;
@@ -769,6 +771,12 @@ const transformHackathonResponse = (
769771
title: flat.title || '',
770772
banner: flat.banner || '',
771773
description: flat.description || '',
774+
// Support both new format (categories) and legacy format (category)
775+
categories: Array.isArray(flat.categories)
776+
? (flat.categories as HackathonCategory[])
777+
: flat.category
778+
? [flat.category as HackathonCategory]
779+
: [HackathonCategory.OTHER],
772780
category: (flat.category as HackathonCategory) || HackathonCategory.OTHER,
773781
venue: flat.venue || {
774782
type: VenueType.VIRTUAL,

lib/utils/hackathon-form-transforms.ts

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,30 @@ export const transformToApiFormat = (stepData: {
2828
const judging = stepData.judging;
2929
const collaboration = stepData.collaboration;
3030

31+
// Convert form category array to API format
32+
const categoriesArray: HackathonCategory[] = Array.isArray(info?.category)
33+
? (info.category as HackathonCategory[]).filter(cat =>
34+
Object.values(HackathonCategory).includes(cat)
35+
)
36+
: info?.category && typeof info.category === 'string'
37+
? [info.category as HackathonCategory]
38+
: [];
39+
3140
return {
3241
information: {
3342
title: info?.name || '',
3443
banner: info?.banner || '',
3544
description: info?.description || '',
45+
// Send categories array (new format, recommended)
46+
categories:
47+
categoriesArray.length > 0
48+
? categoriesArray
49+
: [HackathonCategory.OTHER],
50+
// Also include legacy category for backward compatibility (first category)
3651
category:
37-
Array.isArray(info?.category) && info.category.length > 0
38-
? (info.category[0] as HackathonCategory)
39-
: (info?.category as HackathonCategory) || HackathonCategory.OTHER,
52+
categoriesArray.length > 0
53+
? categoriesArray[0]
54+
: HackathonCategory.OTHER,
4055
venue: {
4156
type: (info?.venueType as VenueType) || VenueType.VIRTUAL,
4257
country: info?.country,
@@ -128,16 +143,19 @@ export const transformFromApiFormat = (draft: HackathonDraft) => {
128143
const judging = draft.judging;
129144
const collaboration = draft.collaboration;
130145

146+
// Handle both new format (categories array) and legacy format (category string)
147+
const categoriesArray: string[] = info?.categories
148+
? info.categories
149+
: info?.category
150+
? [info.category]
151+
: [];
152+
131153
return {
132154
information: {
133155
name: info?.title || '',
134156
banner: info?.banner || '',
135157
description: info?.description || '',
136-
category: Array.isArray(info?.category)
137-
? info.category
138-
: info?.category
139-
? [info.category]
140-
: [],
158+
category: categoriesArray,
141159
venueType: info?.venue?.type || 'physical',
142160
country: info?.venue?.country || '',
143161
state: info?.venue?.state || '',

0 commit comments

Comments
 (0)