);
})()}
@@ -362,27 +430,29 @@ export default function PoolAndAction() {
users still get the button so the auth modal can intercept
in place. */}
{!hasSubmitted &&
- (isButtonDisabled || !isAuthenticated ? (
+ (isClosed ? (
+ // Non-actionable status (ended / not started / archived / cancelled).
+ {getButtonText()}
+
+ ) : !isParticipant ? (
+ // Open, but the viewer hasn't joined โ JOIN first (auth-gated).
+
- )
- }
+ icon={}
>
{getButtonText()}
) : (
+ // Participant + open โ go to the submit form.
))}
+
+
);
}
diff --git a/app/(landing)/hackathons/[slug]/components/sidebar/index.tsx b/app/(landing)/hackathons/[slug]/components/sidebar/index.tsx
index 0fcf91188..d2c4c88e4 100644
--- a/app/(landing)/hackathons/[slug]/components/sidebar/index.tsx
+++ b/app/(landing)/hackathons/[slug]/components/sidebar/index.tsx
@@ -3,6 +3,7 @@ import PoolAndAction from './PoolAndAction';
import FollowAndMessage from './FollowAndMessage';
import MySubmissionPanel from './MySubmissionPanel';
import MyInvitationsPanel from './MyInvitationsPanel';
+import CommunityLinks from './CommunityLinks';
const Sidebar = () => {
return (
@@ -15,6 +16,9 @@ const Sidebar = () => {
+ {/* Community links (Discord / Telegram / socials) render only when the
+ organizer collected them in the Collaboration step. */}
+
);
};
diff --git a/app/(landing)/hackathons/[slug]/components/tabs/contents/Overview.tsx b/app/(landing)/hackathons/[slug]/components/tabs/contents/Overview.tsx
index 634b3399b..6ba0e4f55 100644
--- a/app/(landing)/hackathons/[slug]/components/tabs/contents/Overview.tsx
+++ b/app/(landing)/hackathons/[slug]/components/tabs/contents/Overview.tsx
@@ -16,6 +16,7 @@ import {
} from 'lucide-react';
import { Badge } from '@/components/ui/badge';
import { cn } from '@/lib/utils';
+import { effectivePrizeTiers } from '@/lib/utils/effective-prize-tiers';
import { useMarkdown } from '@/hooks/use-markdown';
import SponsorsSection from '../../SponsorsSection';
@@ -243,10 +244,9 @@ const Overview = () => {
// Partition tiers into overall vs track. Tiers without an
// explicit kind are treated as OVERALL for backward compat with
// hackathons created before the track structure landed.
- const overallTiers = hackathon.prizeTiers.filter(
- t => !t.kind || t.kind === 'OVERALL'
- );
- const trackTiers = hackathon.prizeTiers.filter(t => t.kind === 'TRACK');
+ const tiers = effectivePrizeTiers(hackathon);
+ const overallTiers = tiers.filter(t => !t.kind || t.kind === 'OVERALL');
+ const trackTiers = tiers.filter(t => t.kind === 'TRACK');
return (
@@ -310,64 +310,124 @@ const Overview = () => {
)}
- {trackTiers.length > 0 && (
-
-
-
-
Track Prizes
-
-
- Category prizes alongside the overall placements. Pick the
- tracks you want your submission considered for when you
- submit.
-
+ )}
{/* Legacy org-members picker โ superseded by email invitations.
Kept hidden behind a flag so we can re-surface it if a
power-user organizer asks for the direct-add path. */}
@@ -1024,91 +1058,40 @@ export default function JudgingPage() {
- {resultsPublished && (
-
-
+ {/* Winners are picked, confirmed and paid in the Winners
+ section. This tab is now read-only scoring standings. */}
+
+
+
+
+
-
- Results published
+
+ {resultsPublished
+ ? 'Winners are published'
+ : 'Ready to pick winners?'}
- Winner rankings are live. This hackathon's results
- have been finalized.
+ {resultsPublished
+ ? 'Review and pay winners in the Winners section.'
+ : 'When judging is done, pick a winner for each prize in the Winners section.'}
diff --git a/app/(landing)/organizations/[id]/hackathons/[hackathonId]/participants/page.tsx b/app/(landing)/organizations/[id]/hackathons/[hackathonId]/participants/page.tsx
index 3d6c79873..55d8c637a 100644
--- a/app/(landing)/organizations/[id]/hackathons/[hackathonId]/participants/page.tsx
+++ b/app/(landing)/organizations/[id]/hackathons/[hackathonId]/participants/page.tsx
@@ -3,6 +3,7 @@
import { useEffect, useMemo, useRef, useState, useCallback } from 'react';
import MetricsCard from '@/components/organization/cards/MetricsCard';
import { useParams } from 'next/navigation';
+import { Info } from 'lucide-react';
import { useHackathons } from '@/hooks/use-hackathons';
import { getHackathonStatistics, getHackathon } from '@/lib/api/hackathons';
import { AuthGuard } from '@/components/auth';
@@ -334,6 +335,17 @@ const ParticipantsPage: React.FC = () => {
/>
+
+
+
+ Shortlist the
+ entries you want judged. Only shortlisted submissions move on to
+ the Judging page, where your judges score them. Use the status
+ filter to find submitted entries, then shortlist or disqualify
+ each one.
+
+ {completeness.incompleteSubmissionCount} of{' '}
+ {completeness.totalShortlisted} shortlisted submissions are
+ missing scores from one or more active judges.
+