From bbc0d3707245baf0fed4799ce39d11e06105410f Mon Sep 17 00:00:00 2001 From: Om Swami Date: Wed, 12 Nov 2025 21:30:20 +0530 Subject: [PATCH 01/14] feat: update examples --- examples/next-js/app/globals.css | 60 ++++ examples/next-js/app/page.tsx | 476 ++++++++++++++++++++++++++++++- examples/next-js/package.json | 1 + examples/next-js/utils/wallet.ts | 26 +- examples/vite-core/src/App.tsx | 55 +++- examples/vite-core/src/index.css | 60 ++++ 6 files changed, 661 insertions(+), 17 deletions(-) diff --git a/examples/next-js/app/globals.css b/examples/next-js/app/globals.css index f73f4812..e37c6bb4 100644 --- a/examples/next-js/app/globals.css +++ b/examples/next-js/app/globals.css @@ -172,3 +172,63 @@ button[type='submit'] { padding: 0.5rem; border-radius: 4px; } + +.button-group { + display: flex; + gap: 0.5rem; + margin-top: 0.5rem; +} + +.preview-result { + margin-top: 1rem; + padding: 1rem; + background-color: #333; + border-radius: 8px; + border: 1px solid #444; +} + +.preview-result h4 { + margin-top: 0; + margin-bottom: 0.75rem; + color: rgba(255, 255, 255, 0.87); +} + +.preview-info { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.preview-info > div { + line-height: 1.6; +} + +.preview-info strong { + color: #4a9eff; +} + +.preview-result details { + margin-top: 0.75rem; + cursor: pointer; +} + +.preview-result summary { + padding: 0.5rem; + background-color: #242424; + border-radius: 4px; + user-select: none; +} + +.preview-result summary:hover { + background-color: #2a2a2a; +} + +.preview-result pre { + margin-top: 0.5rem; + padding: 0.75rem; + background-color: #1a1a1a; + border-radius: 4px; + overflow-x: auto; + font-size: 0.85rem; + line-height: 1.4; +} diff --git a/examples/next-js/app/page.tsx b/examples/next-js/app/page.tsx index 3c1e1632..a9c30737 100644 --- a/examples/next-js/app/page.tsx +++ b/examples/next-js/app/page.tsx @@ -1,10 +1,10 @@ 'use client' import { SetStateAction, useCallback, useEffect, useState } from 'react' -import { wallet } from '@/utils/wallet' +import { wallet, director } from '@/utils/wallet' const TESTNET_FEDERATION_CODE = - 'fed11qgqzc2nhwden5te0vejkg6tdd9h8gepwvejkg6tdd9h8garhduhx6at5d9h8jmn9wshxxmmd9uqqzgxg6s3evnr6m9zdxr6hxkdkukexpcs3mn7mj3g5pc5dfh63l4tj6g9zk4er' + 'fed11qgqrgvnhwden5te0v9k8q6rp9ekh2arfdeukuet595cr2ttpd3jhq6rzve6zuer9wchxvetyd938gcewvdhk6tcqqysptkuvknc7erjgf4em3zfh90kffqf9srujn6q53d6r056e4apze5cw27h75' // Expose the wallet to the global window object for testing // @ts-ignore @@ -14,7 +14,7 @@ const useIsOpen = () => { const [open, setIsOpen] = useState(false) const checkIsOpen = useCallback(() => { - if (open !== wallet.isOpen()) { + if (wallet && open !== wallet?.isOpen()) { setIsOpen(wallet.isOpen()) } }, [open]) @@ -30,7 +30,7 @@ const useBalance = (checkIsOpen: () => void) => { const [balance, setBalance] = useState(0) useEffect(() => { - const unsubscribe = wallet.balance.subscribeBalance( + const unsubscribe = wallet?.balance.subscribeBalance( (balance: SetStateAction) => { checkIsOpen() setBalance(balance) @@ -38,7 +38,7 @@ const useBalance = (checkIsOpen: () => void) => { ) return () => { - unsubscribe() + unsubscribe?.() } }, [checkIsOpen]) @@ -78,15 +78,219 @@ const App = () => {
+ + + + +
) } +const MnemonicManager = () => { + const [mnemonicState, setMnemonicState] = useState('') + const [inputMnemonic, setInputMnemonic] = useState('') + const [activeAction, setActiveAction] = useState< + 'get' | 'set' | 'generate' | null + >(null) + const [isLoading, setIsLoading] = useState(false) + const [message, setMessage] = useState<{ + text: string + type: 'success' | 'error' + }>() + const [showMnemonic, setShowMnemonic] = useState(false) + + const clearMessage = () => setMessage(undefined) + + // Helper function to extract user-friendly error messages + const extractErrorMessage = (error: any): string => { + let errorMsg = 'Operation failed' + + if (error instanceof Error) { + errorMsg = error.message + } else if (typeof error === 'object' && error !== null) { + // Handle RPC error objects + const rpcError = error as any + if (rpcError.error) { + errorMsg = rpcError.error + } else if (rpcError.message) { + errorMsg = rpcError.message + } + } + + return errorMsg + } + + const handleAction = async (action: 'get' | 'set' | 'generate') => { + if (activeAction === action) { + setActiveAction(null) + return + } + setActiveAction(action) + clearMessage() + + if (action === 'get') { + await handleGetMnemonic() + } else if (action === 'generate') { + await handleGenerateMnemonic() + } + } + + const handleGenerateMnemonic = async () => { + setIsLoading(true) + try { + if (!director) throw new Error('Director unavailable') + const newMnemonic = await director.generateMnemonic() + setMnemonicState(newMnemonic.join(' ')) + setMessage({ text: 'New mnemonic generated!', type: 'success' }) + setShowMnemonic(true) + } catch (error) { + console.error('Error generating mnemonic:', error) + const errorMsg = extractErrorMessage(error) + setMessage({ text: errorMsg, type: 'error' }) + } finally { + setIsLoading(false) + } + } + + const handleGetMnemonic = async () => { + setIsLoading(true) + try { + if (!director) throw new Error('Director unavailable') + const mnemonic = await director.getMnemonic() + if (mnemonic && mnemonic.length > 0) { + setMnemonicState(mnemonic.join(' ')) + setMessage({ text: 'Mnemonic retrieved!', type: 'success' }) + setShowMnemonic(true) + } else { + setMessage({ text: 'No mnemonic found', type: 'error' }) + } + } catch (error) { + console.error('Error getting mnemonic:', error) + const errorMsg = extractErrorMessage(error) + setMessage({ text: errorMsg, type: 'error' }) + } finally { + setIsLoading(false) + } + } + + const handleSetMnemonic = async (e: React.FormEvent) => { + e.preventDefault() + if (!inputMnemonic.trim()) return + + setIsLoading(true) + try { + if (!director) throw new Error('Director unavailable') + const words = inputMnemonic.trim().split(/\s+/) + await director.setMnemonic(words) + setMessage({ text: 'Mnemonic set successfully!', type: 'success' }) + setInputMnemonic('') + setMnemonicState(words.join(' ')) + setActiveAction(null) + } catch (error) { + console.error('Error setting mnemonic:', error) + const errorMsg = extractErrorMessage(error) + setMessage({ text: errorMsg, type: 'error' }) + } finally { + setIsLoading(false) + } + } + + const copyToClipboard = async () => { + try { + await navigator.clipboard.writeText(mnemonicState) + setMessage({ text: 'Copied to clipboard!', type: 'success' }) + } catch (error) { + setMessage({ text: 'Failed to copy', type: 'error' }) + } + } + + return ( +
+

🔑 Mnemonic Manager

+ +
+ + + +
+ + {activeAction === 'set' && ( +
+