import { useSnapshot } from 'valtio'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { ScrollView, View, type StyleProp, type ViewStyle, RefreshControl } from 'react-native'; import { FlexView, Link, ListTransaction, LoadingSpinner, Text, TransactionUtil, useTheme } from '@reown/appkit-ui-react-native'; import { type Transaction, type TransactionImage } from '@reown/appkit-common-react-native'; import { AssetController, AssetUtil, ConnectionsController, ConstantsUtil, EventsController, OptionsController, TransactionsController } from '@reown/appkit-core-react-native'; import { Placeholder } from '../w3m-placeholder'; import { getTransactionListItemProps } from './utils'; import styles from './styles'; interface Props { style?: StyleProp; } export function AccountActivity({ style }: Props) { const Theme = useTheme(); const [refreshing, setRefreshing] = useState(false); const [initialLoad, setInitialLoad] = useState(true); const { loading, transactions, next } = useSnapshot(TransactionsController.state); const { activeNetwork } = useSnapshot(ConnectionsController.state); const { networkImages } = useSnapshot(AssetController.state); const networkImage = AssetUtil.getNetworkImage(activeNetwork, networkImages); const isSupported = activeNetwork?.caipNetworkId && ConstantsUtil.ACTIVITY_SUPPORTED_CHAINS.includes(activeNetwork.caipNetworkId); const handleLoadMore = () => { const address = ConnectionsController.state.activeAddress; if (!address) { return; } TransactionsController.fetchTransactions(address); EventsController.sendEvent({ type: 'track', event: 'LOAD_MORE_TRANSACTIONS', properties: { address, projectId: OptionsController.state.projectId, cursor: TransactionsController.state.next, isSmartAccount: ConnectionsController.state.accountType === 'smartAccount' } }); }; const onRefresh = useCallback(async () => { const address = ConnectionsController.state.activeAddress; if (!address) { return; } setRefreshing(true); await TransactionsController.fetchTransactions(address, true); setRefreshing(false); }, []); const transactionsByYear = useMemo(() => { return TransactionsController.getTransactionsByYearAndMonth(transactions as Transaction[]); }, [transactions]); useEffect(() => { const address = ConnectionsController.state.activeAddress; if (!TransactionsController.state.transactions.length && address && isSupported) { TransactionsController.fetchTransactions(address, true); } // Set initial load to false after first fetch const timer = setTimeout(() => setInitialLoad(false), 100); return () => clearTimeout(timer); }, [isSupported]); // Show loading spinner during initial load or when loading with no transactions if ((initialLoad || loading) && !transactions.length) { return ( ); } if (!isSupported) { return ( ); } // Only show placeholder when we're not in initial load or loading state if (!Object.keys(transactionsByYear).length && !loading && !initialLoad) { return ( ); } return ( } > {Object.keys(transactionsByYear) .reverse() .map(year => ( {Object.keys(transactionsByYear[year] || {}) .reverse() .map(month => ( {TransactionUtil.getTransactionGroupTitle(year, month)} {transactionsByYear[year]?.[month]?.map((transaction: Transaction) => { const { date, type, descriptions, status, images, isAllNFT, transfers } = getTransactionListItemProps(transaction); const hasMultipleTransfers = transfers?.length > 2; // Show only the first transfer if (hasMultipleTransfers) { const description = TransactionUtil.getTransferDescription(transfers[0]); return ( ); } return ( ); })} ))} ))} {(next || loading) && !refreshing ? ( {next && !loading ? ( Load more ) : null} {loading ? : null} ) : null} ); }