diff --git a/app/api/transparency/payouts/route.ts b/app/api/transparency/payouts/route.ts
new file mode 100644
index 0000000..d74dc48
--- /dev/null
+++ b/app/api/transparency/payouts/route.ts
@@ -0,0 +1,19 @@
+import { NextRequest, NextResponse } from "next/server";
+
+export async function GET(request: NextRequest) {
+ const { searchParams } = new URL(request.url);
+ const limit = Number(searchParams.get("limit")) || 10;
+
+ // TODO: Replace with real DB queries when backend is ready
+ const payouts: {
+ id: string;
+ contributorName: string;
+ contributorAvatar: string | null;
+ amount: number;
+ currency: string;
+ projectName: string;
+ paidAt: string;
+ }[] = [];
+
+ return NextResponse.json(payouts.slice(0, limit));
+}
\ No newline at end of file
diff --git a/app/api/transparency/stats/route.ts b/app/api/transparency/stats/route.ts
new file mode 100644
index 0000000..baf83b3
--- /dev/null
+++ b/app/api/transparency/stats/route.ts
@@ -0,0 +1,13 @@
+import { NextResponse } from "next/server";
+
+export async function GET() {
+ // TODO: Replace with real DB queries when backend is ready
+ const stats = {
+ totalFundsDistributed: 0,
+ totalContributorsPaid: 0,
+ totalProjectsFunded: 0,
+ averagePayoutTimeDays: 0,
+ };
+
+ return NextResponse.json(stats);
+}
\ No newline at end of file
diff --git a/app/transparency/page.tsx b/app/transparency/page.tsx
new file mode 100644
index 0000000..d75abd6
--- /dev/null
+++ b/app/transparency/page.tsx
@@ -0,0 +1,230 @@
+"use client";
+
+import { usePlatformStats, useRecentPayouts } from "@/hooks/use-transparency";
+import { AlertCircle, DollarSign, Users, FolderOpen, Clock } from "lucide-react";
+import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
+import { Button } from "@/components/ui/button";
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { Skeleton } from "@/components/ui/skeleton";
+import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
+import { Badge } from "@/components/ui/badge";
+import type { RecentPayout } from "@/lib/api/transparency";
+
+// Stat Card
+
+function StatCard({
+ title,
+ value,
+ icon: Icon,
+ isLoading,
+}: {
+ title: string;
+ value: string;
+ icon: React.ElementType;
+ isLoading: boolean;
+}) {
+ return (
+
+
+
+ {title}
+
+
+
+
+ {isLoading ? (
+
+ ) : (
+ {value}
+ )}
+
+
+ );
+}
+
+// Payout Row
+
+function PayoutRow({ payout }: { payout: RecentPayout }) {
+ return (
+
+
+
+
+
+ {payout.contributorName.slice(0, 2).toUpperCase()}
+
+
+
+
+ {payout.contributorName}
+
+
{payout.projectName}
+
+
+
+
+ {payout.amount.toLocaleString()} {payout.currency}
+
+
+ {new Date(payout.paidAt).toLocaleDateString()}
+
+
+
+ );
+}
+
+// Page
+
+export default function TransparencyPage() {
+ const {
+ data: stats,
+ isLoading: statsLoading,
+ isError: statsError,
+ error: statsErr,
+ refetch: refetchStats,
+ } = usePlatformStats();
+
+ const {
+ data: payouts,
+ isLoading: payoutsLoading,
+ isError: payoutsError,
+ refetch: refetchPayouts,
+ } = useRecentPayouts(10);
+
+ const statCards = [
+ {
+ title: "Total Funds Distributed",
+ value: stats
+ ? `$${stats.totalFundsDistributed.toLocaleString()}`
+ : "$0",
+ icon: DollarSign,
+ },
+ {
+ title: "Contributors Paid",
+ value: stats ? stats.totalContributorsPaid.toLocaleString() : "0",
+ icon: Users,
+ },
+ {
+ title: "Projects Funded",
+ value: stats ? stats.totalProjectsFunded.toLocaleString() : "0",
+ icon: FolderOpen,
+ },
+ {
+ title: "Avg. Payout Time",
+ value: stats ? `${stats.averagePayoutTimeDays} days` : "0 days",
+ icon: Clock,
+ },
+ ];
+
+ return (
+
+ {/* Hero Header */}
+
+
+
+ Transparency
+
+
+ A real-time look at platform funding activity, contributor payouts,
+ and ecosystem growth.
+
+
+
+
+
+
+ {/* Stats Error */}
+ {statsError && (
+
+
+ Error
+
+
+ Failed to load platform stats.{" "}
+ {(statsErr as Error)?.message}
+
+
+
+
+ )}
+
+ {/* Stats Grid */}
+
+
+ Platform Overview
+
+
+ {statCards.map((card) => (
+
+ ))}
+
+
+
+ {/* Recent Payouts */}
+
+
+ Recent Payouts
+
+
+ {payoutsError ? (
+
+
+ Error
+
+ Failed to load recent payouts.
+
+
+
+ ) : (
+
+
+ {payoutsLoading ? (
+
+ {Array.from({ length: 5 }).map((_, i) => (
+
+ ))}
+
+ ) : !payouts || payouts.length === 0 ? (
+
+ No payouts recorded yet.
+
+ ) : (
+ payouts.map((payout) => (
+
+ ))
+ )}
+
+
+ )}
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/components/global-navbar.tsx b/components/global-navbar.tsx
index df91580..ef50d75 100644
--- a/components/global-navbar.tsx
+++ b/components/global-navbar.tsx
@@ -57,6 +57,16 @@ export function GlobalNavbar() {
>
Leaderboard
+
+ Transparency
+
[...TRANSPARENCY_KEYS.all, 'stats'] as const,
+ payouts: (limit: number) => [...TRANSPARENCY_KEYS.all, 'payouts', limit] as const,
+};
+
+export const usePlatformStats = () => {
+ return useQuery({
+ queryKey: TRANSPARENCY_KEYS.stats(),
+ queryFn: () => transparencyApi.getStats(),
+ staleTime: 1000 * 60 * 10, // 10 minutes
+ });
+};
+
+export const useRecentPayouts = (limit = 10) => {
+ return useQuery({
+ queryKey: TRANSPARENCY_KEYS.payouts(limit),
+ queryFn: () => transparencyApi.getRecentPayouts(limit),
+ staleTime: 1000 * 60 * 5,
+ });
+};
\ No newline at end of file
diff --git a/lib/api/transparency.ts b/lib/api/transparency.ts
new file mode 100644
index 0000000..114d04d
--- /dev/null
+++ b/lib/api/transparency.ts
@@ -0,0 +1,33 @@
+import { z } from 'zod';
+import { get } from './client';
+
+// Schema
+export const platformStatsSchema = z.object({
+ totalFundsDistributed: z.number(),
+ totalContributorsPaid: z.number(),
+ totalProjectsFunded: z.number(),
+ averagePayoutTimeDays: z.number(),
+});
+
+export const recentPayoutSchema = z.object({
+ id: z.string(),
+ contributorName: z.string(),
+ contributorAvatar: z.string().nullable(),
+ amount: z.number(),
+ currency: z.string(),
+ projectName: z.string(),
+ paidAt: z.string(),
+});
+
+export type PlatformStats = z.infer;
+export type RecentPayout = z.infer;
+
+const TRANSPARENCY_ENDPOINT = '/api/transparency';
+
+export const transparencyApi = {
+ getStats: (): Promise =>
+ get(`${TRANSPARENCY_ENDPOINT}/stats`),
+
+ getRecentPayouts: (limit = 10): Promise =>
+ get(`${TRANSPARENCY_ENDPOINT}/payouts`, { params: { limit } }),
+};
\ No newline at end of file