import React, { useMemo } from 'react'
import { ActivityIndicator, SectionList, StyleSheet, View } from 'react-native'
import SectionHead from 'src/components/SectionHead'
import GetStarted from 'src/home/GetStarted'
import { useSelector } from 'src/redux/hooks'
import { getFeatureGate } from 'src/statsig'
import { StatsigFeatureGates } from 'src/statsig/types'
import colors from 'src/styles/colors'
import { Spacing } from 'src/styles/styles'
import NoActivity from 'src/transactions/NoActivity'
import EarnFeedItem from 'src/transactions/feed/EarnFeedItem'
import NftFeedItem from 'src/transactions/feed/NftFeedItem'
import SwapFeedItem from 'src/transactions/feed/SwapFeedItem'
import TokenApprovalFeedItem from 'src/transactions/feed/TokenApprovalFeedItem'
import TransferFeedItem from 'src/transactions/feed/TransferFeedItem'
import {
deduplicateTransactions,
useAllowedNetworkIdsForTransfers,
useFetchTransactions,
} from 'src/transactions/feed/queryHelper'
import {
confirmedStandbyTransactionsSelector,
pendingStandbyTransactionsSelector,
} from 'src/transactions/selectors'
import { TokenTransaction, TokenTransactionTypeV2, TransactionStatus } from 'src/transactions/types'
import { groupFeedItemsInSections } from 'src/transactions/utils'
function TransactionFeed() {
const { loading, error, transactions, fetchingMoreTransactions, fetchMoreTransactions } =
useFetchTransactions()
const allPendingStandbyTransactions = useSelector(pendingStandbyTransactionsSelector)
const allConfirmedStandbyTransactions = useSelector(confirmedStandbyTransactionsSelector)
const allowedNetworks = useAllowedNetworkIdsForTransfers()
const showUKCompliantVariant = getFeatureGate(StatsigFeatureGates.SHOW_UK_COMPLIANT_VARIANT)
const confirmedFeedTransactions = useMemo(() => {
// Filter out received pending transactions that are also in the pending
// standby array because those will be displayed with the pending
// transactions
const completedOrNotPendingStandbyTransactions = transactions.filter(
(tx) =>
tx.status === TransactionStatus.Complete ||
!allPendingStandbyTransactions.find(
(pendingStandbyTx) =>
pendingStandbyTx.transactionHash === tx.transactionHash &&
pendingStandbyTx.networkId === tx.networkId
)
)
const allConfirmedTransactions = deduplicateTransactions(
allConfirmedStandbyTransactions,
completedOrNotPendingStandbyTransactions
).sort((a, b) => {
const diff = b.timestamp - a.timestamp
if (diff === 0) {
// if the timestamps are the same, most likely one of the transactions
// is an approval. on the feed we want to show the approval first.
return a.type === TokenTransactionTypeV2.Approval
? 1
: b.type === TokenTransactionTypeV2.Approval
? -1
: 0
}
return diff
})
return allConfirmedTransactions.filter((tx) => {
return allowedNetworks.includes(tx.networkId)
})
}, [
transactions,
allowedNetworks,
allConfirmedStandbyTransactions,
allPendingStandbyTransactions,
])
const pendingTransactions = useMemo(() => {
return allPendingStandbyTransactions.filter((tx) => {
return allowedNetworks.includes(tx.networkId)
})
}, [allPendingStandbyTransactions, allowedNetworks])
const sections = useMemo(() => {
if (confirmedFeedTransactions.length === 0 && pendingTransactions.length === 0) {
return []
}
const confirmedFeedTxHashes = new Set(confirmedFeedTransactions.map((tx) => tx.transactionHash))
return groupFeedItemsInSections(
pendingTransactions.filter((tx) => !confirmedFeedTxHashes.has(tx.transactionHash)),
confirmedFeedTransactions
)
}, [pendingTransactions, confirmedFeedTransactions])
function renderItem({ item: tx }: { item: TokenTransaction; index: number }) {
switch (tx.type) {
case TokenTransactionTypeV2.Exchange:
case TokenTransactionTypeV2.SwapTransaction:
case TokenTransactionTypeV2.CrossChainSwapTransaction:
return
case TokenTransactionTypeV2.Sent:
case TokenTransactionTypeV2.Received:
return
case TokenTransactionTypeV2.NftSent:
case TokenTransactionTypeV2.NftReceived:
return
case TokenTransactionTypeV2.Approval:
return
case TokenTransactionTypeV2.Deposit:
case TokenTransactionTypeV2.Withdraw:
case TokenTransactionTypeV2.ClaimReward:
case TokenTransactionTypeV2.CrossChainDeposit:
// These are handled by the FeedV2 only
return null
case TokenTransactionTypeV2.EarnDeposit:
case TokenTransactionTypeV2.EarnSwapDeposit:
case TokenTransactionTypeV2.EarnWithdraw:
case TokenTransactionTypeV2.EarnClaimReward:
return
}
}
if (!sections.length) {
return !showUKCompliantVariant ? :
}
return (
<>
}
sections={sections}
keyExtractor={(item) => `${item.transactionHash}-${item.timestamp.toString()}`}
keyboardShouldPersistTaps="always"
testID="TransactionList"
onEndReached={() => fetchMoreTransactions()}
/>
{fetchingMoreTransactions && (
)}
>
)
}
const styles = StyleSheet.create({
loadingIcon: {
marginVertical: Spacing.Thick24,
height: 108,
width: 108,
},
centerContainer: {
alignItems: 'center',
justifyContent: 'center',
flex: 1,
},
})
export default TransactionFeed