diff --git a/app/(public)/leaderboard/[slug]/page.tsx b/app/(public)/leaderboard/[slug]/page.tsx index 24f6d83..ebfdfc4 100644 --- a/app/(public)/leaderboard/[slug]/page.tsx +++ b/app/(public)/leaderboard/[slug]/page.tsx @@ -1,7 +1,6 @@ import { createClient } from "../../../lib/supabase/server"; import LeaderboardTable, { NonNullableMember } from "../../../components/LeaderboardTable"; import LeaderboardHeader from "@/app/components/leaderboard/Header"; -import BackButton from "@/app/components/leaderboard/BackButton"; import Footer from "@/app/components/layout/Footer"; import CTA from "@/app/components/layout/CTA"; @@ -52,13 +51,14 @@ export default async function LeaderboardPage(props: { return (
-
- +
- +
+ +
{!user && } diff --git a/app/(public)/leaderboard/page.tsx b/app/(public)/leaderboard/page.tsx index ba2285d..db786ff 100644 --- a/app/(public)/leaderboard/page.tsx +++ b/app/(public)/leaderboard/page.tsx @@ -37,7 +37,7 @@ export default async function Leaderboards() { return (
- +
DevPulse Logo diff --git a/app/components/Chat.tsx b/app/components/Chat.tsx index 30a4260..06bdcc6 100644 --- a/app/components/Chat.tsx +++ b/app/components/Chat.tsx @@ -7,7 +7,6 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faPaperPlane, faPlus } from "@fortawesome/free-solid-svg-icons"; import Conversations from "./chat/Conversations"; import Messages from "./chat/Messages"; -import { toast } from "react-toastify"; export interface Conversation { id: string; diff --git a/app/components/LeaderboardTable.tsx b/app/components/LeaderboardTable.tsx index b3ada65..d772cd2 100644 --- a/app/components/LeaderboardTable.tsx +++ b/app/components/LeaderboardTable.tsx @@ -1,13 +1,13 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { - faClock, - faCode, - faTerminal, - faServer, faBolt, faFire, faStar, - faRocket, + faGhost, + faMedal, + faCrown, + faSeedling, + faMinus, } from "@fortawesome/free-solid-svg-icons"; import { Database } from "../supabase-types"; @@ -36,125 +36,102 @@ export type NonNullableMember = Omit< editors: { name: string }[]; }; -function LeaderboardStats({ members }: { members: NonNullableMember[] }) { - const totalHours = Math.round( - members.reduce((acc, m) => acc + (m.total_seconds || 0), 0) / 3600, - ); - - const languageCount: Record = {}; - const editorCount: Record = {}; - const osCount: Record = {}; - members.forEach((m) => { - (m.languages || []).forEach((l) => { - languageCount[l.name] = (languageCount[l.name] || 0) + 1; - }); - (m.editors || []).forEach((e) => { - editorCount[e.name] = (editorCount[e.name] || 0) + 1; - }); - (m.operating_systems || []).forEach((os) => { - osCount[os.name] = (osCount[os.name] || 0) + 1; - }); - }); +const getBadgeInfo = (rank: number, hours: number) => { + if (hours >= 160) return { label: "MISSION IMPOSSIBLE", class: "badge-impossible", icon: faGhost }; + if (hours >= 130) return { label: "GOD LEVEL", class: "badge-god", icon: faCrown }; + if (hours >= 100) return { label: "STARLIGHT", class: "badge-starlight", icon: faStar }; + if (hours >= 50) return { label: "ELITE", class: "badge-elite", icon: faFire }; + if (hours >= 20) return { label: "PRO", class: "badge-pro", icon: faBolt }; + if (hours >= 5) return { label: "NOVICE", class: "badge-novice", icon: faMedal }; + if (hours >= 1) return { label: "NEWBIE", class: "badge-newbie", icon: faSeedling }; + return { label: "NONE", class: "badge-none", icon: faMinus }; // 0 hours +}; - const topLanguage = - Object.entries(languageCount).sort((a, b) => b[1] - a[1])[0]?.[0] || "N/A"; - const topEditor = - Object.entries(editorCount).sort((a, b) => b[1] - a[1])[0]?.[0] || "N/A"; - const topOS = - Object.entries(osCount).sort((a, b) => b[1] - a[1])[0]?.[0] || "N/A"; +function LeaderboardPodium({ topUsers }: { topUsers: { user_id: string; rank: number; email: string | null; hours: number; role: string | null; languages: string[]; os: string; editor: string; }[] }) { + if (topUsers.length === 0) return null; return ( -
-
-
-
-
- -
- - Total Time - -
-
- {totalHours}{" "} - - hrs - -
-
+
+ {topUsers.map((user, idx) => { + const rankColor = + idx === 0 + ? "text-yellow-400 drop-shadow-[0_0_8px_rgba(250,204,21,0.4)]" + : idx === 1 + ? "text-gray-300 drop-shadow-[0_0_8px_rgba(209,213,219,0.4)]" + : "text-amber-600 drop-shadow-[0_0_8px_rgba(217,119,6,0.4)]"; + + const badgeInfo = getBadgeInfo(user.rank, user.hours); + const initial = (user.email?.[0] || "?").toUpperCase(); -
-
-
-
- -
- - Top Lang - -
-
- {topLanguage} -
-
+ return ( +
+ {/* Minimal Background Glow based on rank */} +
-
-
-
-
- -
- - Editor - -
-
- {topEditor} -
-
+
+
+
+ {initial} +
+
+
+ {user.email?.split("@")[0] || "Unknown"} +
+
+ {badgeInfo.icon && ( + + )} + {badgeInfo.label} +
+
+
+ +
+ + {idx === 0 ? "01" : idx === 1 ? "02" : "03"} + +
+
-
-
-
-
- + {/* Stats Row */} +
+
+ + Hours + + + {user.hours} + +
+
+ + Language + + + {user.languages?.[0] || "N/A"} + +
+
+ + Editor + + + {user.editor || "N/A"} + +
+
- - OS - -
-
- {topOS} -
-
+ ); + })}
); } -const getBadgeInfo = (rank: number, hours: number) => { - if (rank === 1) - return { label: "GOD LEVEL", class: "badge-god", icon: faBolt }; - if (rank === 2) return { label: "ELITE", class: "badge-elite", icon: faFire }; - if (rank === 3) return { label: "PRO", class: "badge-pro", icon: faStar }; - if (hours > 100) - return { label: "MASTER", class: "badge-master", icon: faRocket }; - if (hours > 20) - return { label: "HUSTLER", class: "badge-hustler", icon: null }; - return { label: "NOVICE", class: "badge-novice", icon: null }; -}; +import LeaderboardStats from "./leaderboard/LeaderboardStats"; export default function LeaderboardTable({ members, @@ -188,7 +165,7 @@ export default function LeaderboardTable({ }; return ( -
+