From d55b3c70c727bfb531e9e03d64870b16dd0687b3 Mon Sep 17 00:00:00 2001 From: BenRey Date: Wed, 6 Nov 2024 00:41:10 +0100 Subject: [PATCH] Refactor ConnectMassaWallet component and account store for improved state management and wallet handling --- .../components/ConnectMassaWallet.tsx | 94 +++------ .../ConnectMassaWallets/store/accountStore.ts | 195 ++++++++---------- src/lib/ConnectMassaWallets/store/index.ts | 6 +- 3 files changed, 120 insertions(+), 175 deletions(-) diff --git a/src/lib/ConnectMassaWallets/components/ConnectMassaWallet.tsx b/src/lib/ConnectMassaWallets/components/ConnectMassaWallet.tsx index ae79c40b..eb608842 100644 --- a/src/lib/ConnectMassaWallets/components/ConnectMassaWallet.tsx +++ b/src/lib/ConnectMassaWallets/components/ConnectMassaWallet.tsx @@ -1,9 +1,3 @@ -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore -import React from 'react'; - -import { useEffect, useState } from 'react'; - import { BearbySvg } from './BearbySvg'; import BearbyWallet from './BearbyWallet'; import SelectMassaWallet from './SelectMassaWallet'; @@ -19,19 +13,8 @@ export const ConnectMassaWallet = () => { const { currentWallet, wallets, setCurrentWallet, isFetching } = useAccountStore(); - const [selectedWallet, setSelectedWallet] = useState( - currentWallet?.name(), - ); - - useEffect(() => { - const provider = wallets.find((p) => p.name() === selectedWallet); - if (provider && !currentWallet) { - setCurrentWallet(provider); - } - }, [wallets, selectedWallet, currentWallet, setCurrentWallet]); - function renderWallet() { - switch (selectedWallet) { + switch (currentWallet?.name()) { case WalletName.MassaStation: return ; case WalletName.Bearby: @@ -43,7 +26,7 @@ export const ConnectMassaWallet = () => { } function renderSelectedWallet() { - switch (selectedWallet) { + switch (currentWallet?.name()) { case WalletName.MassaStation: return ( <> @@ -61,54 +44,45 @@ export const ConnectMassaWallet = () => { } } - const noWalletSelected = !selectedWallet || isFetching; - - function renderNoWalletSelected() { + if (!currentWallet) { return ( - { - setSelectedWallet(providerName); - const provider = wallets.find((p) => p.name() === providerName); - if (provider) { - setCurrentWallet(provider); - } - }} - /> +
+ { + const provider = wallets.find((p) => p.name() === providerName); + if (provider) { + await setCurrentWallet(provider); + } + }} + /> +
); } return (
- {noWalletSelected ? ( - renderNoWalletSelected() - ) : ( - <> -
-
- {renderSelectedWallet()} - - {selectedWallet === WalletName.Bearby && ( - - )} -
- { - setSelectedWallet(undefined); - setCurrentWallet(); - }} +
+
+ {renderSelectedWallet()} + + {currentWallet?.name() === WalletName.Bearby && ( + -
- {renderWallet()} - - )} + )} +
+ { + setCurrentWallet(); + }} + /> +
+ + {!isFetching && renderWallet()}
); }; diff --git a/src/lib/ConnectMassaWallets/store/accountStore.ts b/src/lib/ConnectMassaWallets/store/accountStore.ts index b2e4b43a..2dd724bf 100644 --- a/src/lib/ConnectMassaWallets/store/accountStore.ts +++ b/src/lib/ConnectMassaWallets/store/accountStore.ts @@ -1,26 +1,7 @@ -import { Provider } from '@massalabs/massa-web3'; import { create } from 'zustand'; +import { Network, Provider } from '@massalabs/massa-web3'; import { Wallet, WalletName } from '@massalabs/wallet-provider'; -async function handleBearbyAccountChange( - newAddress: string, - store: AccountStoreState, -) { - const { connectedAccount, currentWallet, setConnectedAccount } = store; - - const oldAddress = connectedAccount?.address; - - if (newAddress !== oldAddress) { - const newAccounts = await currentWallet?.accounts(); - - if (newAccounts?.length) { - // Bearby returns only one account - const newAccount = newAccounts[0]; - setConnectedAccount(newAccount); - } - } -} - export interface AccountStoreState { connectedAccount?: Provider; accounts?: Provider[]; @@ -33,14 +14,12 @@ export interface AccountStoreState { networkObserver?: { unsubscribe: () => void; }; - chainId?: bigint; - network?: string; + network?: Network; - setCurrentWallet: (wallet?: Wallet) => void; + setCurrentWallet: (wallet?: Wallet, account?: Provider) => Promise; setWallets: (wallets: Wallet[]) => void; - setConnectedAccount: (account?: Provider) => void; - setCurrentNetwork: () => void; + setCurrentNetwork: (network: Network) => void; } export const useAccountStore = create((set, get) => ({ @@ -51,110 +30,106 @@ export const useAccountStore = create((set, get) => ({ currentWallet: undefined, wallets: [], isFetching: false, - chainId: undefined, network: undefined, - setCurrentWallet: (currentWallet?: Wallet) => { - try { - set({ isFetching: true }); - - const previousWallet = get().currentWallet; - - if (previousWallet?.name() !== currentWallet?.name()) { - get().accountObserver?.unsubscribe(); - get().networkObserver?.unsubscribe(); - set({ accountObserver: undefined, networkObserver: undefined }); - } - if (!currentWallet) { - set({ - currentWallet: undefined, - connectedAccount: undefined, - accounts: undefined, - }); - return; - } + setCurrentWallet: async (wallet?: Wallet, account?: Provider) => { + set({ isFetching: true }); + if (!wallet) { + cleanUpAll(get, set); + return; + } - if (!get().networkObserver) { - const networkObserver = currentWallet.listenNetworkChanges(async () => { - get().setCurrentNetwork(); - }); - set({ networkObserver }); - } + if (get().currentWallet?.name() !== wallet.name()) + cleanupObservers(get, set); - if (currentWallet?.name() === WalletName.Bearby) { - currentWallet - .connect() - .then(() => { - // subscribe to network events - const observer = currentWallet.listenAccountChanges( - (newAddress: string) => { - handleBearbyAccountChange(newAddress, get()); - }, - ); - - set({ currentWallet, accountObserver: observer }); - - // get connected account - currentWallet - .accounts() - .then((accounts) => { - // bearby expose only 1 account - get().setConnectedAccount(accounts[0]); - set({ accounts }); - }) - .catch((error) => { - console.warn('error getting accounts from bearby', error); - }); - }) - .catch((error) => { - console.warn('error connecting to bearby', error); - }); + if (wallet.name() === WalletName.Bearby) { + try { + await setupBearbyWallet(wallet, set, get); + } catch (error) { return; } + } - set({ currentWallet }); - - get().setCurrentNetwork(); + if (!get().networkObserver) { + const networkObserver = wallet.listenNetworkChanges(async () => { + get().setCurrentNetwork(await wallet.networkInfos()); + }); + set({ networkObserver }); + } - currentWallet - .accounts() - .then((accounts) => { - set({ accounts }); + set({ currentWallet: wallet }); + const network = await wallet.networkInfos(); + get().setCurrentNetwork(network); + const accounts = await wallet.accounts(); + set({ accounts }); + get().setConnectedAccount(account || accounts[0]); - const selectedAccount = accounts[0]; - get().setConnectedAccount(selectedAccount); - }) - .catch((error) => { - console.warn('error getting accounts from wallet', error); - }); - } finally { - set({ isFetching: false }); - } + set({ isFetching: false }); }, setWallets: (wallets: Wallet[]) => { set({ wallets }); - - // if current wallet is not in the new list of wallets, unset it if (!wallets.some((p) => p.name() === get().currentWallet?.name())) { - set({ - currentWallet: undefined, - connectedAccount: undefined, - accounts: undefined, - }); + cleanupWallet(set); } }, - // set the connected account, and update the massa client - setConnectedAccount: async (connectedAccount?: Provider) => { + setConnectedAccount: (connectedAccount?: Provider) => { set({ connectedAccount }); }, - setCurrentNetwork: () => { - get() - .currentWallet?.networkInfos() - .then((infos) => { - set({ chainId: infos.chainId, network: infos.name }); - }); + setCurrentNetwork: (network: Network) => { + if (network === get().network) return; + set({ network }); }, })); + +function cleanupObservers( + get: () => AccountStoreState, + set: (partial: Partial) => void, +) { + get().accountObserver?.unsubscribe(); + get().networkObserver?.unsubscribe(); + set({ accountObserver: undefined, networkObserver: undefined }); +} + +function cleanupWallet(set: (partial: Partial) => void) { + set({ + currentWallet: undefined, + connectedAccount: undefined, + accounts: undefined, + }); +} + +function cleanUpAll( + get: () => AccountStoreState, + set: (partial: Partial) => void, +) { + cleanupObservers(get, set); + cleanupWallet(set); + set({ isFetching: false }); +} + +async function setupBearbyWallet( + wallet: Wallet, + set: (partial: Partial) => void, + get: () => AccountStoreState, +) { + if (!wallet.connected) { + await wallet.connect(); + } + + const observer = wallet.listenAccountChanges(async (newAddress: string) => { + const { connectedAccount, currentWallet, setConnectedAccount } = get(); + + if (!currentWallet || !connectedAccount) return; + + if (newAddress !== connectedAccount.address) { + const accounts = await currentWallet.accounts(); + const newAccount = accounts.find((acc) => acc.address === newAddress); + setConnectedAccount(newAccount); + } + }); + + set({ accountObserver: observer }); +} diff --git a/src/lib/ConnectMassaWallets/store/index.ts b/src/lib/ConnectMassaWallets/store/index.ts index ed41d175..5d3aaf93 100644 --- a/src/lib/ConnectMassaWallets/store/index.ts +++ b/src/lib/ConnectMassaWallets/store/index.ts @@ -8,8 +8,4 @@ export async function initAccountStore() { }); } -async function initializeStores() { - await initAccountStore(); -} - -initializeStores(); +await initAccountStore();