import React, { RefObject, useMemo } from 'react' import { useTranslation } from 'react-i18next' import { StyleSheet, Text, View } from 'react-native' import AppAnalytics from 'src/analytics/AppAnalytics' import { EarnEvents } from 'src/analytics/Events' import { EarnCommonProperties, TokenProperties } from 'src/analytics/Properties' import BottomSheet, { BottomSheetModalRefType } from 'src/components/BottomSheet' import { ActionCard } from 'src/earn/ActionCard' import { BeforeDepositAction } from 'src/earn/types' import { ExternalExchangeProvider } from 'src/fiatExchanges/ExternalExchanges' import { CICOFlow } from 'src/fiatExchanges/types' import EarnCoins from 'src/icons/EarnCoins' import QuickActionsAdd from 'src/icons/quick-actions/Add' import QuickActionsSend from 'src/icons/quick-actions/Send' import SwapAndDeposit from 'src/icons/SwapAndDeposit' import SwapArrows from 'src/icons/SwapArrows' import { navigate } from 'src/navigator/NavigationService' import { Screens } from 'src/navigator/Screens' import { EarnPosition } from 'src/positions/types' import { NETWORK_NAMES } from 'src/shared/conts' import { getFeatureGate } from 'src/statsig' import { StatsigFeatureGates } from 'src/statsig/types' import { typeScale } from 'src/styles/fonts' import { Spacing } from 'src/styles/styles' import { TokenBalance } from 'src/tokens/slice' import { getTokenAnalyticsProps } from 'src/tokens/utils' function AddAction({ token, forwardedRef, analyticsProps, }: { token: TokenBalance forwardedRef: React.RefObject analyticsProps: EarnCommonProperties & TokenProperties }) { const { t } = useTranslation() const action: BeforeDepositAction = { name: 'Add', title: t('earnFlow.beforeDepositBottomSheet.action.add'), details: t('earnFlow.beforeDepositBottomSheet.action.addDescription', { tokenSymbol: token.symbol, tokenNetwork: NETWORK_NAMES[token.networkId], }), iconComponent: QuickActionsAdd, onPress: () => { AppAnalytics.track(EarnEvents.earn_before_deposit_action_press, { action: 'Add', ...analyticsProps, }) navigate(Screens.FiatExchangeAmount, { tokenId: token.tokenId, flow: CICOFlow.CashIn, tokenSymbol: token.symbol, }) forwardedRef.current?.close() }, } return } function AddMoreAction({ token, forwardedRef, analyticsProps, }: { token: TokenBalance forwardedRef: React.RefObject analyticsProps: EarnCommonProperties & TokenProperties }) { const { t } = useTranslation() const action: BeforeDepositAction = { name: 'AddMore', title: t('earnFlow.beforeDepositBottomSheet.action.addMore', { tokenSymbol: token.symbol }), details: t('earnFlow.beforeDepositBottomSheet.action.addDescription', { tokenSymbol: token.symbol, tokenNetwork: NETWORK_NAMES[token.networkId], }), iconComponent: QuickActionsAdd, onPress: () => { AppAnalytics.track(EarnEvents.earn_before_deposit_action_press, { action: 'AddMore', ...analyticsProps, }) navigate(Screens.FiatExchangeAmount, { tokenId: token.tokenId, flow: CICOFlow.CashIn, tokenSymbol: token.symbol, }) forwardedRef.current?.close() }, } return } function TransferAction({ token, exchanges, forwardedRef, analyticsProps, }: { token: TokenBalance exchanges: ExternalExchangeProvider[] forwardedRef: React.RefObject analyticsProps: EarnCommonProperties & TokenProperties }) { const { t } = useTranslation() const action: BeforeDepositAction = { name: 'Transfer', title: t('earnFlow.beforeDepositBottomSheet.action.transfer'), details: t('earnFlow.beforeDepositBottomSheet.action.transferDescription', { tokenSymbol: token.symbol, tokenNetwork: NETWORK_NAMES[token.networkId], }), iconComponent: QuickActionsSend, onPress: () => { AppAnalytics.track(EarnEvents.earn_before_deposit_action_press, { action: 'Transfer', ...analyticsProps, }) navigate(Screens.ExchangeQR, { flow: CICOFlow.CashIn, exchanges }) forwardedRef.current?.close() }, } return } function CrossChainSwapAction({ token, forwardedRef, analyticsProps, }: { token: TokenBalance forwardedRef: React.RefObject analyticsProps: EarnCommonProperties & TokenProperties }) { const { t } = useTranslation() const action: BeforeDepositAction = { name: 'CrossChainSwap', title: t('earnFlow.beforeDepositBottomSheet.action.crossChainSwap'), details: t('earnFlow.beforeDepositBottomSheet.action.crossChainSwapDescription', { tokenSymbol: token.symbol, }), iconComponent: SwapArrows, onPress: () => { AppAnalytics.track(EarnEvents.earn_before_deposit_action_press, { action: 'CrossChainSwap', ...analyticsProps, }) navigate(Screens.SwapScreenWithBack, { toTokenId: token.tokenId }) forwardedRef.current?.close() }, } return } function SwapAction({ token, forwardedRef, analyticsProps, }: { token: TokenBalance forwardedRef: React.RefObject analyticsProps: EarnCommonProperties & TokenProperties }) { const { t } = useTranslation() const action: BeforeDepositAction = { name: 'Swap', title: t('earnFlow.beforeDepositBottomSheet.action.swap'), details: t('earnFlow.beforeDepositBottomSheet.action.swapDescription', { tokenSymbol: token.symbol, tokenNetwork: NETWORK_NAMES[token.networkId], }), iconComponent: SwapArrows, onPress: () => { AppAnalytics.track(EarnEvents.earn_before_deposit_action_press, { action: 'Swap', ...analyticsProps, }) navigate(Screens.SwapScreenWithBack, { toTokenId: token.tokenId }) forwardedRef.current?.close() }, } return } function SwapAndDepositAction({ token, pool, forwardedRef, analyticsProps, allowCrossChainSwapAndDeposit, }: { token: TokenBalance pool: EarnPosition forwardedRef: React.RefObject analyticsProps: EarnCommonProperties & TokenProperties allowCrossChainSwapAndDeposit: boolean }) { const { t } = useTranslation() const action: BeforeDepositAction = { name: 'SwapAndDeposit', title: t('earnFlow.beforeDepositBottomSheet.action.swapAndDeposit'), details: allowCrossChainSwapAndDeposit ? t('earnFlow.beforeDepositBottomSheet.action.swapAndDepositAllTokensDescription') : t('earnFlow.beforeDepositBottomSheet.action.swapAndDepositDescription', { tokenNetwork: NETWORK_NAMES[token.networkId], }), iconComponent: SwapAndDeposit, onPress: () => { AppAnalytics.track(EarnEvents.earn_before_deposit_action_press, { action: 'SwapAndDeposit', ...analyticsProps, }) navigate(Screens.EarnEnterAmount, { pool, mode: 'swap-deposit' }) forwardedRef.current?.close() }, } return } function DepositAction({ token, pool, forwardedRef, analyticsProps, }: { token: TokenBalance pool: EarnPosition forwardedRef: React.RefObject analyticsProps: EarnCommonProperties & TokenProperties }) { const { t } = useTranslation() const action: BeforeDepositAction = { name: 'Deposit', title: t('earnFlow.beforeDepositBottomSheet.action.deposit', { tokenSymbol: token.symbol }), details: t('earnFlow.beforeDepositBottomSheet.action.depositDescription', { amount: token.balance, tokenSymbol: token.symbol, }), iconComponent: EarnCoins, onPress: () => { AppAnalytics.track(EarnEvents.earn_before_deposit_action_press, { action: 'Deposit', ...analyticsProps, }) navigate(Screens.EarnEnterAmount, { pool }) forwardedRef.current?.close() }, } return } export default function BeforeDepositBottomSheet({ forwardedRef, token, pool, hasDepositToken, hasTokensOnSameNetwork, hasTokensOnOtherNetworks, canAdd, exchanges, }: { forwardedRef: RefObject token: TokenBalance pool: EarnPosition hasDepositToken: boolean hasTokensOnSameNetwork: boolean hasTokensOnOtherNetworks: boolean canAdd: boolean exchanges: ExternalExchangeProvider[] }) { const { t } = useTranslation() const analyticsProps = { ...getTokenAnalyticsProps(token), poolId: pool.positionId, providerId: pool.appId, depositTokenId: pool.dataProps.depositTokenId, } const { availableShortcutIds } = pool const allowCrossChainSwaps = getFeatureGate(StatsigFeatureGates.ALLOW_CROSS_CHAIN_SWAPS) const allowCrossChainSwapAndDeposit = getFeatureGate( StatsigFeatureGates.ALLOW_CROSS_CHAIN_SWAP_AND_DEPOSIT ) const { canSwapDeposit, showCrossChainSwap, showSwap, showAdd, showAddMore, showTransfer } = useMemo(() => { if (allowCrossChainSwapAndDeposit) { const hasOtherTokens = hasTokensOnOtherNetworks || hasTokensOnSameNetwork // should never have a case where allowCrossChainSwapAndDeposit is true // and allowCrossChainSwaps is false, so just presence of any token // should enable swap / swap and deposit const canSwapDeposit = availableShortcutIds.includes('swap-deposit') && hasOtherTokens return { canSwapDeposit, // no longer need to show separate cross chain swap action showCrossChainSwap: false, showSwap: !canSwapDeposit && hasOtherTokens, showAdd: canAdd && !hasDepositToken, showAddMore: canAdd && hasDepositToken, // Show Transfer if add is not an option or if the user has no tokens showTransfer: !canAdd || (!hasDepositToken && !hasOtherTokens), } } else { const canCrossChainSwap = allowCrossChainSwaps && hasTokensOnOtherNetworks const hasAllDepositAndSwapOptions = hasDepositToken && hasTokensOnSameNetwork && canCrossChainSwap const hasNoDepositOrSwapOptions = !hasDepositToken && !hasTokensOnSameNetwork && !canCrossChainSwap const canSwapDeposit = availableShortcutIds.includes('swap-deposit') && hasTokensOnSameNetwork return { canSwapDeposit, showCrossChainSwap: canSwapDeposit && canCrossChainSwap, showSwap: !canSwapDeposit && (hasTokensOnSameNetwork || canCrossChainSwap), showAdd: canAdd && !hasDepositToken, // Don't show add more if the user has all deposit and swap options are available showAddMore: canAdd && hasDepositToken && !hasAllDepositAndSwapOptions, // Show Transfer if the user has no deposit or swap options or if the token // does not support buy and if not all deposit and swap options are available showTransfer: hasNoDepositOrSwapOptions || (!canAdd && !hasAllDepositAndSwapOptions), } } }, [ hasDepositToken, hasTokensOnSameNetwork, hasTokensOnOtherNetworks, canAdd, availableShortcutIds, allowCrossChainSwapAndDeposit, allowCrossChainSwaps, ]) const title = canSwapDeposit || hasDepositToken ? t('earnFlow.beforeDepositBottomSheet.depositTitle') : t('earnFlow.beforeDepositBottomSheet.beforeYouCanDepositTitle') return ( {hasDepositToken && ( )} {canSwapDeposit && ( )} {(canSwapDeposit || hasDepositToken) && (showCrossChainSwap || showSwap || showAdd || showAddMore || showTransfer) && ( {allowCrossChainSwapAndDeposit ? t('earnFlow.beforeDepositBottomSheet.alternativeDescription') : t('earnFlow.beforeDepositBottomSheet.crossChainAlternativeDescription', { tokenNetwork: NETWORK_NAMES[token.networkId], })} )} {showCrossChainSwap && ( )} {showSwap && ( )} {showAdd && ( )} {showAddMore && ( )} {showTransfer && ( )} ) } const styles = StyleSheet.create({ actionsContainer: { flex: 1, gap: Spacing.Regular16, marginVertical: Spacing.Thick24, }, actionDetails: { ...typeScale.bodySmall, }, bottomSheetTitle: { ...typeScale.titleSmall, }, })