Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions app/(landing)/organizations/[id]/hackathons/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const calculateDraftCompletion = (draft: HackathonDraft): number => {
draft.information?.title,
draft.information?.banner,
draft.information?.description,
draft.information?.category,
draft.information?.categories,
draft.timeline?.startDate,
draft.timeline?.submissionDeadline,
draft.timeline?.judgingDate,
Expand Down Expand Up @@ -123,8 +123,9 @@ export default function HackathonsPage() {

if (categoryFilter !== 'all') {
filtered = filtered.filter(item => {
const category = item.data.information?.category?.toLowerCase() || '';
return category === categoryFilter.toLowerCase();
const category =
item.data.information?.categories?.join(',')?.toLowerCase() || '';
return category.includes(categoryFilter.toLowerCase());
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ export default function NewHackathonTab({
const { isPublishing, publish } = useHackathonPublish({
organizationId: derivedOrgId || '',
stepData,
draftId,
publishHackathonAction,
});

Expand Down
10 changes: 4 additions & 6 deletions components/organization/hackathons/new/tabs/InfoTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,9 @@ export default function InfoTab({
name: initialData?.name || '',
banner: initialData?.banner || '',
description: initialData?.description || '',
category: Array.isArray(initialData?.category)
? initialData.category
: initialData?.category
? [initialData.category]
: [],
categories: Array.isArray(initialData?.categories)
? initialData.categories
: [],
venueType: initialData?.venueType || 'physical',
country: initialData?.country || '',
state: initialData?.state || '',
Expand Down Expand Up @@ -145,7 +143,7 @@ export default function InfoTab({
)}
/>

<CategorySelection control={form.control} name='category' />
<CategorySelection control={form.control} name='categories' />

<VenueSection
control={form.control}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,7 @@ export default function InformationSection({
<InfoItem
label='Categories'
value={
Array.isArray(data.category)
? data.category.join(', ')
: data.category || ''
Array.isArray(data.categories) ? data.categories.join(', ') : ''
}
/>
<Separator className='bg-gray-900' />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const infoSchema = z
.min(10, 'Description must be at least 10 characters')
.max(5000, 'Description must be less than 5000 characters'),

category: z
categories: z
.array(
z.enum([
'DeFi',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,9 @@ export default function GeneralSettingsTab({
name: initialData?.name || '',
banner: initialData?.banner || '',
description: initialData?.description || '',
category: Array.isArray(initialData?.category)
? initialData.category
: initialData?.category
? [initialData.category]
: [],
categories: Array.isArray(initialData?.categories)
? initialData.categories
: [],
venueType: initialData?.venueType || 'virtual',
country: initialData?.country || '',
state: initialData?.state || '',
Expand Down Expand Up @@ -205,7 +203,7 @@ export default function GeneralSettingsTab({
)}
/>

<CategorySelection control={form.control} name='category' />
<CategorySelection control={form.control} name='categories' />

<VenueSection
control={form.control}
Expand Down
12 changes: 5 additions & 7 deletions hooks/hackathon/use-hackathon-transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,12 @@ export function useHackathonTransform() {
extendedHackathon._organizationName ||
'organization';

// Extract categories - support both single category and multiple categories
// Extract categories
const categories: string[] = [];
if (hackathon.information?.category) {
// If category is an array, use it; otherwise convert single category to array
if (Array.isArray(hackathon.information.category)) {
categories.push(...hackathon.information.category);
} else {
categories.push(hackathon.information.category);
if (hackathon.information?.categories) {
// If categories is an array, use it
if (Array.isArray(hackathon.information.categories)) {
categories.push(...hackathon.information.categories);
}
}
// Add additional categories if they exist in the hackathon object
Expand Down
5 changes: 5 additions & 0 deletions hooks/use-hackathon-publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ interface StepData {
interface UseHackathonPublishProps {
organizationId: string;
stepData: StepData;
draftId?: string | null;
publishHackathonAction: (
data: PublishHackathonRequest
) => Promise<{ _id: string }>;
Expand All @@ -48,6 +49,7 @@ interface UseHackathonPublishProps {
export const useHackathonPublish = ({
organizationId,
stepData,
draftId,
publishHackathonAction,
}: UseHackathonPublishProps) => {
const router = useRouter();
Expand Down Expand Up @@ -196,6 +198,9 @@ export const useHackathonPublish = ({

toast.info('Publishing hackathon...');
const apiData = transformToApiFormat(stepData) as PublishHackathonRequest;
if (draftId) {
apiData.draftId = draftId;
}
apiData.contractId = contractId;
apiData.escrowAddress = escrowAddress;
apiData.transactionHash = transactionHash;
Expand Down
37 changes: 21 additions & 16 deletions lib/api/hackathons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,9 @@ export interface HackathonInformation {
title: string;
banner: string;
description: string;
category?: HackathonCategory; // Legacy format (single category)
categories?: HackathonCategory[]; // New format (array of categories)
venue?: HackathonVenue;
categories: HackathonCategory[]; // New format (array of categories)
slug: string;
venue?: HackathonVenue;
}

// Timeline Tab Types
Expand Down Expand Up @@ -177,6 +176,7 @@ export type CreateDraftRequest = Partial<HackathonData>;
export type UpdateDraftRequest = Partial<HackathonData>;

export interface PublishHackathonRequest extends HackathonData {
draftId?: string;
contractId?: string;
escrowAddress?: string;
transactionHash?: string;
Expand Down Expand Up @@ -709,7 +709,6 @@ interface FlatHackathonData {
// Flat fields that map to nested structure
banner?: string;
description?: string;
category?: string | HackathonCategory; // Legacy format
categories?: HackathonCategory[]; // New format
venue?: HackathonVenue;
startDate?: string;
Expand Down Expand Up @@ -786,10 +785,7 @@ const transformHackathonResponse = (
// 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,
: [HackathonCategory.OTHER],
venue: flat.venue,
},
timeline: {
Expand Down Expand Up @@ -1382,13 +1378,22 @@ export const transformPublicHackathonToHackathon = (
internalStatus = 'completed';
}

// Get first category or default to OTHER
const category = publicHackathon.categories?.[0] || HackathonCategory.OTHER;
const categoryEnum = Object.values(HackathonCategory).includes(
category as HackathonCategory
)
? (category as HackathonCategory)
: HackathonCategory.OTHER;
// Map all categories from API response
const categoriesArray: HackathonCategory[] = publicHackathon.categories
? publicHackathon.categories
.map(cat => {
// Check if the category string matches any HackathonCategory enum value
const matchedCategory = Object.values(HackathonCategory).find(
enumCat => enumCat === cat
);
return matchedCategory || null;
})
.filter((cat): cat is HackathonCategory => cat !== null)
: [];

// Ensure at least one category
const categories: HackathonCategory[] =
categoriesArray.length > 0 ? categoriesArray : [HackathonCategory.OTHER];

// Extract resources (telegram, discord, etc.) from resources array
const telegram = publicHackathon.resources?.find(
Expand All @@ -1412,7 +1417,7 @@ export const transformPublicHackathonToHackathon = (
title: publicHackathon.title,
banner: publicHackathon.imageUrl,
description: publicHackathon.description,
category: categoryEnum,
categories: categories,
slug: publicHackathon.slug,
venue,
},
Expand Down
25 changes: 7 additions & 18 deletions lib/utils/hackathon-form-transforms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,12 @@ 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 =>
// Convert form categories array to API format
const categoriesArray: HackathonCategory[] = Array.isArray(info?.categories)
? (info.categories as HackathonCategory[]).filter(cat =>
Object.values(HackathonCategory).includes(cat)
)
: info?.category && typeof info.category === 'string'
? [info.category as HackathonCategory]
: [];
: [];

return {
information: {
Expand All @@ -48,11 +46,6 @@ export const transformToApiFormat = (stepData: {
categoriesArray.length > 0
? categoriesArray
: [HackathonCategory.OTHER],
// Also include legacy category for backward compatibility (first category)
category:
categoriesArray.length > 0
? categoriesArray[0]
: HackathonCategory.OTHER,
venue: {
type: (info?.venueType as VenueType) || VenueType.VIRTUAL,
country: info?.country,
Expand Down Expand Up @@ -144,19 +137,15 @@ 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]
: [];
// Handle categories array
const categoriesArray: string[] = info?.categories ? info.categories : [];

return {
information: {
name: info?.title || '',
banner: info?.banner || '',
description: info?.description || '',
category: categoriesArray,
categories: categoriesArray,
venueType: info?.venue?.type || 'physical',
country: info?.venue?.country || '',
state: info?.venue?.state || '',
Expand Down
Loading