Skip to content

Commit ba34d7b

Browse files
authored
Connect wallet on localnet (#85)
* support multiple account view in a wallet * add mnemonic support, fix icons in localnet
1 parent 252e734 commit ba34d7b

File tree

9 files changed

+255
-102
lines changed

9 files changed

+255
-102
lines changed

package-lock.json

Lines changed: 38 additions & 32 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@
2929
"@perawallet/connect": "^1.3.4",
3030
"@radix-ui/react-dialog": "^1.0.5",
3131
"@radix-ui/react-dropdown-menu": "^2.0.6",
32-
"@radix-ui/react-hover-card": "^1.0.7",
3332
"@radix-ui/react-icons": "^1.3.0",
3433
"@radix-ui/react-label": "^2.0.2",
3534
"@radix-ui/react-navigation-menu": "^1.1.4",
35+
"@radix-ui/react-popover": "^1.0.7",
3636
"@radix-ui/react-select": "^2.0.0",
3737
"@radix-ui/react-slot": "^1.0.2",
3838
"@radix-ui/react-tabs": "^1.0.4",

src/features/common/components/hover-card.tsx

Lines changed: 0 additions & 27 deletions
This file was deleted.

src/features/common/components/platform-provider.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export function PlatformProvider({ children }: PropsWithChildren) {
2222
clientStatic: LuteConnect,
2323
clientOptions: { siteName: 'Algorand Studio' },
2424
},
25+
PROVIDER_ID.MNEMONIC,
2526
],
2627
nodeConfig: {
2728
network: networkConfig.id,
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import * as React from 'react'
2+
import * as PopoverPrimitive from '@radix-ui/react-popover'
3+
4+
import { cn } from '@/features/common/utils'
5+
6+
const Popover = PopoverPrimitive.Root
7+
8+
const PopoverTrigger = PopoverPrimitive.Trigger
9+
10+
const PopoverContent = React.forwardRef<
11+
React.ElementRef<typeof PopoverPrimitive.Content>,
12+
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
13+
>(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
14+
<PopoverPrimitive.Portal>
15+
<PopoverPrimitive.Content
16+
ref={ref}
17+
align={align}
18+
sideOffset={sideOffset}
19+
className={cn(
20+
'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
21+
className
22+
)}
23+
{...props}
24+
/>
25+
</PopoverPrimitive.Portal>
26+
))
27+
PopoverContent.displayName = PopoverPrimitive.Content.displayName
28+
29+
export { Popover, PopoverTrigger, PopoverContent }

src/features/layout/pages/layout-page.test.tsx

Lines changed: 86 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { executeComponentTest } from '@/tests/test-component'
2-
import { render, waitFor } from '@/tests/testing-library'
2+
import { fireEvent, render, waitFor } from '@/tests/testing-library'
33
import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'
44
import { LayoutPage } from '@/features/layout/pages/layout-page'
5-
import { connectWalletLabel } from '@/features/wallet/components/connect-wallet-button'
6-
import { useWallet } from '@txnlab/use-wallet'
5+
import { connectWalletLabel, selectAccountLabel, disconnectWalletLabel } from '@/features/wallet/components/connect-wallet-button'
6+
import { PROVIDER_ID, Provider, useWallet } from '@txnlab/use-wallet'
77
import { Event as TauriEvent, listen } from '@tauri-apps/api/event'
88
import { networkConfigAtom, settingsStore } from '@/features/settings/data'
99
import { useNavigate } from 'react-router-dom'
@@ -61,15 +61,94 @@ describe('when rendering the layout page', () => {
6161

6262
const walletAddressText = component.getByText('CGRS...LQ5Q')
6363
expect(walletAddressText).toBeTruthy()
64-
65-
const linkElement = component.getByRole('link', { name: /CGRS...LQ5Q/i })
66-
expect(linkElement.getAttribute('href')).toBe('/explore/account/CGRSYAYF2M5HNH6KYY6RPLYANVZ5ZQO4OTC3M3YPI4D6JFBXZGRUSVLQ5Q')
6764
})
6865
}
6966
)
7067
})
71-
})
68+
describe('and there is more than one account', () => {
69+
it('the account switcher should be shown', async () => {
70+
const original = await vi.importActual<{ useWallet: () => ReturnType<typeof useWallet> }>('@txnlab/use-wallet')
71+
vi.mocked(useWallet).mockImplementation(() => {
72+
return {
73+
...original.useWallet(),
74+
activeAddress: 'CGRSYAYF2M5HNH6KYY6RPLYANVZ5ZQO4OTC3M3YPI4D6JFBXZGRUSVLQ5Q',
75+
status: 'active',
76+
isActive: true,
77+
isReady: true,
78+
connectedActiveAccounts: [
79+
{
80+
providerId: PROVIDER_ID.PERA,
81+
address: 'CGRSYAYF2M5HNH6KYY6RPLYANVZ5ZQO4OTC3M3YPI4D6JFBXZGRUSVLQ5Q',
82+
name: 'Account 1',
83+
},
84+
{
85+
providerId: PROVIDER_ID.PERA,
86+
address: 'SOMEOTHERADDRESS',
87+
name: 'Account 2',
88+
},
89+
],
90+
}
91+
})
92+
93+
await executeComponentTest(
94+
() => render(<LayoutPage />, undefined),
95+
async (component) => {
96+
await waitFor(async () => {
97+
const selectAccountTrigger = component.getByTitle('CGRSYAYF2M5HNH6KYY6RPLYANVZ5ZQO4OTC3M3YPI4D6JFBXZGRUSVLQ5Q')
98+
expect(selectAccountTrigger).toBeTruthy()
99+
fireEvent.click(selectAccountTrigger)
100+
101+
const selectElement = component.getByLabelText(selectAccountLabel)
102+
expect(selectElement).toBeTruthy()
103+
})
104+
}
105+
)
106+
})
107+
})
108+
109+
describe('and the user disconnects the wallet', () => {
110+
it('the wallet should be disconnected', async () => {
111+
const original = await vi.importActual<{ useWallet: () => ReturnType<typeof useWallet> }>('@txnlab/use-wallet')
112+
const disconnect = vi.fn()
113+
vi.mocked(useWallet).mockImplementation(() => {
114+
return {
115+
...original.useWallet(),
116+
activeAddress: 'CGRSYAYF2M5HNH6KYY6RPLYANVZ5ZQO4OTC3M3YPI4D6JFBXZGRUSVLQ5Q',
117+
status: 'active',
118+
isActive: true,
119+
isReady: true,
120+
providers: [
121+
{
122+
disconnect,
123+
isActive: true,
124+
metadata: {
125+
id: PROVIDER_ID.PERA,
126+
name: 'Pera',
127+
icon: 'someicon.png',
128+
isWalletConnect: true,
129+
},
130+
} as unknown as Provider,
131+
],
132+
}
133+
})
134+
await executeComponentTest(
135+
() => render(<LayoutPage />, undefined),
136+
async (component) => {
137+
await waitFor(async () => {
138+
const selectAccountTrigger = component.getByTitle('CGRSYAYF2M5HNH6KYY6RPLYANVZ5ZQO4OTC3M3YPI4D6JFBXZGRUSVLQ5Q')
139+
expect(selectAccountTrigger).toBeTruthy()
140+
fireEvent.click(selectAccountTrigger)
72141

142+
const disconnectButton = component.getByLabelText(disconnectWalletLabel)
143+
expect(disconnectButton).toBeTruthy()
144+
fireEvent.click(disconnectButton)
145+
expect(disconnect).toHaveBeenCalled()
146+
})
147+
}
148+
)
149+
})
150+
})
151+
})
73152
describe('and the user opens a deep link to mainnet', () => {
74153
beforeAll(() => {
75154
window.__TAURI__ = {}

src/features/settings/data/network.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export const testnetConfig: NetworkConfig = {
4545
},
4646
walletProviders: mainnetConfig.walletProviders,
4747
}
48-
const localnetConfig: NetworkConfig = {
48+
export const localnetConfig: NetworkConfig = {
4949
id: 'localnet',
5050
name: 'LocalNet',
5151
indexer: {
@@ -58,7 +58,7 @@ const localnetConfig: NetworkConfig = {
5858
port: 4001,
5959
token: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
6060
},
61-
walletProviders: [],
61+
walletProviders: [PROVIDER_ID.KMD, PROVIDER_ID.MNEMONIC],
6262
}
6363

6464
export const networksConfigs = [mainnetConfig, testnetConfig, localnetConfig]

0 commit comments

Comments
 (0)