diff --git a/frontend/app/connect-wallet/page.tsx b/frontend/app/connect-wallet/page.tsx new file mode 100644 index 00000000..24de7aa6 --- /dev/null +++ b/frontend/app/connect-wallet/page.tsx @@ -0,0 +1,30 @@ +"use client"; + +import React from "react"; +import Link from "next/link"; +import WalletConnectButton from "@/components/WalletConnectButton"; + +export default function ConnectWalletPage() { + return ( +
+
+

Connect Wallet

+

+ Connect your Freighter wallet to submit puzzle answers and claim + on-chain NFT rewards. +

+ +
+ +
+ + + Back to puzzles + +
+
+ ); +} diff --git a/frontend/components/WalletConnectButton.jsx b/frontend/components/WalletConnectButton.jsx new file mode 100644 index 00000000..775d979d --- /dev/null +++ b/frontend/components/WalletConnectButton.jsx @@ -0,0 +1,101 @@ +"use client"; + +import { useEffect } from "react"; +import { Button } from "@/components/ui/button"; +import LoadingSpinner from "@/components/ui/LoadingSpinner"; +import { useWalletConnection, WALLET_STATUS } from "@/hooks/useWalletConnection"; + +/** + * localStorage key used to persist the last connected Stellar address so the + * button can show a stable session across page reloads (#691). + */ +const STORAGE_KEY = "stellarhunts.wallet.address"; + +/** + * Shorten a Stellar public key for display, e.g. GABCDE...WXYZ. + */ +function shortenAddress(address) { + if (!address) return ""; + return `${address.slice(0, 4)}...${address.slice(-4)}`; +} + +/** + * WalletConnectButton + * -------------------- + * Freighter wallet connect button (#691). Wraps `useWalletConnection` to + * expose a single control that: + * - connects / disconnects via Freighter + * - displays the active account address + * - surfaces a user rejection or a missing extension + * - restores the last connected address across reloads + */ +export default function WalletConnectButton({ className }) { + const { + status, + address, + error, + isExtensionInstalled, + connect, + disconnect, + } = useWalletConnection(); + + const isConnecting = status === WALLET_STATUS.CONNECTING; + const isConnected = status === WALLET_STATUS.CONNECTED && Boolean(address); + + // Persist the connected address so a reload keeps showing the active + // account instead of flashing back to the disconnected state. + useEffect(() => { + if (typeof window === "undefined") return; + if (isConnected && address) { + window.localStorage.setItem(STORAGE_KEY, address); + } else if (status === WALLET_STATUS.DISCONNECTED) { + window.localStorage.removeItem(STORAGE_KEY); + } + }, [isConnected, address, status]); + + return ( +
+ {isConnected ? ( +
+ + {shortenAddress(address)} + + +
+ ) : ( + + )} + + {error && ( +

+ {error} +

+ )} + + {!error && !isConnected && status === WALLET_STATUS.DISCONNECTED && !isExtensionInstalled && ( +

+ Freighter extension not detected. +

+ )} +
+ ); +}