diff --git a/app/(landing)/hackathons/[slug]/page.tsx b/app/(landing)/hackathons/[slug]/page.tsx
index 8f5946e55..c69c106b7 100644
--- a/app/(landing)/hackathons/[slug]/page.tsx
+++ b/app/(landing)/hackathons/[slug]/page.tsx
@@ -15,6 +15,7 @@ import SubmissionTab from '@/components/hackathons/submissions/submissionTab';
import { HackathonDiscussions } from '@/components/hackathons/discussion/comment';
import { TeamFormationTab } from '@/components/hackathons/team-formation/TeamFormationTab';
import LoadingScreen from '@/components/landing-page/project/CreateProjectModal/LoadingScreen';
+import { useTimelineEvents } from '@/hooks/hackathon/use-timeline-events';
export default function HackathonPage() {
const router = useRouter();
@@ -23,14 +24,16 @@ export default function HackathonPage() {
const {
currentHackathon,
- // content,
- timelineEvents,
participants,
submissions,
- prizes,
loading,
setCurrentHackathon,
} = useHackathonData();
+ console.log(currentHackathon);
+ const timeline_Events = useTimelineEvents(currentHackathon, {
+ includeEndDate: false,
+ dateFormat: { month: 'short', day: 'numeric', year: 'numeric' },
+ });
const hackathonTabs = useMemo(() => {
const tabs = [
@@ -193,8 +196,9 @@ export default function HackathonPage() {
{activeTab === 'overview' && (
)}
diff --git a/app/(landing)/hackathons/preview/[orgId]/[draftId]/page.tsx b/app/(landing)/hackathons/preview/[orgId]/[draftId]/page.tsx
index 4432cf4ba..9e14c6a50 100644
--- a/app/(landing)/hackathons/preview/[orgId]/[draftId]/page.tsx
+++ b/app/(landing)/hackathons/preview/[orgId]/[draftId]/page.tsx
@@ -5,6 +5,7 @@ import { useRouter, useSearchParams } from 'next/navigation';
import { ArrowLeft } from 'lucide-react';
import {
previewDraft,
+ PrizeTier,
transformPublicHackathonToHackathon,
} from '@/lib/api/hackathons';
import { HackathonBanner } from '@/components/hackathons/hackathonBanner';
@@ -28,30 +29,29 @@ const mockTimelineEvents = [
{ event: 'Winners Announced', date: new Date().toISOString() },
];
-const mockPrizes = [
+const mockPrizes: PrizeTier[] = [
{
- title: 'First Place',
- rank: '1st',
- prize: '$5,000',
- icon: '🥇',
- details: ['Cash prize', 'Certificate', 'Featured on homepage'],
+ position: '1st',
+ amount: 5000,
+ currency: 'USD',
+ description: 'Cash prize, Certificate, Featured on homepage',
},
{
- title: 'Second Place',
- rank: '2nd',
- prize: '$3,000',
- icon: '🥈',
- details: ['Cash prize', 'Certificate'],
+ position: '2nd',
+ amount: 3000,
+ currency: 'USD',
+ description: 'Cash prize, Certificate',
},
{
- title: 'Third Place',
- rank: '3rd',
- prize: '$2,000',
- icon: '🥉',
- details: ['Cash prize', 'Certificate'],
+ position: '3rd',
+ amount: 2000,
+ currency: 'USD',
+ description: 'Cash prize, Certificate',
},
];
+const totalPrizePool = mockPrizes.reduce((sum, prize) => sum + prize.amount, 0);
+
interface PreviewPageProps {
params: Promise<{
orgId: string;
@@ -400,6 +400,7 @@ export default function DraftPreviewPage({ params }: PreviewPageProps) {
{activeTab === 'overview' && (
{timelineEvents && }
- {prizes && }
+ {prizes && (
+
+ )}
);
}
diff --git a/components/hackathons/overview/hackathonPrizes.tsx b/components/hackathons/overview/hackathonPrizes.tsx
index cf6d50439..825a10ba1 100644
--- a/components/hackathons/overview/hackathonPrizes.tsx
+++ b/components/hackathons/overview/hackathonPrizes.tsx
@@ -1,66 +1,110 @@
'use client';
+import { PrizeTier } from '@/lib/api/hackathons';
+
interface HackathonPrizesProps {
title?: string;
- totalPrizes?: string;
+ totalPrizePool?: string;
otherPrizes?: string;
- prizes: Array<{
- title: string;
- rank: string;
- prize: string;
- details: string[];
- icon?: string;
- }>;
+ prizes: PrizeTier[];
}
export function HackathonPrizes({
title = 'PRIZES',
- totalPrizes = '$1,000+ in prizes',
+ totalPrizePool,
otherPrizes,
prizes,
}: HackathonPrizesProps) {
+ const firstThreePrizes = prizes.slice(0, 3);
+ const remainingPrizes = prizes.slice(3);
+
return (
{title}
- {totalPrizes}
+ {totalPrizePool} USDC
{otherPrizes && (
+ {otherPrizes}
)}
-
- {prizes.map((prize, index) => (
-
-
-
{prize.icon || '⭐'}
-
-
{prize.title}
-
{prize.rank}
+ {/* First 3 prizes in cards */}
+ {firstThreePrizes.length > 0 && (
+
+ {firstThreePrizes.map((prize, index) => (
+
+
+
+ {index === 0
+ ? '🥇'
+ : index === 1
+ ? '🥈'
+ : index === 2
+ ? '🥉'
+ : '⭐'}
+
+
+
+ {prize.position}
+
+
{prize.position}
+
-
-
-
- {prize.prize}
+
+
+ {prize.amount} {prize.currency || 'USDC'}
+
-
- {prize.details.map((detail, i) => (
- -
- ✓
- {detail}
-
- ))}
-
+ ))}
+
+ )}
+
+ {remainingPrizes.length > 0 && (
+
+
+
+
+
+ |
+ POSITION
+ |
+
+ PRIZE AMOUNT
+ |
+
+ CURRENCY
+ |
+
+
+
+ {remainingPrizes.map((prize, index) => (
+
+ |
+ {prize.position}
+ |
+
+ {prize.amount}
+ |
+
+ {prize.currency || 'USDC'}
+ |
+
+ ))}
+
+
- ))}
-
+
+ )}
);
}
diff --git a/components/hackathons/overview/hackathonTimeline.tsx b/components/hackathons/overview/hackathonTimeline.tsx
index 2a9ed046f..d785b2ec4 100644
--- a/components/hackathons/overview/hackathonTimeline.tsx
+++ b/components/hackathons/overview/hackathonTimeline.tsx
@@ -1,63 +1,87 @@
'use client';
-interface TimelineEvent {
+import { Calendar, CheckCircle2, Clock, Flag, Trophy } from 'lucide-react';
+
+interface Timeline {
event: string;
date: string;
}
-
interface HackathonTimelineProps {
- events?: TimelineEvent[];
+ events: Timeline[];
}
-export function HackathonTimeline({
- events = [
- { event: 'Hackathon Launch', date: 'September 9, 2025' },
- { event: 'First Workshop: Getting Started', date: 'September 10' },
- {
- event: 'Weekly Web Design & Deployment Sessions',
- date: 'Sept 11 – Sep 28',
- },
- { event: 'Submission Deadline', date: 'October 28, 2025 @ 11:59 PM UTC' },
- { event: 'Judging Period', date: 'November 9' },
- { event: 'Winners Announced', date: 'December 15, 2025' },
- ],
-}: HackathonTimelineProps) {
+export function HackathonTimeline({ events }: HackathonTimelineProps) {
+ if (!events.length) return null;
+
+ function getEventIcon(event: Timeline['event']) {
+ const normalized = event.toLowerCase();
+
+ if (normalized.includes('start')) return Flag;
+ if (normalized.includes('deadline')) return Clock;
+ if (normalized.includes('judging')) return CheckCircle2;
+ if (normalized.includes('winner')) return Trophy;
+
+ return Calendar;
+ }
+
return (
-
-
+
+
TIMELINE & KEY DATES
-
-
-
-
-
- |
- EVENT
- |
-
- DATE
- |
-
-
-
- {events.map((event, index) => (
-
- |
- {event.event}
- |
-
- {event.date}
- |
-
- ))}
-
-
+
+ {/* Vertical line */}
+
+
+ {/* Timeline events */}
+
+ {events.map((event, index) => {
+ const Icon = getEventIcon(event.event);
+ return (
+
+ {/* Dot marker */}
+
+
+ {/* Content card */}
+
+
+
+
+ {event.event}
+
+
+
+ {event.date}
+
+
+
+ {/* Event number badge */}
+
+
+
+
+ );
+ })}
+
+
+
+ {/* Bottom decoration */}
+ {/*
+
+
+ All times in UTC unless specified
+
+
*/}
);
diff --git a/hooks/hackathon/use-timeline-events.ts b/hooks/hackathon/use-timeline-events.ts
new file mode 100644
index 000000000..c107bd667
--- /dev/null
+++ b/hooks/hackathon/use-timeline-events.ts
@@ -0,0 +1,102 @@
+'use client';
+import { Hackathon } from '@/types/hackathon';
+import { useMemo } from 'react';
+
+export interface TimelineEvent {
+ event: string;
+ date: string;
+ rawDate: Date;
+ type: 'start' | 'deadline' | 'judging' | 'winner' | 'end';
+}
+
+interface UseTimelineEventsOptions {
+ includeEndDate?: boolean;
+ dateFormat?: Intl.DateTimeFormatOptions;
+ deadlineFormat?: Intl.DateTimeFormatOptions;
+}
+
+export const useTimelineEvents = (
+ currentHackathon: Hackathon | null,
+ options: UseTimelineEventsOptions = {}
+) => {
+ const {
+ includeEndDate = true,
+ dateFormat = { year: 'numeric', month: 'long', day: 'numeric' },
+ deadlineFormat = {
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric',
+ hour: '2-digit',
+ minute: '2-digit',
+ },
+ } = options;
+
+ return useMemo(() => {
+ if (!currentHackathon) return [];
+
+ const events: TimelineEvent[] = [];
+
+ // Add start date
+ if (currentHackathon.startDate) {
+ const startDate = new Date(currentHackathon.startDate);
+ events.push({
+ event: 'Hackathon Starts',
+ date: startDate.toLocaleDateString('en-US', dateFormat),
+ rawDate: startDate,
+ type: 'start',
+ });
+ }
+
+ // Add submission deadline
+ if (currentHackathon.deadline) {
+ const deadline = new Date(currentHackathon.deadline);
+ events.push({
+ event: 'Submission Deadline',
+ date: deadline.toLocaleDateString('en-US', deadlineFormat),
+ rawDate: deadline,
+ type: 'deadline',
+ });
+ }
+
+ // Add judging date
+ if (currentHackathon.judgingDate) {
+ const judgingDate = new Date(currentHackathon.judgingDate);
+ events.push({
+ event: 'Judging Period',
+ date: judgingDate.toLocaleDateString('en-US', dateFormat),
+ rawDate: judgingDate,
+ type: 'judging',
+ });
+ }
+
+ // Add winner announcement date
+ if (currentHackathon.winnerAnnouncementDate) {
+ const winnerDate = new Date(currentHackathon.winnerAnnouncementDate);
+ events.push({
+ event: 'Winners Announced',
+ date: winnerDate.toLocaleDateString('en-US', dateFormat),
+ rawDate: winnerDate,
+ type: 'winner',
+ });
+ }
+
+ // Add end date if enabled and different from winner announcement
+ if (
+ includeEndDate &&
+ currentHackathon.endDate &&
+ currentHackathon.endDate !== currentHackathon.winnerAnnouncementDate
+ ) {
+ const endDate = new Date(currentHackathon.endDate);
+ events.push({
+ event: 'Hackathon Ends',
+ date: endDate.toLocaleDateString('en-US', dateFormat),
+ rawDate: endDate,
+ type: 'end',
+ });
+ }
+
+ return events
+ .sort((a, b) => a.rawDate.getTime() - b.rawDate.getTime())
+ .map(({ ...event }) => event);
+ }, [currentHackathon, includeEndDate, dateFormat, deadlineFormat]);
+};
diff --git a/types/hackathon.ts b/types/hackathon.ts
index 2b6ab0432..b3b2b3a9b 100644
--- a/types/hackathon.ts
+++ b/types/hackathon.ts
@@ -1,3 +1,23 @@
+import {
+ HackathonPhase,
+ PrizeTier,
+ SponsorPartner,
+} from '@/lib/api/hackathons';
+
+export interface JudgingCriteria {
+ title: string;
+ weight?: number;
+ description?: string;
+}
+
+export interface Venue {
+ type: 'virtual' | 'physical';
+ country?: string;
+ state?: string;
+ city?: string;
+ venueName?: string;
+ venueAddress?: string;
+}
export interface Participant {
id: string | number;
name: string;
@@ -112,6 +132,28 @@ export interface HackathonParticipationSettings {
tabVisibility?: HackathonTabVisibility;
}
+// export interface Hackathon {
+// id: string;
+// title: string;
+// tagline: string;
+// description: string;
+// slug?: string;
+// imageUrl: string;
+// status: 'upcoming' | 'ongoing' | 'ended';
+// participants: number;
+// totalPrizePool: string;
+// deadline: string;
+// categories: string[];
+// startDate: string;
+// endDate: string;
+// organizer: string;
+// featured?: boolean;
+// resources?: string[];
+// participantType?: ParticipantType;
+// tabVisibility?: Pick
;
+// participation?: HackathonParticipationSettings;
+// }
+
export interface Hackathon {
id: string;
title: string;
@@ -132,4 +174,19 @@ export interface Hackathon {
participantType?: ParticipantType;
tabVisibility?: Pick;
participation?: HackathonParticipationSettings;
+ orgId?: string;
+ prizeTiers?: PrizeTier[];
+ teamMin?: number;
+ teamMax?: number;
+ venue?: Venue;
+ sponsors?: SponsorPartner[];
+ socialLinks?: string[];
+ contactEmail?: string;
+ telegram?: string;
+ discord?: string;
+ phases?: HackathonPhase[];
+ timezone?: string;
+ judgingDate?: string;
+ winnerAnnouncementDate?: string;
+ criteria?: JudgingCriteria[];
}