diff --git a/package-lock.json b/package-lock.json index 0411ca6..c8b864e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "plotlink", - "version": "1.36.0", + "version": "1.37.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "plotlink", - "version": "1.36.0", + "version": "1.37.0", "workspaces": [ "packages/*" ], diff --git a/package.json b/package.json index fe9fa37..b8b2820 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "plotlink", - "version": "1.36.0", + "version": "1.37.0", "private": true, "workspaces": [ "packages/*" diff --git a/src/components/airdrop/ContributionPanel.tsx b/src/components/airdrop/ContributionPanel.tsx index dc3ab6d..7a0402c 100644 --- a/src/components/airdrop/ContributionPanel.tsx +++ b/src/components/airdrop/ContributionPanel.tsx @@ -1,10 +1,131 @@ "use client"; +import { useEffect, useState } from "react"; +import { useAccount } from "wagmi"; + +interface ProjectionData { + address: string; + buy_volume: number; + qualified_refs: number; + has_fc_bonus: boolean; + multiplier: number; + weighted_spend: number; + community_total: number; + projected_share: { + bronze: number; + silver: number; + gold: number; + diamond: number; + }; +} + +function Stat({ label, value, accent }: { label: string; value: string; accent?: boolean }) { + return ( +
+
{label}
+
{value}
+
+ ); +} + export function ContributionPanel() { + const { address, isConnected } = useAccount(); + const [fetchState, setFetchState] = useState<{ + data: ProjectionData | null; + error: string | null; + done: boolean; + }>({ data: null, error: null, done: !isConnected }); + + useEffect(() => { + if (!isConnected || !address) return; + + let cancelled = false; + fetch(`/api/airdrop/projection?address=${address.toLowerCase()}`) + .then(res => { + if (res.status === 404) return null; + if (!res.ok) throw new Error("Failed to load"); + return res.json(); + }) + .then(d => { if (!cancelled) setFetchState({ data: d, error: null, done: true }); }) + .catch(() => { if (!cancelled) setFetchState({ data: null, error: "Failed to load contribution data.", done: true }); }); + + return () => { cancelled = true; setFetchState({ data: null, error: null, done: false }); }; + }, [isConnected, address]); + + const { data, error } = fetchState; + const loading = isConnected && !fetchState.done; + + if (loading) { + return ( +
+

Loading contribution data...

+
+ ); + } + + if (error) { + return ( +
+

{error}

+
+ ); + } + + if (!data) { + return ( +
+

Your Contribution

+

Buy PLOT tokens to start earning your share of the airdrop pool.

+
+ ); + } + + const currentShare = data.community_total > 0 + ? (data.weighted_spend / data.community_total * 100).toFixed(2) + : "0.00"; + return ( -
-

Your Contribution

-

Buy PLOT tokens to earn your share of the airdrop pool.

+
+

Your Contribution

+ +
+ + + + + + +
+ +
+
Projected Share by Milestone
+
+
+
Bronze
+
{Math.round(data.projected_share.bronze).toLocaleString()}
+
PLOT
+
+
+
Silver
+
{Math.round(data.projected_share.silver).toLocaleString()}
+
PLOT
+
+
+
Gold
+
{Math.round(data.projected_share.gold).toLocaleString()}
+
PLOT
+
+
+
Diamond
+
{Math.round(data.projected_share.diamond).toLocaleString()}
+
PLOT
+
+
+
); }