import { useState, createContext, useEffect } from 'react'; import type { InjectedAccountWithMeta, InjectedExtension } from '@polkadot/extension-inject/types'; import { web3Accounts, web3Enable } from '@polkadot/extension-dapp'; import isLoggedIn from 'utils'; import { useApi } from 'hooks'; import { Account } from 'types'; import { GearKeyring } from '@gear-js/api'; import { Balance } from '@polkadot/types/interfaces'; import { UnsubscribePromise } from '@polkadot/api/types'; import Props from './types'; type Value = { accounts: InjectedAccountWithMeta[] | undefined; account: Account | undefined; switchAccount: (account: InjectedAccountWithMeta) => void; logout: () => void; }; const AccountContext = createContext({} as Value); function AccountProvider({ children }: Props) { const { api } = useApi(); const [accounts, setAccounts] = useState<InjectedAccountWithMeta[]>(); const [account, setAccount] = useState<Account>(); const getAccounts = (extensions: InjectedExtension[]) => (extensions.length > 0 ? web3Accounts() : undefined); useEffect(() => { setTimeout(() => { web3Enable('Gear App').then(getAccounts).then(setAccounts); }, 300); }, []); const getBalance = (balance: Balance) => { const [value, unit] = balance.toHuman().split(' '); return { value, unit }; }; const getAccount = (_account: InjectedAccountWithMeta, balance: Balance) => ({ ..._account, balance: getBalance(balance), decodedAddress: GearKeyring.decodeAddress(_account.address), }); const switchAccount = (_account: InjectedAccountWithMeta) => { api?.balance .findOut(_account.address) .then((balance) => getAccount(_account, balance)) .then(setAccount); }; const logout = () => { setAccount(undefined); }; useEffect(() => { const loggedInAccount = accounts?.find(isLoggedIn); if (loggedInAccount) switchAccount(loggedInAccount); // eslint-disable-next-line react-hooks/exhaustive-deps }, [api, accounts]); const updateBalance = (balance: Balance) => { setAccount((prevAccount) => ({ ...prevAccount!, balance: getBalance(balance) })); }; useEffect(() => { let unsub: UnsubscribePromise | undefined; if (account) { unsub = api?.gearEvents.subscribeToBalanceChange(account.address, updateBalance); } return () => { if (unsub) unsub.then((callback) => callback()); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [api, account]); const { Provider } = AccountContext; const value = { accounts, account, switchAccount, logout }; return <Provider value={value}>{children}</Provider>; } export { AccountContext, AccountProvider };