import { Fragment, useCallback, useEffect } from 'react' import { isAddress } from 'shared/util' import { useRootDispatch, RootDispatch } from 'store' import { getAccounts, upsetAccount } from 'store/accounts.reducer' import { useWalletAddress, useWalletBalance } from 'hooks/useWallet' import { splt } from 'providers/sol.provider' // Watch id let watchId = 0 let prevLamports: number | undefined = undefined const AccountWatcher = () => { const dispatch = useRootDispatch() const walletAddress = useWalletAddress() const lamports = useWalletBalance() // First-time fetching const fetchData = useCallback(async () => { try { if (!isAddress(walletAddress)) return await dispatch(getAccounts({ owner: walletAddress })).unwrap() } catch (er) { return window.notify({ type: 'error', description: 'Cannot fetch data of accounts', }) } }, [dispatch, walletAddress]) // Watch account changes const watchData = useCallback(async () => { if (!isAddress(walletAddress)) return console.warn('Wallet is not connected') if (watchId) return console.warn('Already watched') const filters = [{ memcmp: { bytes: walletAddress, offset: 32 } }] watchId = splt.watch((er: string | null, re: any) => { if (er) return console.error(er) const { address, data } = re return dispatch(upsetAccount({ address, data })) }, filters) }, [dispatch, walletAddress]) // When we close accounts, there a high chance // that the next balance will be greater than the current balance // We use this trick to reload relevant list useEffect(() => { if (typeof prevLamports !== 'undefined' && lamports > prevLamports) { dispatch(getAccounts({ owner: walletAddress })) } prevLamports = lamports }, [dispatch, walletAddress, lamports]) useEffect(() => { fetchData() watchData() // Unwatch (cancel socket) return () => { ;(async () => { try { await splt.unwatch(watchId) } catch (er) { // Do nothing } })() watchId = 0 } }, [fetchData, watchData]) return } export default AccountWatcher