diff --git a/app/bounty/page.tsx b/app/bounty/page.tsx
index 7b32e76..bb231e5 100644
--- a/app/bounty/page.tsx
+++ b/app/bounty/page.tsx
@@ -229,7 +229,7 @@ export default function BountiesPage() {
setSearchQuery(e.target.value)}
/>
diff --git a/app/globals.css b/app/globals.css
index e3f8d6c..c4ef028 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -118,6 +118,7 @@
* {
@apply border-border outline-ring/50;
}
+
body {
@apply bg-background text-foreground;
}
diff --git a/app/leaderboard/page.tsx b/app/leaderboard/page.tsx
index d8b3978..ae98942 100644
--- a/app/leaderboard/page.tsx
+++ b/app/leaderboard/page.tsx
@@ -82,10 +82,10 @@ export default function LeaderboardPage() {
{/* Hero Header */}
-
+
Leaderboard
-
+
Recognizing the top contributors in the ecosystem.
diff --git a/app/profile/[userId]/page.tsx b/app/profile/[userId]/page.tsx
new file mode 100644
index 0000000..77f8d29
--- /dev/null
+++ b/app/profile/[userId]/page.tsx
@@ -0,0 +1,157 @@
+"use client";
+
+import { useContributorReputation } from "@/hooks/use-reputation";
+import { ReputationCard } from "@/components/reputation/reputation-card";
+import { CompletionHistory } from "@/components/reputation/completion-history";
+import { Button } from "@/components/ui/button";
+import { Skeleton } from "@/components/ui/skeleton";
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
+import { AlertCircle, ChevronLeft } from "lucide-react";
+import Link from "next/link";
+import { useParams } from "next/navigation";
+import { useMemo } from "react";
+
+export default function ProfilePage() {
+ const params = useParams();
+ const userId = params.userId as string;
+ const { data: reputation, isLoading, error } = useContributorReputation(userId);
+
+ const MAX_MOCK_HISTORY = 50;
+
+ const mockHistory = useMemo(() => {
+ if (!reputation) return [];
+ const count = Math.min(reputation.stats.totalCompleted ?? 0, MAX_MOCK_HISTORY);
+ return Array(count).fill(null).map((_, i) => ({
+ id: `bounty-${i}`,
+ bountyId: `b-${i}`,
+ bountyTitle: `Implemented feature #${100 + i}`,
+ projectName: "Drips Protocol",
+ projectLogoUrl: null,
+ difficulty: ["BEGINNER", "INTERMEDIATE", "ADVANCED"][i % 3] as "BEGINNER" | "INTERMEDIATE" | "ADVANCED",
+ rewardAmount: 500,
+ rewardCurrency: "USDC",
+ claimedAt: "2023-01-01T00:00:00Z",
+ completedAt: "2024-01-15T12:00:00Z",
+ completionTimeHours: 48,
+ maintainerRating: 5,
+ maintainerFeedback: "Great work!",
+ pointsEarned: 150
+ }));
+ }, [reputation]);
+
+ if (isLoading) {
+ return (
+
+ );
+ }
+
+ if (error) {
+ // Check if it's a 404 (Not Found)
+ const apiError = error as { status?: number; message?: string };
+ const isNotFound = apiError?.status === 404 || apiError?.message?.includes("404");
+
+ if (isNotFound) {
+ return (
+
+
+
Profile Not Found
+
+ We could not find a reputation profile for this user.
+
+
+
+ );
+ }
+
+ // Generic Error
+ return (
+
+
+
Something went wrong
+
+ We encountered an error while loading the profile.
+
+
+
+ );
+ }
+
+ if (!reputation) {
+ return (
+
+
+
Profile Not Found
+
+ We could not find a reputation profile for this user.
+
+
+
+ );
+ }
+
+ return (
+
+
+
+
+ {/* Left Sidebar: Reputation Card */}
+
+
+
+ {/* Additional Sidebar Info could go here */}
+
+
+ {/* Main Content: Activity & History */}
+
+
+
+
+ Bounty History
+
+
+ Analytics
+
+
+
+
+ Activity History
+
+
+
+
+
+ Detailed analytics coming soon.
+
+
+
+
+
+
+ );
+}
diff --git a/components/bounty/bounty-sidebar.tsx b/components/bounty/bounty-sidebar.tsx
index 1808aeb..f11640d 100644
--- a/components/bounty/bounty-sidebar.tsx
+++ b/components/bounty/bounty-sidebar.tsx
@@ -10,6 +10,7 @@ import { formatDistanceToNow } from "date-fns"
// import { useRouter } from "next/navigation" // If we need refresh
import { ApplicationDialog } from "./application-dialog"
import { toast } from "sonner"
+import { ParticipantCard } from "./participant-card"
interface BountySidebarProps {
bounty: Bounty
@@ -166,6 +167,15 @@ export function BountySidebar({ bounty }: BountySidebarProps) {
+ {bounty.claimedBy && (
+ <>
+
+
+ >
+ )}
+
+
+
+
+
+
+
+ );
+ }
+
+ if (!reputation) {
+ return (
+