Skip to content
Closed
Show file tree
Hide file tree
Changes from 6 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
2 changes: 1 addition & 1 deletion app/ThemeSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
} from "@/components/ui/dropdown-menu";

export default function ThemeSelector() {
const { setTheme, theme } = useTheme();
const { setTheme } = useTheme();

const handleThemeChange = (newTheme: string) => {
// Ensure only valid theme values are set
Expand Down
107 changes: 25 additions & 82 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,98 +1,41 @@
import { ActivityTypes } from "@/components/Leaderboard/stats-card/activity-types";
import { ActivityLineCard } from "@/components/Leaderboard/stats-card/activity-line-card";
import ActiveContributors from "@/components/Leaderboard/stats-card/active-contributors";
import { PaginatedActivitySection } from "@/components/PaginatedActivitySection";

// app/page.tsx
import {
ActivityGroup,
getMonthlyActivityBuckets,
getPreviousMonthActivityCount,
getRecentActivitiesGroupedByType,
getReposOverview,
} from "@/lib/db";

import Link from "next/link";
import { getConfig } from "@/lib/config";
import { ArrowRight } from "lucide-react";
import HomeDashboard from "@/components/home-dashboard"; // New Client Component

export default async function Home() {
const config = getConfig();

// 1. Fetch Existing Overview Data (Server Side)
const totalCount = (groups: ActivityGroup[]) =>
groups.reduce((sum, g) => sum + g.activities.length, 0);

const week = await getRecentActivitiesGroupedByType(
"week"
);
const month = await getRecentActivitiesGroupedByType(
"month"
);

const previousMonthCount =
await getPreviousMonthActivityCount();
const week = await getRecentActivitiesGroupedByType("week");
const month = await getRecentActivitiesGroupedByType("month");
const previousMonthCount = await getPreviousMonthActivityCount();
const bucketData = await getMonthlyActivityBuckets();

return (
<div className="min-h-screen transition-colors">
<div className="mx-auto max-w-7xl px-4 sm:px-6 py-10 space-y-14">
<section className="text-center space-y-4">
<h1
className="text-5xl sm:text-5xl lg:text-7xl font-bold tracking-tight bg-clip-text text-transparent bg-linear-to-r from-[#50B78B] via-[#60C79B] to-[#70D7AB]
"
>
{config.org.name}
</h1>
<p className="max-w-2xl mx-auto text-sm sm:text-base text-zinc-600 dark:text-zinc-400">
{config.org.description}
</p>
</section>

<section className="grid gap-6 select-none sm:grid-cols-2 lg:grid-cols-3">
<ActivityLineCard
totalActivitiesLabel={totalCount(month)}
prev_month={previousMonthCount}
week1={bucketData.w1}
week2={bucketData.w2}
week3={bucketData.w3}
week4={bucketData.w4}
/>
<ActiveContributors data={month} />
<ActivityTypes
entries={month}
totalActivities={totalCount(month)}
/>
</section>

<section className="space-y-6 max-w-5xl mx-auto">
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3">
<h2 className="text-xl sm:text-2xl font-bold text-[#50B78B]">
Recent Activities
</h2>
<Link
href="/leaderboard"
className="flex items-center gap-2 text-sm font-medium text-[#50B78B]"
>
View Leaderboard
<ArrowRight className="h-4 w-4" />
</Link>
</div>

{week.length === 0 ? (
<div className="rounded-2xl border p-10 text-center text-zinc-500">
No activity in this period
</div>
) : (
<div className="space-y-8">
{week.map((group) => (
<PaginatedActivitySection
key={group.activity_definition}
group={group}
itemsPerPage={10}
/>
))}
</div>
)}
</section>
</div>
</div>
);
}
const reposOverview = await getReposOverview();

// 2. Bundle data for the client component
const overviewData = {
totalMonth: totalCount(month),
week,
month,
previousMonthCount,
bucketData,
config,
reposData: {
reposOverview
}
};

// 3. Pass data to the interactive dashboard
return <HomeDashboard overviewData={overviewData} />;
}
8 changes: 4 additions & 4 deletions components/Leaderboard/LeaderboardCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ export function LeaderboardCard({
{/* Activity Tags */}
<div className="space-y-1 flex-1">
{sortActivitiesByPriority(Object.entries(entry.activity_breakdown))
.filter(([activityName, data]) => data.count > 0)
.filter(([_activityName, data]) => data.count > 0)
.map(([activityName, data]) => {
const style = getActivityStyle(activityName);
const IconComponent = style.icon;
Expand Down Expand Up @@ -311,7 +311,7 @@ export function LeaderboardCard({
{/* Activity Breakdown */}
<div className="flex flex-wrap gap-2">
{sortActivitiesByPriority(Object.entries(entry.activity_breakdown))
.filter(([activityName, data]) => data.count > 0)
.filter(([_activityName, data]) => data.count > 0)
.map(([activityName, data]) => {
const style = getActivityStyle(activityName);
const IconComponent = style.icon;
Expand Down Expand Up @@ -452,7 +452,7 @@ export function LeaderboardCard({
{/* Activity Tags */}
<div className="space-y-1 flex-1">
{sortActivitiesByPriority(Object.entries(entry.activity_breakdown))
.filter(([activityName, data]) => data.count > 0)
.filter(([_activityName, data]) => data.count > 0)
.map(([activityName, data]) => {
const style = getActivityStyle(activityName);
const IconComponent = style.icon;
Expand Down Expand Up @@ -547,7 +547,7 @@ export function LeaderboardCard({
<div className="flex-1 w-full">
<div className="space-y-1.5">
{sortActivitiesByPriority(Object.entries(entry.activity_breakdown))
.filter(([activityName, data]) => data.count > 0)
.filter(([_activityName, data]) => data.count > 0)
.map(([activityName, data]) => {
const style = getActivityStyle(activityName);
const IconComponent = style.icon;
Expand Down
25 changes: 12 additions & 13 deletions components/Leaderboard/LeaderboardView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
import { cn } from "@/lib/utils";
import { useMemo, useState, useEffect, useRef } from "react";
import { sortEntries, type SortBy } from "@/lib/leaderboard";
import { useRouter, useSearchParams, usePathname } from "next/navigation";
import { useSearchParams, usePathname } from "next/navigation";
import { Input } from "@/components/ui/input";
import { LeaderboardCard, type LeaderboardEntry } from "./LeaderboardCard";
import {
Expand Down Expand Up @@ -120,7 +120,6 @@ export default function LeaderboardView({
topByActivity,
hiddenRoles,
}: LeaderboardViewProps) {
const router = useRouter();
const searchParams = useSearchParams();

const [searchQuery, setSearchQuery] = useState("");
Expand Down Expand Up @@ -453,15 +452,15 @@ export default function LeaderboardView({
}
};

const updateRolesParam = (roles: Set<string>) => {
const params = new URLSearchParams(searchParams.toString());
if (roles.size > 0) {
params.set("roles", Array.from(roles).join(","));
} else {
params.delete("roles");
}
if (typeof window !== 'undefined') window.history.replaceState(null, '', `${pathname}?${params.toString()}`);
};
// const updateRolesParam = (roles: Set<string>) => {
// const params = new URLSearchParams(searchParams.toString());
// if (roles.size > 0) {
// params.set("roles", Array.from(roles).join(","));
// } else {
// params.delete("roles");
// }
// if (typeof window !== 'undefined') window.history.replaceState(null, '', `${pathname}?${params.toString()}`);
// };

const filteredTopByActivity = useMemo(() => {
if (selectedRoles.size === 0) {
Expand Down Expand Up @@ -634,7 +633,7 @@ export default function LeaderboardView({
return (
<button
key={opt.key}
onClick={(e) => {
onClick={(_e) => {
setPopoverOpen(false);
setSortBy(opt.key as SortBy);
const params = new URLSearchParams(searchParams.toString());
Expand Down Expand Up @@ -809,7 +808,7 @@ export default function LeaderboardView({
? "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-6"
: "space-y-4"
)}>
{paginatedEntries.map((entry, index) => {
{paginatedEntries.map((entry) => {
// Use the pre-computed rank from entryRanks, which is based on full sorted list
// This ensures rank doesn't change with search or pagination
const rank = entryRanks.get(entry.username) || 1;
Expand Down
Loading