From b9e2caca525ce15798d5a87ef7b48da0413ad270 Mon Sep 17 00:00:00 2001 From: dev-agent Date: Tue, 26 May 2026 10:03:40 +0000 Subject: [PATCH 1/2] [#1254] Build ReferralCTA.tsx with copy + X share Fetches referral code via unauth GET /api/airdrop/referral-code. Shows referral URL with copy-to-clipboard (desktop + mobile fallback) and X share intent button. Multiplier benefit hint. Graceful empty state when code not yet created. Closes #1254 Co-Authored-By: Claude Opus 4.7 (1M context) --- package-lock.json | 4 +- package.json | 2 +- src/components/airdrop/ReferralCTA.tsx | 76 +++++++++++++++++++++++++- 3 files changed, 76 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index eebbca7..cd975b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "plotlink", - "version": "1.38.0", + "version": "1.39.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "plotlink", - "version": "1.38.0", + "version": "1.39.0", "workspaces": [ "packages/*" ], diff --git a/package.json b/package.json index af6351e..f6ecd8c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "plotlink", - "version": "1.38.0", + "version": "1.39.0", "private": true, "workspaces": [ "packages/*" diff --git a/src/components/airdrop/ReferralCTA.tsx b/src/components/airdrop/ReferralCTA.tsx index 965e8a7..7aec662 100644 --- a/src/components/airdrop/ReferralCTA.tsx +++ b/src/components/airdrop/ReferralCTA.tsx @@ -1,10 +1,80 @@ "use client"; +import { useEffect, useState } from "react"; +import { useAccount } from "wagmi"; + export function ReferralCTA() { + const { address, isConnected } = useAccount(); + const [code, setCode] = useState(null); + const [copied, setCopied] = useState(false); + + useEffect(() => { + if (!isConnected || !address) return; + + let cancelled = false; + fetch(`/api/airdrop/referral-code?address=${address.toLowerCase()}`) + .then(r => r.ok ? r.json() : null) + .then(d => { if (!cancelled && d?.code) setCode(d.code); }) + .catch(() => {}); + return () => { cancelled = true; }; + }, [isConnected, address]); + + if (!code) { + return ( +
+

Invite Friends

+

Your referral link will appear once activation is complete.

+
+ ); + } + + const refUrl = `https://plotlink.xyz/?ref=${code}`; + const shareText = `Join the PlotLink Buy-Back Sprint! Use my referral link to boost both our multipliers:`; + const xShareUrl = `https://x.com/intent/post?text=${encodeURIComponent(shareText)}&url=${encodeURIComponent(refUrl)}`; + + const handleCopy = async () => { + try { + await navigator.clipboard.writeText(refUrl); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } catch { + const input = document.createElement("input"); + input.value = refUrl; + document.body.appendChild(input); + input.select(); + document.execCommand("copy"); + document.body.removeChild(input); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } + }; + return ( -
-

Invite Friends

-

Share your referral link to boost your multiplier.

+
+

Invite Friends

+ +
+ {refUrl} + +
+ + + Share on X + + +

+ Each qualified referral adds +0.2 to your multiplier (up to 3.0×). +

); } From 68638a8a0a87b066eb1280e0d2b736bcd7bff6ca Mon Sep 17 00:00:00 2001 From: dev-agent Date: Tue, 26 May 2026 10:05:46 +0000 Subject: [PATCH 2/2] =?UTF-8?q?[#1254]=20Fix=20stale=20code=20on=20wallet?= =?UTF-8?q?=20switch=20=E2=80=94=20key=20state=20by=20address?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Track fetched address in state so code clears automatically when wallet changes. Derive displayed code from address match instead of sync setState in effect. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/components/airdrop/ReferralCTA.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/airdrop/ReferralCTA.tsx b/src/components/airdrop/ReferralCTA.tsx index 7aec662..d90ab9e 100644 --- a/src/components/airdrop/ReferralCTA.tsx +++ b/src/components/airdrop/ReferralCTA.tsx @@ -5,7 +5,7 @@ import { useAccount } from "wagmi"; export function ReferralCTA() { const { address, isConnected } = useAccount(); - const [code, setCode] = useState(null); + const [fetchState, setFetchState] = useState<{ code: string | null; addr: string | null }>({ code: null, addr: null }); const [copied, setCopied] = useState(false); useEffect(() => { @@ -14,11 +14,13 @@ export function ReferralCTA() { let cancelled = false; fetch(`/api/airdrop/referral-code?address=${address.toLowerCase()}`) .then(r => r.ok ? r.json() : null) - .then(d => { if (!cancelled && d?.code) setCode(d.code); }) - .catch(() => {}); + .then(d => { if (!cancelled) setFetchState({ code: d?.code ?? null, addr: address.toLowerCase() }); }) + .catch(() => { if (!cancelled) setFetchState({ code: null, addr: address.toLowerCase() }); }); return () => { cancelled = true; }; }, [isConnected, address]); + const code = fetchState.addr === address?.toLowerCase() ? fetchState.code : null; + if (!code) { return (