diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx new file mode 100644 index 0000000..a103694 --- /dev/null +++ b/src/app/dashboard/page.tsx @@ -0,0 +1,188 @@ +"use client"; + +import { useEffect, useState } from "react"; +import Link from "next/link"; +import { Navbar } from "@/components/Navbar"; +import { GroupCard } from "@/components/GroupCard"; +import { useWallet } from "@/app/providers"; +import { SavingsGroup, GroupStatus, formatAmount } from "@sorosave/sdk"; + +// Placeholder data - will be replaced with contract queries filtered by connected wallet +const PLACEHOLDER_GROUPS: SavingsGroup[] = [ + { + id: 1, + name: "Lagos Savings Circle", + admin: "GABCDEFGHIJKLMNOPQRSTUVWXYZ234567ABCDEFG", + token: "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC", + contributionAmount: 1000000000n, + cycleLength: 604800, + maxMembers: 5, + members: ["GABCD...", "GEFGH...", "GIJKL..."], + payoutOrder: [], + currentRound: 0, + totalRounds: 0, + status: GroupStatus.Forming, + createdAt: 1700000000, + }, + { + id: 2, + name: "DeFi Builders Fund", + admin: "GABCDEFGHIJKLMNOPQRSTUVWXYZ234567ABCDEFG", + token: "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC", + contributionAmount: 5000000000n, + cycleLength: 2592000, + maxMembers: 10, + members: ["GABCD...", "GEFGH...", "GIJKL...", "GMNOP...", "GQRST..."], + payoutOrder: ["GABCD...", "GEFGH...", "GIJKL...", "GMNOP...", "GQRST..."], + currentRound: 2, + totalRounds: 5, + status: GroupStatus.Active, + createdAt: 1699000000, + }, +]; + +function needsContribution(group: SavingsGroup): boolean { + return group.status === GroupStatus.Active && group.currentRound < group.totalRounds; +} + +function StatCard({ label, value, sub, color = "text-gray-900" }: { + label: string; value: string; sub?: string; color?: string; +}) { + return ( +
+

{label}

+

{value}

+ {sub &&

{sub}

} +
+ ); +} + +export default function DashboardPage() { + const { address, isConnected } = useWallet(); + const [groups, setGroups] = useState([]); + const [isLoading, setIsLoading] = useState(true); + + useEffect(() => { + // TODO: Replace with sorosaveClient.getGroupsByMember(address) + const timer = setTimeout(() => { + setGroups(PLACEHOLDER_GROUPS); + setIsLoading(false); + }, 500); + return () => clearTimeout(timer); + }, [address]); + + const activeGroups = groups.filter((g) => g.status === GroupStatus.Active); + const actionGroups = groups.filter(needsContribution); + + const totalContributed = groups.reduce((sum, g) => { + const rounds = BigInt(Math.min(g.currentRound, g.totalRounds)); + return sum + g.contributionAmount * rounds; + }, 0n); + + const totalReceived = groups.reduce((sum, g) => { + if (g.payoutOrder.length === 0 || g.currentRound === 0) return sum; + // User receives pot once when it's their turn; simplified as 1 payout per active/completed group + const pot = g.contributionAmount * BigInt(g.members.length); + return g.currentRound > 0 ? sum + pot : sum; + }, 0n); + + if (!isConnected) { + return ( + <> + +
+
+

Connect Your Wallet

+

+ Connect your Freighter wallet to view your savings groups, contributions, and upcoming payouts. +

+
+
+ + ); + } + + return ( + <> + +
+
+
+

My Dashboard

+

+ {address ? `${address.slice(0, 8)}...${address.slice(-6)}` : ""} +

+
+ + Browse Groups + +
+ + {/* Summary */} +
+ + + + 0 ? "action required" : "all caught up"} + color="text-amber-600" /> +
+ + {isLoading ? ( +
+
+

Loading your groups...

+
+ ) : groups.length === 0 ? ( +
+

No groups yet

+

Join or create a savings group to get started.

+
+ + Browse Groups + + + Create Group + +
+
+ ) : ( + <> + {/* Groups needing contribution */} + {actionGroups.length > 0 && ( +
+

+ + Needs Your Contribution +

+
+ {actionGroups.map((g) => ( +
+ +
+ ))} +
+
+ )} + + {/* All groups */} +
+

All My Groups

+
+ {groups.map((g) => ( + + ))} +
+
+ + )} +
+ + ); +} diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index 2d673aa..0ef1764 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -13,6 +13,12 @@ export function Navbar() { SoroSave
+ + Dashboard +