From 6925acedd4d5b2a4d905e22e17dc0342db83f130 Mon Sep 17 00:00:00 2001 From: VK Date: Thu, 11 Jun 2026 07:30:16 +0400 Subject: [PATCH 01/49] feat(demo-wallet): wallet UI redesign (TON-1682) Redesign of the demo wallet on top of current main: - New dashboard: balance total, assets list, header, and Swap / Send / Receive action row. - Reworked auth flow (password setup/unlock), wallet management and wallet-selector, receive flow, and connect-to-dApp modal. - New shared UI primitives (button, dialog, drawer, modal, select, popover, segmented, icons) and fallback-image handling. - Fiat balance via rates, jetton/NFT image arrays, and the toncenter jetton-master / address-book mappers. --- apps/demo-wallet/package.json | 7 + apps/demo-wallet/src/App.css | 21 + apps/demo-wallet/src/App.tsx | 2 +- .../src/components/ActionPreviewList.tsx | 10 +- apps/demo-wallet/src/components/AppRouter.tsx | 37 +- .../src/components/BalanceTotal.tsx | 87 ++++ apps/demo-wallet/src/components/Button.tsx | 2 +- .../src/components/ConnectDappModal.tsx | 73 +++ .../src/components/DashboardActionButton.tsx | 33 ++ .../src/components/DashboardActions.tsx | 44 ++ .../src/components/DashboardAssetRow.tsx | 94 ++++ .../src/components/DashboardAssets.tsx | 195 ++++++++ .../src/components/DashboardHeader.tsx | 52 ++ .../src/components/FallbackImage.tsx | 83 ++++ .../demo-wallet/src/components/JettonFlow.tsx | 6 +- apps/demo-wallet/src/components/Modal.tsx | 106 ---- .../src/components/NetworkSelector.tsx | 42 +- apps/demo-wallet/src/components/NewLayout.tsx | 23 + apps/demo-wallet/src/components/NftsCard.tsx | 360 ++------------ .../src/components/ProtectedRoute.tsx | 8 +- .../src/components/ReceiveModal.tsx | 139 ++++++ .../src/components/SettingsDropdown.tsx | 462 ++++++------------ apps/demo-wallet/src/components/ToggleRow.tsx | 60 +++ .../components/TransactionRequestDetails.tsx | 4 +- apps/demo-wallet/src/components/WalletRow.tsx | 199 ++++++++ .../src/components/WalletSelectorModal.tsx | 91 ++++ apps/demo-wallet/src/components/index.ts | 15 +- .../src/components/swap/SwapSettings.tsx | 7 +- .../transactions/TonTransferCard.tsx | 4 +- .../centered-screen/centered-screen.tsx | 47 ++ .../shared/centered-screen/index.ts | 9 + .../shared/confirm-modal/confirm-modal.tsx | 66 +++ .../components/shared/confirm-modal/index.ts | 9 + .../src/core/components/ui/button/button.tsx | 87 ++++ .../src/core/components/ui/button/index.ts | 10 + .../src/core/components/ui/dialog/dialog.tsx | 98 ++++ .../src/core/components/ui/dialog/index.ts | 9 + .../src/core/components/ui/drawer/drawer.tsx | 95 ++++ .../src/core/components/ui/drawer/index.ts | 9 + .../src/core/components/ui/icons/icons.tsx | 80 +++ .../src/core/components/ui/icons/index.ts | 9 + .../src/core/components/ui/modal/index.ts | 10 + .../src/core/components/ui/modal/modal.tsx | 109 +++++ .../core/components/ui/option-row/index.ts | 10 + .../components/ui/option-row/option-row.tsx | 47 ++ .../src/core/components/ui/popover/index.ts | 9 + .../core/components/ui/popover/popover.tsx | 39 ++ .../src/core/components/ui/segmented/index.ts | 10 + .../components/ui/segmented/segmented.tsx | 45 ++ .../src/core/components/ui/select/index.ts | 9 + .../src/core/components/ui/select/select.tsx | 149 ++++++ .../src/core/components/ui/sonner/index.ts | 9 + .../components/ui/sonner}/sonner.tsx | 0 .../components/setup-password-screen/index.ts | 9 + .../setup-password-screen.tsx | 129 +++++ .../auth/components/unlock-screen/index.ts | 9 + .../unlock-screen/unlock-screen.tsx | 119 +++++ apps/demo-wallet/src/features/auth/index.ts | 10 + .../ledger/components/ledger-screen/index.ts | 9 + .../ledger-screen/ledger-screen.tsx | 100 ++++ apps/demo-wallet/src/features/ledger/index.ts | 9 + .../add-wallet-modal/add-wallet-modal.tsx | 48 ++ .../components/add-wallet-modal/index.ts | 10 + .../create-wallet-modal.tsx | 49 ++ .../components/create-wallet-modal/index.ts | 10 + .../create-wallet-screen.tsx | 129 +++++ .../components/create-wallet-screen/index.ts | 9 + .../import-wallet-screen.tsx | 242 +++++++++ .../components/import-wallet-screen/index.ts | 9 + .../components/welcome-screen/index.ts | 9 + .../welcome-screen/welcome-screen.tsx | 72 +++ .../src/features/wallet-setup/index.ts | 14 + .../src/features/wallet-setup/routes.ts | 17 + apps/demo-wallet/src/hooks/index.ts | 3 + apps/demo-wallet/src/hooks/useCountUp.ts | 56 +++ apps/demo-wallet/src/hooks/useJettonInfo.ts | 2 +- apps/demo-wallet/src/hooks/useMediaQuery.ts | 31 ++ .../src/hooks/useReceivedToasts.tsx | 110 +++++ .../src/hooks/useWalletDataUpdater.ts | 37 +- apps/demo-wallet/src/index.css | 6 +- apps/demo-wallet/src/main.extension.tsx | 1 + apps/demo-wallet/src/main.tsx | 1 + .../demo-wallet/src/pages/SendTransaction.tsx | 5 +- apps/demo-wallet/src/pages/SetupPassword.tsx | 114 ----- apps/demo-wallet/src/pages/SetupWallet.tsx | 146 ------ apps/demo-wallet/src/pages/UnlockWallet.tsx | 95 ---- .../demo-wallet/src/pages/WalletDashboard.tsx | 331 +------------ apps/demo-wallet/src/pages/index.ts | 3 - apps/demo-wallet/src/utils/format.ts | 41 ++ apps/demo-wallet/src/utils/formatters.ts | 17 +- apps/demo-wallet/src/utils/index.ts | 3 + apps/demo-wallet/src/utils/jetton.ts | 9 +- apps/demo-wallet/src/utils/rates.ts | 24 + apps/demo-wallet/src/utils/telegram.ts | 34 ++ apps/demo-wallet/src/vite-env.d.ts | 2 + .../appkit/actions/gasless/gasless.test.ts | 19 +- .../appkit/actions/jettons/jettons.test.ts | 50 +- demo/wallet-core/src/hooks/useWalletStore.ts | 17 + demo/wallet-core/src/index.ts | 3 + .../src/store/createWalletStore.ts | 4 + .../src/store/slices/ratesSlice.ts | 149 ++++++ .../src/store/slices/walletManagementSlice.ts | 49 +- demo/wallet-core/src/types/store.ts | 23 + .../ui/fallback-image/fallback-image.tsx | 36 ++ .../src/components/ui/fallback-image/index.ts | 10 + .../fallback-image/use-resolved-image-src.ts | Bin 0 -> 1728 bytes .../staking-balance-block.tsx | 2 +- .../staking-confirm-modal.tsx | 2 +- packages/appkit-react/src/index.ts | 1 + .../src/actions/jettons/get-jetton-info.ts | 38 +- .../appkit/src/utils/jetton/jetton-info.ts | 10 +- packages/appkit/src/utils/nft/nft-info.ts | 7 +- packages/mcp/src/services/McpWalletService.ts | 45 +- .../walletkit/src/api/interfaces/ApiClient.ts | 5 +- .../src/api/models/core/TokenImage.ts | 24 +- .../src/clients/tonapi/ApiClientTonApi.ts | 4 +- .../tonapi/mappers/map-jetton-masters.ts | 64 +-- .../clients/tonapi/mappers/map-nft-items.ts | 26 +- .../tonapi/mappers/map-user-jettons.ts | 2 +- .../clients/toncenter/ApiClientToncenter.ts | 13 +- .../toncenter/mappers/map-address-book.ts | 29 ++ .../toncenter/mappers/map-emulation.ts | 13 +- .../toncenter/mappers/map-jetton-masters.ts | 47 ++ .../src/clients/toncenter/types/metadata.ts | 1 + .../src/clients/toncenter/types/nfts.ts | 14 +- .../toncenter/types/v3/NFTCollectionV3.ts | 11 +- .../src/contracts/w5/WalletV5R1.fixture.ts | 6 +- packages/walletkit/src/core/JettonsManager.ts | 40 +- packages/walletkit/src/types/index.ts | 1 + packages/walletkit/src/types/jettons.ts | 13 +- pnpm-lock.yaml | 162 ++++++ 131 files changed, 4484 insertions(+), 1779 deletions(-) create mode 100644 apps/demo-wallet/src/components/BalanceTotal.tsx create mode 100644 apps/demo-wallet/src/components/ConnectDappModal.tsx create mode 100644 apps/demo-wallet/src/components/DashboardActionButton.tsx create mode 100644 apps/demo-wallet/src/components/DashboardActions.tsx create mode 100644 apps/demo-wallet/src/components/DashboardAssetRow.tsx create mode 100644 apps/demo-wallet/src/components/DashboardAssets.tsx create mode 100644 apps/demo-wallet/src/components/DashboardHeader.tsx create mode 100644 apps/demo-wallet/src/components/FallbackImage.tsx delete mode 100644 apps/demo-wallet/src/components/Modal.tsx create mode 100644 apps/demo-wallet/src/components/NewLayout.tsx create mode 100644 apps/demo-wallet/src/components/ReceiveModal.tsx create mode 100644 apps/demo-wallet/src/components/ToggleRow.tsx create mode 100644 apps/demo-wallet/src/components/WalletRow.tsx create mode 100644 apps/demo-wallet/src/components/WalletSelectorModal.tsx create mode 100644 apps/demo-wallet/src/core/components/shared/centered-screen/centered-screen.tsx create mode 100644 apps/demo-wallet/src/core/components/shared/centered-screen/index.ts create mode 100644 apps/demo-wallet/src/core/components/shared/confirm-modal/confirm-modal.tsx create mode 100644 apps/demo-wallet/src/core/components/shared/confirm-modal/index.ts create mode 100644 apps/demo-wallet/src/core/components/ui/button/button.tsx create mode 100644 apps/demo-wallet/src/core/components/ui/button/index.ts create mode 100644 apps/demo-wallet/src/core/components/ui/dialog/dialog.tsx create mode 100644 apps/demo-wallet/src/core/components/ui/dialog/index.ts create mode 100644 apps/demo-wallet/src/core/components/ui/drawer/drawer.tsx create mode 100644 apps/demo-wallet/src/core/components/ui/drawer/index.ts create mode 100644 apps/demo-wallet/src/core/components/ui/icons/icons.tsx create mode 100644 apps/demo-wallet/src/core/components/ui/icons/index.ts create mode 100644 apps/demo-wallet/src/core/components/ui/modal/index.ts create mode 100644 apps/demo-wallet/src/core/components/ui/modal/modal.tsx create mode 100644 apps/demo-wallet/src/core/components/ui/option-row/index.ts create mode 100644 apps/demo-wallet/src/core/components/ui/option-row/option-row.tsx create mode 100644 apps/demo-wallet/src/core/components/ui/popover/index.ts create mode 100644 apps/demo-wallet/src/core/components/ui/popover/popover.tsx create mode 100644 apps/demo-wallet/src/core/components/ui/segmented/index.ts create mode 100644 apps/demo-wallet/src/core/components/ui/segmented/segmented.tsx create mode 100644 apps/demo-wallet/src/core/components/ui/select/index.ts create mode 100644 apps/demo-wallet/src/core/components/ui/select/select.tsx create mode 100644 apps/demo-wallet/src/core/components/ui/sonner/index.ts rename apps/demo-wallet/src/{components/ui => core/components/ui/sonner}/sonner.tsx (100%) create mode 100644 apps/demo-wallet/src/features/auth/components/setup-password-screen/index.ts create mode 100644 apps/demo-wallet/src/features/auth/components/setup-password-screen/setup-password-screen.tsx create mode 100644 apps/demo-wallet/src/features/auth/components/unlock-screen/index.ts create mode 100644 apps/demo-wallet/src/features/auth/components/unlock-screen/unlock-screen.tsx create mode 100644 apps/demo-wallet/src/features/auth/index.ts create mode 100644 apps/demo-wallet/src/features/ledger/components/ledger-screen/index.ts create mode 100644 apps/demo-wallet/src/features/ledger/components/ledger-screen/ledger-screen.tsx create mode 100644 apps/demo-wallet/src/features/ledger/index.ts create mode 100644 apps/demo-wallet/src/features/wallet-setup/components/add-wallet-modal/add-wallet-modal.tsx create mode 100644 apps/demo-wallet/src/features/wallet-setup/components/add-wallet-modal/index.ts create mode 100644 apps/demo-wallet/src/features/wallet-setup/components/create-wallet-modal/create-wallet-modal.tsx create mode 100644 apps/demo-wallet/src/features/wallet-setup/components/create-wallet-modal/index.ts create mode 100644 apps/demo-wallet/src/features/wallet-setup/components/create-wallet-screen/create-wallet-screen.tsx create mode 100644 apps/demo-wallet/src/features/wallet-setup/components/create-wallet-screen/index.ts create mode 100644 apps/demo-wallet/src/features/wallet-setup/components/import-wallet-screen/import-wallet-screen.tsx create mode 100644 apps/demo-wallet/src/features/wallet-setup/components/import-wallet-screen/index.ts create mode 100644 apps/demo-wallet/src/features/wallet-setup/components/welcome-screen/index.ts create mode 100644 apps/demo-wallet/src/features/wallet-setup/components/welcome-screen/welcome-screen.tsx create mode 100644 apps/demo-wallet/src/features/wallet-setup/index.ts create mode 100644 apps/demo-wallet/src/features/wallet-setup/routes.ts create mode 100644 apps/demo-wallet/src/hooks/useCountUp.ts create mode 100644 apps/demo-wallet/src/hooks/useMediaQuery.ts create mode 100644 apps/demo-wallet/src/hooks/useReceivedToasts.tsx delete mode 100644 apps/demo-wallet/src/pages/SetupPassword.tsx delete mode 100644 apps/demo-wallet/src/pages/SetupWallet.tsx delete mode 100644 apps/demo-wallet/src/pages/UnlockWallet.tsx create mode 100644 apps/demo-wallet/src/utils/format.ts create mode 100644 apps/demo-wallet/src/utils/rates.ts create mode 100644 apps/demo-wallet/src/utils/telegram.ts create mode 100644 demo/wallet-core/src/store/slices/ratesSlice.ts create mode 100644 packages/appkit-react/src/components/ui/fallback-image/fallback-image.tsx create mode 100644 packages/appkit-react/src/components/ui/fallback-image/index.ts create mode 100644 packages/appkit-react/src/components/ui/fallback-image/use-resolved-image-src.ts create mode 100644 packages/walletkit/src/clients/toncenter/mappers/map-address-book.ts create mode 100644 packages/walletkit/src/clients/toncenter/mappers/map-jetton-masters.ts diff --git a/apps/demo-wallet/package.json b/apps/demo-wallet/package.json index 9f47952c9..b90d6bf72 100644 --- a/apps/demo-wallet/package.json +++ b/apps/demo-wallet/package.json @@ -24,10 +24,15 @@ "dependencies": { "@demo/v4ledger-adapter": "workspace:*", "@demo/wallet-core": "workspace:*", + "@fontsource-variable/inter": "^5.2.8", "@ledgerhq/hw-transport-webhid": "6.34.0", "@ledgerhq/hw-transport-webusb": "6.33.0", + "@radix-ui/react-dialog": "1.1.15", + "@radix-ui/react-popover": "1.1.15", + "@radix-ui/react-select": "2.2.6", "@scure/bip39": "^2.2.0", "@tailwindcss/vite": "^4.3.0", + "@telegram-apps/sdk": "^3.11.8", "@ton/core": "catalog:", "@ton/crypto": "catalog:", "@ton/walletkit": "workspace:*", @@ -41,6 +46,7 @@ "immer": "^10.2.0", "lucide-react": "^0.562.0", "next-themes": "^0.4.6", + "qr-code-styling": "^1.9.2", "react": "catalog:", "react-dom": "catalog:", "react-router-dom": "^7.15.1", @@ -49,6 +55,7 @@ "tailwindcss": "^4.3.0", "tailwindcss-animate": "^1.0.7", "tw-animate-css": "^1.4.0", + "vaul": "^1.1.2", "zustand": "^5.0.13" }, "devDependencies": { diff --git a/apps/demo-wallet/src/App.css b/apps/demo-wallet/src/App.css index f611305f8..1d8be7bdb 100644 --- a/apps/demo-wallet/src/App.css +++ b/apps/demo-wallet/src/App.css @@ -5,6 +5,20 @@ @custom-variant dark (&:is(.dark *)); +@theme { + --font-sans: 'Inter Variable', system-ui, Avenir, Helvetica, Arial, sans-serif; + --font-display: 'Inter Display', 'Inter Variable', system-ui, sans-serif; +} + +@font-face { + font-family: 'Inter Display'; + font-style: normal; + font-display: swap; + font-weight: 100 900; + src: url('@fontsource-variable/inter/files/inter-latin-opsz-normal.woff2') format('woff2-variations'); + font-variation-settings: 'opsz' 32; +} + #root { width: 100%; } @@ -159,4 +173,11 @@ body { @apply bg-background text-foreground; } + button:not(:disabled), + [role='button'], + a, + summary, + label[for] { + cursor: pointer; + } } diff --git a/apps/demo-wallet/src/App.tsx b/apps/demo-wallet/src/App.tsx index c795d41ba..da4cde225 100644 --- a/apps/demo-wallet/src/App.tsx +++ b/apps/demo-wallet/src/App.tsx @@ -12,7 +12,7 @@ import type { WalletKitConfig } from '@demo/wallet-core'; import { AppRouter } from './components'; -import { Toaster } from '@/components/ui/sonner'; +import { Toaster } from '@/core/components/ui/sonner'; import { DISABLE_AUTO_EMULATION, DISABLE_HTTP_BRIDGE, diff --git a/apps/demo-wallet/src/components/ActionPreviewList.tsx b/apps/demo-wallet/src/components/ActionPreviewList.tsx index 586d002e1..467dc7ad5 100644 --- a/apps/demo-wallet/src/components/ActionPreviewList.tsx +++ b/apps/demo-wallet/src/components/ActionPreviewList.tsx @@ -10,6 +10,8 @@ import React, { memo, useMemo } from 'react'; import type { ToncenterEmulationResponse } from '@ton/walletkit'; import { emulationEvent } from '@ton/walletkit'; +import { shortenAddress } from '@/utils'; + interface ActionPreviewListProps { emulationResult: ToncenterEmulationResponse; walletAddress?: string; @@ -77,7 +79,7 @@ export const ActionPreviewList: React.FC = memo( key={`acc-${i}`} className="text-[10px] px-2 py-0.5 bg-gray-100 text-gray-700 rounded" > - {acc.name ?? shortenAddress(acc.address)} + {acc.name ?? shortenAddress(acc.address, 6)} ))} @@ -91,9 +93,3 @@ export const ActionPreviewList: React.FC = memo( ); }, ); - -function shortenAddress(addr?: string): string { - if (!addr) return ''; - const a = String(addr); - return a.length <= 12 ? a : `${a.slice(0, 6)}...${a.slice(-6)}`; -} diff --git a/apps/demo-wallet/src/components/AppRouter.tsx b/apps/demo-wallet/src/components/AppRouter.tsx index 57020400a..2ac15555c 100644 --- a/apps/demo-wallet/src/components/AppRouter.tsx +++ b/apps/demo-wallet/src/components/AppRouter.tsx @@ -13,9 +13,6 @@ import { useWalletStore, useWallet } from '@demo/wallet-core'; import { ProtectedRoute } from './ProtectedRoute'; import { LoaderCircle } from './LoaderCircle'; import { - SetupPassword, - UnlockWallet, - SetupWallet, WalletDashboard, SendTransaction, TracePage, @@ -25,7 +22,11 @@ import { TonConnectRoute, } from '../pages'; +import { SetupPasswordScreen, UnlockScreen } from '@/features/auth'; +import { LedgerScreen } from '@/features/ledger'; +import { WelcomeScreen, CreateWalletScreen, ImportWalletScreen } from '@/features/wallet-setup'; import { useWalletDataUpdater } from '@/hooks/useWalletDataUpdater'; +import { useReceivedToasts } from '@/hooks/useReceivedToasts'; import { Button } from '@/components/Button'; export const AppRouter: React.FC = () => { @@ -36,11 +37,12 @@ export const AppRouter: React.FC = () => { const { hasWallet } = useWallet(); useWalletDataUpdater(); + useReceivedToasts(); const getInitialRoute = () => { - if (!isPasswordSet) return '/setup-password'; + if (!isPasswordSet) return '/welcome'; if (!isUnlocked) return '/unlock'; - if (!hasWallet) return '/setup-wallet'; + if (!hasWallet) return '/welcome'; return '/wallet'; }; @@ -83,15 +85,32 @@ export const AppRouter: React.FC = () => { {/* Public routes */} - } /> - } /> + } /> + } /> + } /> {/* Protected routes - require authentication */} - + + + } + /> + + + + } + /> + + } /> diff --git a/apps/demo-wallet/src/components/BalanceTotal.tsx b/apps/demo-wallet/src/components/BalanceTotal.tsx new file mode 100644 index 000000000..8708f8ea8 --- /dev/null +++ b/apps/demo-wallet/src/components/BalanceTotal.tsx @@ -0,0 +1,87 @@ +/** + * Copyright (c) TonTech. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ + +import React, { useCallback, useMemo } from 'react'; +import { Copy } from 'lucide-react'; +import { toast } from 'sonner'; +import { useWallet, useJettons, useRates } from '@demo/wallet-core'; + +import { useCountUp } from '@/hooks/useCountUp'; +import { findRate, formatUsdParts, shortenAddress, toDecimal } from '@/utils'; + +const TON_DECIMALS = 9; + +export const BalanceTotal: React.FC = () => { + const { address, balance } = useWallet(); + const { userJettons } = useJettons(); + const { entries: rates, lastUpdated: ratesUpdated } = useRates(); + + // Wait for both balance and real rates (not the bootstrap TON rate) before showing the total. + const ready = balance !== undefined && ratesUpdated > 0; + + const totalUsd = useMemo(() => { + if (!ready) return 0; + + let total = 0; + const tonRate = rates['TON']?.rate; + if (tonRate) { + total += toDecimal(balance, TON_DECIMALS) * tonRate; + } + for (const jetton of userJettons) { + const rate = findRate(rates, jetton.address)?.rate; + if (!rate) continue; + total += toDecimal(jetton.balance, jetton.decimalsNumber ?? 9) * rate; + } + return total; + }, [ready, rates, balance, userJettons]); + + const handleCopy = useCallback(async () => { + if (!address) return; + try { + await navigator.clipboard.writeText(address); + toast.success('Address copied'); + } catch { + toast.error('Failed to copy address'); + } + }, [address]); + + const animatedTotal = useCountUp(totalUsd); + const { intPart, fracPart } = formatUsdParts(animatedTotal); + + return ( +
+ {ready ? ( +
+ $ + {intPart} + . + {fracPart} +
+ ) : ( +
+ )} + + {address ? ( + + ) : ( +
+ )} +
+ ); +}; diff --git a/apps/demo-wallet/src/components/Button.tsx b/apps/demo-wallet/src/components/Button.tsx index 98e8ffe3b..3b9ac21c8 100644 --- a/apps/demo-wallet/src/components/Button.tsx +++ b/apps/demo-wallet/src/components/Button.tsx @@ -27,7 +27,7 @@ export const Button: React.FC = ({ ...props }) => { const baseClasses = - 'font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center'; + 'font-medium rounded-lg transition-[transform,background-color,color] hover:scale-[1.03] active:scale-[0.97] disabled:hover:scale-100 disabled:active:scale-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center'; const variantClasses = { primary: 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500', diff --git a/apps/demo-wallet/src/components/ConnectDappModal.tsx b/apps/demo-wallet/src/components/ConnectDappModal.tsx new file mode 100644 index 000000000..878b07f68 --- /dev/null +++ b/apps/demo-wallet/src/components/ConnectDappModal.tsx @@ -0,0 +1,73 @@ +/** + * Copyright (c) TonTech. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ + +import React, { useCallback, useState } from 'react'; +import { useTonConnect } from '@demo/wallet-core'; + +import { Button } from './Button'; + +import { Modal } from '@/core/components/ui/modal'; + +interface ConnectDappModalProps { + isOpen: boolean; + onClose: () => void; +} + +export const ConnectDappModal: React.FC = ({ isOpen, onClose }) => { + const { handleTonConnectUrl } = useTonConnect(); + const [url, setUrl] = useState(''); + const [isConnecting, setIsConnecting] = useState(false); + + const handleConnect = useCallback(async () => { + const trimmed = url.trim(); + if (!trimmed) return; + + setIsConnecting(true); + try { + await handleTonConnectUrl(trimmed); + setUrl(''); + onClose(); + } catch { + // connect modal / error state handled by the store + } finally { + setIsConnecting(false); + } + }, [url, handleTonConnectUrl, onClose]); + + return ( + !open && onClose()} className="px-2"> + + Connect to dApp + + + + +