import React, { useMemo } from 'react' import _ from 'lodash' import Fuse from 'fuse.js' import { useAccount } from 'wagmi' import { type Address } from 'viem' import { useTranslations } from 'next-intl' import { type Chain } from '@/utils/types' import { useTransactionsState } from '@/slices/transactions/hooks' import { usePortfolioState } from '@/slices/portfolio/hooks' import { BridgeTransaction } from '@/slices/api/generated' import { CHAINS_BY_ID } from '@/constants/chains' import { tokenAddressToToken } from '@/constants/tokens' import { TransactionsState } from '@/slices/transactions/reducer' import { PortfolioState } from '@/slices/portfolio/reducer' import { Transaction, TransactionType } from './Transaction/Transaction' import { UserExplorerLink } from './Transaction/components/TransactionExplorerLink' import { NoSearchResultsContent } from '../Portfolio/components/NoSearchResultContent' import { checkTransactionsExist } from '@/utils/checkTransactionsExist' import { useWalletState } from '@/slices/wallet/hooks' export const Activity = ({ visibility }: { visibility: boolean }) => { const { address } = useAccount() const { userHistoricalTransactions, isUserHistoricalTransactionsLoading, }: TransactionsState = useTransactionsState() const { isWalletPending } = useWalletState() const { searchInput, searchedBalances }: PortfolioState = usePortfolioState() const isLoading: boolean = isUserHistoricalTransactionsLoading const isSearchInputActive = Boolean(searchInput.length > 0) const isMasqueradeActive = Object.keys(searchedBalances).length > 0 const masqueradeAddress = Object.keys(searchedBalances)[0] as Address const filteredHistoricalTransactions = filterTransactionsBySearch( userHistoricalTransactions, isLoading, searchInput, isSearchInputActive, masqueradeAddress ) const hasHistoricalTransactions = !_.isEmpty(userHistoricalTransactions) const hasFilteredSearchResults = !_.isEmpty(filteredHistoricalTransactions) const viewingAddress: string | null = useMemo(() => { if (isMasqueradeActive) { return masqueradeAddress } else if (address) { return address } else return null }, [isMasqueradeActive, masqueradeAddress, address]) const t = useTranslations('Activity') return (
{!viewingAddress && (
{t('Your pending and recent transactions will appear here')}
)} {viewingAddress && isLoading && (
{t('Loading activity')}...
)} {viewingAddress && !isLoading && !hasHistoricalTransactions && (
{t('No transactions in last 30 days')}
)} {viewingAddress && !isLoading && hasHistoricalTransactions && ( {userHistoricalTransactions && filteredHistoricalTransactions .slice(0, isSearchInputActive ? 100 : 6) .map((transaction: BridgeTransaction) => renderTransaction(transaction, address, isWalletPending) )} {isSearchInputActive && !hasFilteredSearchResults && ( )} )}
) } const renderTransaction = ( transaction: BridgeTransaction, viewingAddress: Address, disabled: boolean ) => { return ( ) } const filterTransactionsBySearch = ( transactions: BridgeTransaction[], isLoading: boolean, searchInput: string, isSearchActive: boolean, masqueradeAddress: string ) => { let searchFiltered = [] const fuseOptions = { includeScore: true, threshold: 0.33, distance: 20, keys: [ 'originChain.name', 'originToken.symbol', 'destinationChain.name', 'destinationToken.symbol', 'originTokenAddresses', 'destinationTokenAddresses', 'fromInfo.txnHash', 'toInfo.txnHash', ], } if (!isLoading && checkTransactionsExist(transactions)) { const formatted = transactions.map((transaction) => { const originToken = tokenAddressToToken( transaction?.fromInfo?.chainID, transaction?.fromInfo?.tokenAddress ) const destinationToken = tokenAddressToToken( transaction?.toInfo?.chainID, transaction?.toInfo?.tokenAddress ) return { ...transaction, originChain: CHAINS_BY_ID[transaction?.fromInfo?.chainID] as Chain, originToken: originToken, originTokenAddresses: originToken && Object.values(originToken?.addresses), destinationChain: CHAINS_BY_ID[transaction?.toInfo?.chainID] as Chain, destinationToken: destinationToken, destinationTokenAddresses: destinationToken && Object.values(destinationToken?.addresses), } }) const fuse = new Fuse(formatted, fuseOptions) if (isSearchActive) { searchFiltered = fuse.search(searchInput).map((i) => i.item) } const inputIsMasqueradeAddress = searchInput === masqueradeAddress return isSearchActive && !inputIsMasqueradeAddress ? searchFiltered : transactions } return searchFiltered } export const ActivitySection = ({ title, children, twClassName, }: { title: string children?: React.ReactNode twClassName?: string }) => { return (

{title}

{children}
) }