diff --git a/app/(public)/leaderboard/[slug]/page.tsx b/app/(public)/leaderboard/[slug]/page.tsx index ebfdfc4..da7fc21 100644 --- a/app/(public)/leaderboard/[slug]/page.tsx +++ b/app/(public)/leaderboard/[slug]/page.tsx @@ -1,14 +1,20 @@ import { createClient } from "../../../lib/supabase/server"; -import LeaderboardTable, { NonNullableMember } from "../../../components/LeaderboardTable"; +import LeaderboardTable, { + NonNullableMember, +} from "../../../components/LeaderboardTable"; import LeaderboardHeader from "@/app/components/leaderboard/Header"; import Footer from "@/app/components/layout/Footer"; import CTA from "@/app/components/layout/CTA"; +import { getUserWithProfile } from "@/app/lib/supabase/help/user"; export default async function LeaderboardPage(props: { params: Promise<{ slug: string }>; }) { - const { slug } = await props.params; - const supabase = await createClient(); + const [{ user }, { slug }, supabase] = await Promise.all([ + getUserWithProfile(), + props.params, + createClient(), + ]); const { data: leaderboard } = await supabase .from("leaderboards") @@ -32,10 +38,6 @@ export default async function LeaderboardPage(props: { .select("*") .eq("leaderboard_id", leaderboard.id); - const { - data: { user }, - } = await supabase.auth.getUser(); - const isOwner = user?.id === leaderboard.owner_id; if (error) { diff --git a/app/(public)/leaderboard/page.tsx b/app/(public)/leaderboard/page.tsx index 1091881..17d4194 100644 --- a/app/(public)/leaderboard/page.tsx +++ b/app/(public)/leaderboard/page.tsx @@ -4,6 +4,7 @@ import Footer from "@/app/components/layout/Footer"; import CTA from "@/app/components/layout/CTA"; import Image from "next/image"; import { Metadata } from "next"; +import { getUserWithProfile } from "@/app/lib/supabase/help/user"; export const metadata: Metadata = { title: "Leaderboards - DevPulse", @@ -54,17 +55,14 @@ export const metadata: Metadata = { export default async function Leaderboards() { const supabase = await createClient(); - const [leaderboardsResult, userResult] = await Promise.all([ + const [{ data, error }, { user }] = await Promise.all([ supabase .from("leaderboards") .select("id, name, slug") .order("created_at", { ascending: false }), - supabase.auth.getUser(), + getUserWithProfile(), ]); - const { data, error } = leaderboardsResult; - const { data: user } = userResult; - if (error) { return (
+ You will receive an email with instructions to reset your password. +
+ diff --git a/app/components/dashboard/Stats.tsx b/app/components/dashboard/Stats.tsx index 6f901ce..a93e3c9 100644 --- a/app/components/dashboard/Stats.tsx +++ b/app/components/dashboard/Stats.tsx @@ -17,6 +17,7 @@ import Machines from "./widgets/Machines"; import Categories from "./widgets/Categories"; import Dependencies from "./widgets/Dependencies"; +import Image from "next/image"; export interface StatsData { total_seconds: number; @@ -36,10 +37,14 @@ export interface StatsData { interface StatsProps { name?: string; email?: string; + avatar: string | null; } -export default function Stats({ name = "User", email = "user@example.com" }: StatsProps) { - +export default function Stats({ + name = "User", + email = "user@example.com", + avatar = null, +}: StatsProps) { const [syncing, setSyncing] = useState(false); const [animated, setAnimated] = useState(false); const [profileOpen, setProfileOpen] = useState(false); @@ -48,7 +53,10 @@ export default function Stats({ name = "User", email = "user@example.com" }: Sta // Close profile dropdown when clicking outside useEffect(() => { function handleClickOutside(event: MouseEvent) { - if (profileRef.current && !profileRef.current.contains(event.target as Node)) { + if ( + profileRef.current && + !profileRef.current.contains(event.target as Node) + ) { setProfileOpen(false); } } @@ -117,25 +125,28 @@ export default function Stats({ name = "User", email = "user@example.com" }: Sta const topEditor = stats.editors[0]?.name || "N/A"; // Use actual daily_stats if available, otherwise fallback to empty/flat - const dailyData = stats.daily_stats && stats.daily_stats.length > 0 - ? stats.daily_stats.map(d => { - // Parse date to short day name (e.g., "Mon") - const dateObj = new Date(d.date); - const dayStr = dateObj.toLocaleDateString("en-US", { weekday: "short" }); - return { - day: dayStr, - hours: parseFloat((d.total_seconds / 3600).toFixed(1)), - }; - }) - : [ - { day: "Mon", hours: 0 }, - { day: "Tue", hours: 0 }, - { day: "Wed", hours: 0 }, - { day: "Thu", hours: 0 }, - { day: "Fri", hours: 0 }, - { day: "Sat", hours: 0 }, - { day: "Sun", hours: 0 } - ]; + const dailyData = + stats.daily_stats && stats.daily_stats.length > 0 + ? stats.daily_stats.map((d) => { + // Parse date to short day name (e.g., "Mon") + const dateObj = new Date(d.date); + const dayStr = dateObj.toLocaleDateString("en-US", { + weekday: "short", + }); + return { + day: dayStr, + hours: parseFloat((d.total_seconds / 3600).toFixed(1)), + }; + }) + : [ + { day: "Mon", hours: 0 }, + { day: "Tue", hours: 0 }, + { day: "Wed", hours: 0 }, + { day: "Thu", hours: 0 }, + { day: "Fri", hours: 0 }, + { day: "Sat", hours: 0 }, + { day: "Sun", hours: 0 }, + ]; // Pie data const pieData = stats.languages.slice(0, 6).map((l) => ({ @@ -193,8 +204,13 @@ export default function Stats({ name = "User", email = "user@example.com" }: Sta }, { label: "Best Day", - value: stats.best_day?.date && stats.best_day.total_seconds ? formatHours(stats.best_day.total_seconds) : "N/A", - sub: stats.best_day?.date ? new Date(stats.best_day.date).toLocaleDateString() : "", + value: + stats.best_day?.date && stats.best_day.total_seconds + ? formatHours(stats.best_day.total_seconds) + : "N/A", + sub: stats.best_day?.date + ? new Date(stats.best_day.date).toLocaleDateString() + : "", color: "#f59e0b", trend: "Top", trendUp: true, @@ -224,78 +240,127 @@ export default function Stats({ name = "User", email = "user@example.com" }: Sta+ {name} +
+{email}
+{name}
-{email}
-