From b4f6cb047f4ddc8acd13c03faa61f110bd2dabda Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Sat, 14 Mar 2026 11:56:40 +0000 Subject: [PATCH] [#204] Build reader dashboard with donation history and Phase 5 portfolio placeholder - Create /dashboard/reader route (client component, wallet-gated) - Fetch donation history by connected wallet via react-query - Show donation list with storyline ID, date, and $PLOT amount - Display total donated amount - Portfolio section placeholder clearly marked for Phase 5 (P5-7b) - Terminal aesthetic throughout Fixes #204 Co-Authored-By: Claude Opus 4.6 (1M context) --- src/app/dashboard/reader/page.tsx | 113 ++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 src/app/dashboard/reader/page.tsx diff --git a/src/app/dashboard/reader/page.tsx b/src/app/dashboard/reader/page.tsx new file mode 100644 index 00000000..56354378 --- /dev/null +++ b/src/app/dashboard/reader/page.tsx @@ -0,0 +1,113 @@ +"use client"; + +import { useAccount } from "wagmi"; +import { useQuery } from "@tanstack/react-query"; +import { supabase, type Donation } from "../../../../lib/supabase"; +import { ConnectWallet } from "../../../components/ConnectWallet"; +import { formatUnits } from "viem"; + +async function fetchDonations(address: string): Promise { + if (!supabase) return []; + const { data } = await supabase + .from("donations") + .select("*") + .eq("donor_address", address.toLowerCase()) + .order("block_timestamp", { ascending: false }) + .returns(); + return data ?? []; +} + +export default function ReaderDashboard() { + const { address, isConnected } = useAccount(); + + const { data: donations = [], isLoading } = useQuery({ + queryKey: ["reader-donations", address], + queryFn: () => fetchDonations(address!), + enabled: isConnected && !!address, + }); + + if (!isConnected) { + return ( +
+

+ Connect your wallet to view your dashboard. +

+ +
+ ); + } + + const totalDonated = donations.reduce( + (sum, d) => sum + BigInt(d.amount), + BigInt(0), + ); + + return ( +
+

+ Reader Dashboard +

+ + {/* --- Portfolio section (Phase 5) --- */} +
+

Portfolio

+

+ Token holdings and portfolio value available after Phase 5 (P5-7b). +

+
+ + {/* --- Donation History --- */} +
+

+ Donation History +

+

+ {donations.length}{" "} + {donations.length === 1 ? "donation" : "donations"} + {donations.length > 0 && ( + + {" "} + · {formatUnits(totalDonated, 18)} $PLOT total + + )} +

+ + {isLoading &&

Loading...

} + +
+ {donations.map((d) => ( + + ))} + {!isLoading && donations.length === 0 && ( +

+ No donations yet. +

+ )} +
+
+
+ ); +} + +function DonationRow({ donation }: { donation: Donation }) { + return ( +
+
+ + Story #{donation.storyline_id} + + {donation.block_timestamp && ( + + )} +
+ + {formatUnits(BigInt(donation.amount), 18)} $PLOT + +
+ ); +}