Skip to content

Commit

Permalink
refactor(solid): combine into one file
Browse files Browse the repository at this point in the history
  • Loading branch information
drichar committed Jun 19, 2024
1 parent 527f48d commit 56f7528
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 208 deletions.
31 changes: 0 additions & 31 deletions packages/use-wallet-solid/src/WalletProvider.tsx

This file was deleted.

53 changes: 0 additions & 53 deletions packages/use-wallet-solid/src/__tests__/WalletProvider.test.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ import {
type WalletAccount
} from '@txnlab/use-wallet'
import { For, Show, createSignal } from 'solid-js'
import { Wallet, useWallet } from '../useWallet'
import { WalletProvider } from '../WalletProvider'
import { Wallet, WalletProvider, useWallet, useWalletManager } from '../index'
import algosdk from 'algosdk'

const mocks = vi.hoisted(() => {
Expand Down Expand Up @@ -541,3 +540,53 @@ describe('useWallet', () => {
expect(screen.getByTestId('active-network')).toHaveTextContent(NetworkId.MAINNET)
})
})

describe('WalletProvider', () => {
it('provides the WalletManager to its children', () => {
const TestComponent = () => {
const manager = useWalletManager()
return <h1>{manager ? 'Manager provided' : 'No manager'}</h1>
}

const walletManager = new WalletManager({
wallets: [WalletId.DEFLY]
})

render(() => (
<WalletProvider manager={walletManager}>
<TestComponent />
</WalletProvider>
))

expect(screen.getByText('Manager provided')).toBeInTheDocument()
})

it('throws an error when useWalletManager is used outside of WalletProvider', () => {
const TestComponent = () => {
try {
useWalletManager()
return <div>No error thrown</div>
} catch (error: any) {
return <div>{error.message}</div>
}
}

render(() => <TestComponent />)
expect(
screen.getByText('useWalletManager must be used within a WalletProvider')
).toBeInTheDocument()
})

it('calls resumeSessions on mount', async () => {
const mockResumeSessions = vi.fn()
const fakeManager = { resumeSessions: mockResumeSessions }

render(() => (
<WalletProvider manager={fakeManager as any as WalletManager}>
<div />
</WalletProvider>
))

expect(mockResumeSessions).toHaveBeenCalled()
})
})
152 changes: 150 additions & 2 deletions packages/use-wallet-solid/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,151 @@
import { useStore } from '@tanstack/solid-store'
import algosdk from 'algosdk'
import { JSX, createContext, createMemo, createSignal, onMount, useContext } from 'solid-js'
import type {
NetworkId,
WalletAccount,
WalletId,
WalletManager,
WalletMetadata,
WalletState
} from '@txnlab/use-wallet'

export * from '@txnlab/use-wallet'
export { WalletProvider } from './WalletProvider'
export { useWallet } from './useWallet'

interface WalletProviderProps {
manager: WalletManager
children: JSX.Element
}

const WalletContext = createContext<() => WalletManager>()

export const WalletProvider = (props: WalletProviderProps) => {
const store = () => props.manager

onMount(async () => {
try {
await props.manager.resumeSessions()
} catch (error) {
console.error('Error resuming sessions:', error)
}
})

return <WalletContext.Provider value={store}>{props.children}</WalletContext.Provider>
}

export const useWalletManager = (): WalletManager => {
const manager = useContext(WalletContext)
if (!manager) {
throw new Error('useWalletManager must be used within a WalletProvider')
}
return manager()
}

export interface Wallet {
id: () => string
metadata: () => WalletMetadata
accounts: () => WalletAccount[]
activeAccount: () => WalletAccount | null
isConnected: () => boolean
isActive: () => boolean
connect: (args?: Record<string, any>) => Promise<WalletAccount[]>
disconnect: () => Promise<void>
setActive: () => void
setActiveAccount: (address: string) => void
}

export function useWallet() {
const manager = createMemo(() => useWalletManager())

const [algodClient, setAlgodClient] = createSignal<algosdk.Algodv2>(manager().algodClient)

const walletStore = useStore(manager().store, (state) => state.wallets)

const walletState = (walletId: WalletId): WalletState | null => walletStore()[walletId] || null

const activeWalletId = useStore(manager().store, (state) => state.activeWallet)

const activeWallet = () => manager().getWallet(activeWalletId() as WalletId) || null

const activeWalletState = () => walletState(activeWalletId() as WalletId)

const activeWalletAccounts = () => activeWalletState()?.accounts ?? null

const activeWalletAddresses = () =>
activeWalletAccounts()?.map((account) => account.address) ?? null

const activeAccount = () => activeWalletState()?.activeAccount ?? null

const activeAddress = () => activeAccount()?.address ?? null

const isWalletActive = (walletId: WalletId) => walletId === activeWalletId()
const isWalletConnected = (walletId: WalletId) =>
!!walletState(walletId)?.accounts.length || false

const activeNetwork = useStore(manager().store, (state) => state.activeNetwork)

const setActiveNetwork = async (networkId: NetworkId): Promise<void> => {
if (activeNetwork() === networkId) {
return
}
// Disconnect any connected wallets
await manager().disconnect()

console.info(`[Solid] Creating Algodv2 client for ${networkId}...`)

const { token, baseServer, port, headers } = manager().networkConfig[networkId]
const newClient = new algosdk.Algodv2(token, baseServer, port, headers)
setAlgodClient(newClient)

manager().algodClient = newClient

manager().store.setState((state) => ({
...state,
activeNetwork: networkId
}))

console.info(`[Solid] ✅ Active network set to ${networkId}.`)
}

const signTransactions = <T extends algosdk.Transaction[] | Uint8Array[]>(
txnGroup: T | T[],
indexesToSign?: number[]
): Promise<Uint8Array[]> => {
const wallet = activeWallet()
if (!wallet) {
throw new Error('No active wallet')
}
return wallet.signTransactions(txnGroup, indexesToSign)
}

const transactionSigner = (
txnGroup: algosdk.Transaction[],
indexesToSign: number[]
): Promise<Uint8Array[]> => {
const wallet = activeWallet()
if (!wallet) {
throw new Error('No active wallet')
}
return wallet.transactionSigner(txnGroup, indexesToSign)
}

return {
activeWalletId,
walletStore,
algodClient,
activeNetwork,
activeWallet,
activeWalletAccounts,
activeWalletAddresses,
activeWalletState,
activeAccount,
activeAddress,
isWalletActive,
isWalletConnected,
setActiveNetwork,
setAlgodClient,
signTransactions,
transactionSigner,
wallets: manager().wallets
}
}
Loading

0 comments on commit 56f7528

Please sign in to comment.