diff --git a/dongle/app/layout.tsx b/dongle/app/layout.tsx index f7fa87e..73fb573 100644 --- a/dongle/app/layout.tsx +++ b/dongle/app/layout.tsx @@ -1,7 +1,7 @@ import type { Metadata } from "next"; import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; - +import { WalletProvider } from "@/context/wallet.context"; const geistSans = Geist({ variable: "--font-geist-sans", subsets: ["latin"], @@ -27,7 +27,9 @@ export default function RootLayout({ - {children} + + {children} + ); diff --git a/dongle/app/page.tsx b/dongle/app/page.tsx index 295f8fd..dcce020 100644 --- a/dongle/app/page.tsx +++ b/dongle/app/page.tsx @@ -1,8 +1,50 @@ +"use client"; + import Image from "next/image"; +import { useWallet } from "@/context/wallet.context"; export default function Home() { + const { isConnected, isConnecting, publicKey, connectWallet, disconnectWallet } = + useWallet(); + return ( -
+
+ {/* Wallet Header */} +
+ {isConnected ? ( +
+
+ + {publicKey ? `${publicKey.substring(0, 6)}...${publicKey.substring(publicKey.length - 4)}` : "Connected"} + + +
+ ) : ( + + )} +
+
Promise; + disconnectWallet: () => void; +} + +const WalletContext = createContext(undefined); + +const WALLET_STORAGE_KEY = "dongle_wallet_state"; + +export function WalletProvider({ children }: { children: ReactNode }) { + const [publicKey, setPublicKey] = useState(null); + const [isConnected, setIsConnected] = useState(false); + const [isConnecting, setIsConnecting] = useState(false); + + useEffect(() => { + const restoreWalletState = async () => { + try { + const storedState = localStorage.getItem(WALLET_STORAGE_KEY); + if (storedState) { + const { publicKey: storedKey, isConnected: storedConnected } = JSON.parse(storedState); + if (storedConnected && storedKey) { + const isStillConnected = await walletService.isConnected(); + if (isStillConnected) { + const currentKey = await walletService.getPublicKey(); + setPublicKey(currentKey); + setIsConnected(true); + } else { + localStorage.removeItem(WALLET_STORAGE_KEY); + } + } + } + } catch (error) { + console.error("Failed to restore wallet state:", error); + localStorage.removeItem(WALLET_STORAGE_KEY); + } + }; + restoreWalletState(); + }, []); + + const connectWallet = useCallback(async () => { + if (isConnected) return; + + setIsConnecting(true); + try { + const address = await walletService.connectWallet(); + setPublicKey(address); + setIsConnected(true); + + localStorage.setItem(WALLET_STORAGE_KEY, JSON.stringify({ + publicKey: address, + isConnected: true + })); + } catch (error) { + console.error("Wallet connection failed:", error); + } finally { + setIsConnecting(false); + } + }, [isConnected]); + + const disconnectWallet = useCallback(() => { + setPublicKey(null); + setIsConnected(false); + localStorage.removeItem(WALLET_STORAGE_KEY); + }, []); + + return ( + + {children} + + ); +} + +export function useWallet(): WalletContextType { + const context = useContext(WalletContext); + if (context === undefined) { + throw new Error("useWallet must be used within a WalletProvider"); + } + return context; +} diff --git a/dongle/package-lock.json b/dongle/package-lock.json index 33c831b..bebbfd9 100644 --- a/dongle/package-lock.json +++ b/dongle/package-lock.json @@ -68,6 +68,7 @@ "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/generator": "^7.28.6", @@ -1584,6 +1585,7 @@ "integrity": "sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -1643,6 +1645,7 @@ "integrity": "sha512-npiaib8XzbjtzS2N4HlqPvlpxpmZ14FjSJrteZpPxGUaYPlvhzlzUZ4mZyABo0EFrOWnvyd0Xxroq//hKhtAWg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.53.0", "@typescript-eslint/types": "8.53.0", @@ -2142,6 +2145,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2502,6 +2506,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -3093,6 +3098,7 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -3278,6 +3284,7 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -5470,6 +5477,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -5479,6 +5487,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -6167,6 +6176,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -6329,6 +6339,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -6604,6 +6615,7 @@ "integrity": "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==", "dev": true, "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" }