From f4422dd3fbc8cdcf473e206392da3fee8d5f1259 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 9 Dec 2024 11:02:33 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../core/analytics/models/AnalyticsParam.kt | 6 +- .../data/onramp/DefaultOnrampErrorResolver.kt | 20 +----- .../tangem/data/onramp/di/OnrampDataModule.kt | 7 +- .../domain/onramp/model/error/OnrampError.kt | 5 +- .../onramp/analytics/OnrampAnalyticsEvent.kt | 67 +++++++++++------- .../analytics/TokenExchangeAnalyticsEvent.kt | 3 +- .../ConfirmResidencyComponent.kt | 7 +- .../DefaultConfirmResidencyComponent.kt | 7 +- .../model/ConfirmResidencyModel.kt | 4 ++ .../onramp/main/DefaultOnrampMainComponent.kt | 6 +- .../amount/OnrampAmountStateFactory.kt | 13 +++- .../main/model/OnrampMainComponentModel.kt | 70 +++++++++++++------ .../providers/entity/ProviderListItemUM.kt | 7 +- .../providers/model/SelectProviderModel.kt | 32 ++++++++- .../redirect/model/OnrampRedirectModel.kt | 10 ++- .../onramp/root/DefaultOnrampComponent.kt | 5 +- .../selectcountry/SelectCountryComponent.kt | 3 +- .../model/OnrampSelectCountryModel.kt | 11 ++- .../selectcurrency/SelectCurrencyComponent.kt | 3 +- .../model/OnrampSelectCurrencyModel.kt | 4 ++ .../DefaultOnrampSettingsComponent.kt | 5 +- .../settings/OnrampSettingsComponent.kt | 3 +- .../settings/model/OnrampSettingsModel.kt | 32 +++++---- .../model/OnrampSuccessComponentModel.kt | 27 +++++-- .../utils/OnrampErrorAnalyticsSender.kt | 32 +++++++++ 25 files changed, 274 insertions(+), 115 deletions(-) create mode 100644 features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/utils/OnrampErrorAnalyticsSender.kt diff --git a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt index 9c7c2a3251..723451acf5 100644 --- a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt +++ b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt @@ -200,12 +200,10 @@ sealed class AnalyticsParam { const val INPUT = "Input" const val COUNT = "Count" const val DERIVATION = "Derivation" - - // region swap - const val TOKEN_CATEGORY = "Token" const val STATUS = "Status" const val PROVIDER = "Provider" const val PLACE = "Place" - // + const val RESIDENCE = "Residence" + const val PAYMENT_METHOD = "Payment Method" } } \ No newline at end of file diff --git a/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampErrorResolver.kt b/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampErrorResolver.kt index 8fc5e23cc5..2f60ba2878 100644 --- a/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampErrorResolver.kt +++ b/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampErrorResolver.kt @@ -1,20 +1,17 @@ package com.tangem.data.onramp -import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.data.onramp.converters.error.OnrampErrorConverter import com.tangem.datasource.api.common.response.ApiResponseError -import com.tangem.domain.onramp.analytics.OnrampAnalyticsEvent import com.tangem.domain.onramp.model.error.OnrampError import com.tangem.domain.onramp.model.error.OnrampRedirectError import com.tangem.domain.onramp.repositories.OnrampErrorResolver internal class DefaultOnrampErrorResolver( - private val analyticsEventHandler: AnalyticsEventHandler, private val onrampErrorConverter: OnrampErrorConverter, ) : OnrampErrorResolver { override fun resolve(throwable: Throwable): OnrampError { - val error = when (throwable) { + return when (throwable) { is ApiResponseError.HttpException -> { onrampErrorConverter.convert(throwable.errorBody.orEmpty()) } @@ -24,20 +21,5 @@ internal class DefaultOnrampErrorResolver( OnrampError.DomainError(throwable.message) } } - - when (error) { - is OnrampError.AmountError.TooBigError -> analyticsEventHandler.send(OnrampAnalyticsEvent.MaxAmountError) - is OnrampError.AmountError.TooSmallError -> analyticsEventHandler.send(OnrampAnalyticsEvent.MinAmountError) - is OnrampError.DataError -> analyticsEventHandler.send( - OnrampAnalyticsEvent.Errors( - tokenSymbol = "tokenSymbol", - providerName = "providerName", - errorCode = error.code, - ), - ) - else -> { /* no-op */ - } - } - return error } } \ No newline at end of file diff --git a/data/onramp/src/main/java/com/tangem/data/onramp/di/OnrampDataModule.kt b/data/onramp/src/main/java/com/tangem/data/onramp/di/OnrampDataModule.kt index 072b2dbbdb..a61d427078 100644 --- a/data/onramp/src/main/java/com/tangem/data/onramp/di/OnrampDataModule.kt +++ b/data/onramp/src/main/java/com/tangem/data/onramp/di/OnrampDataModule.kt @@ -1,7 +1,6 @@ package com.tangem.data.onramp.di import com.squareup.moshi.Moshi -import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.data.onramp.DefaultOnrampErrorResolver import com.tangem.data.onramp.DefaultOnrampRepository import com.tangem.data.onramp.DefaultOnrampTransactionRepository @@ -72,13 +71,9 @@ internal object OnrampDataModule { @Provides @Singleton - fun provideOnrampErrorResolver( - @NetworkMoshi moshi: Moshi, - analyticsEventHandler: AnalyticsEventHandler, - ): OnrampErrorResolver { + fun provideOnrampErrorResolver(@NetworkMoshi moshi: Moshi): OnrampErrorResolver { val jsonAdapter = moshi.adapter(ExpressErrorResponse::class.java) return DefaultOnrampErrorResolver( - analyticsEventHandler, OnrampErrorConverter(jsonAdapter), ) } diff --git a/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/error/OnrampError.kt b/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/error/OnrampError.kt index 50b8598b78..c7b4a01e27 100644 --- a/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/error/OnrampError.kt +++ b/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/error/OnrampError.kt @@ -6,6 +6,7 @@ sealed class OnrampError { sealed class AmountError : OnrampError() { abstract val requiredAmount: BigDecimal + data class TooSmallError( override val requiredAmount: BigDecimal, ) : AmountError() @@ -25,5 +26,7 @@ sealed class OnrampError { val description: String?, ) : OnrampError() - data class DomainError(val error: String?) : OnrampError() + data class DomainError( + val description: String?, + ) : OnrampError() } \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/analytics/OnrampAnalyticsEvent.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/analytics/OnrampAnalyticsEvent.kt index ce1236faf1..e577385a98 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/analytics/OnrampAnalyticsEvent.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/analytics/OnrampAnalyticsEvent.kt @@ -1,6 +1,14 @@ package com.tangem.domain.onramp.analytics import com.tangem.core.analytics.models.AnalyticsEvent +import com.tangem.core.analytics.models.AnalyticsParam.Key.CURRENCY +import com.tangem.core.analytics.models.AnalyticsParam.Key.ERROR_CODE +import com.tangem.core.analytics.models.AnalyticsParam.Key.ERROR_DESCRIPTION +import com.tangem.core.analytics.models.AnalyticsParam.Key.PAYMENT_METHOD +import com.tangem.core.analytics.models.AnalyticsParam.Key.PROVIDER +import com.tangem.core.analytics.models.AnalyticsParam.Key.RESIDENCE +import com.tangem.core.analytics.models.AnalyticsParam.Key.SOURCE +import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN_PARAM import com.tangem.domain.onramp.model.OnrampSource sealed class OnrampAnalyticsEvent( @@ -18,8 +26,8 @@ sealed class OnrampAnalyticsEvent( ) : OnrampAnalyticsEvent( event = "Buy Screen Opened", params = mapOf( - "Source" to source.analyticsName, - "Token" to tokenSymbol, + SOURCE to source.analyticsName, + TOKEN_PARAM to tokenSymbol, ), ) @@ -29,7 +37,7 @@ sealed class OnrampAnalyticsEvent( private val currency: String, ) : OnrampAnalyticsEvent( event = "Currency Chosen", - params = mapOf("Currency" to currency), + params = mapOf(CURRENCY to currency), ) data object CloseOnramp : OnrampAnalyticsEvent(event = "Button - Close") @@ -42,14 +50,14 @@ sealed class OnrampAnalyticsEvent( private val residence: String, ) : OnrampAnalyticsEvent( event = "Residence Chosen", - params = mapOf("Residence" to residence), + params = mapOf(RESIDENCE to residence), ) data class ResidenceConfirmScreenOpened( private val residence: String, ) : OnrampAnalyticsEvent( event = "Residence Confirm Screen", - params = mapOf("Residence" to residence), + params = mapOf(RESIDENCE to residence), ) data object OnResidenceChange : OnrampAnalyticsEvent(event = "Button - Change") @@ -58,7 +66,7 @@ sealed class OnrampAnalyticsEvent( private val residence: String, ) : OnrampAnalyticsEvent( event = "Button - Confirm", - params = mapOf("Residence" to residence), + params = mapOf(RESIDENCE to residence), ) data object ProvidersScreenOpened : OnrampAnalyticsEvent(event = "Providers Screen Opened") @@ -70,9 +78,9 @@ sealed class OnrampAnalyticsEvent( ) : OnrampAnalyticsEvent( event = "Provider Calculated", params = mapOf( - "Provider" to providerName, - "Token" to tokenSymbol, - "Payment Method" to paymentMethod, + PROVIDER to providerName, + TOKEN_PARAM to tokenSymbol, + PAYMENT_METHOD to paymentMethod, ), ) @@ -83,7 +91,7 @@ sealed class OnrampAnalyticsEvent( ) : OnrampAnalyticsEvent( event = "Method Chosen", params = mapOf( - "Payment Method" to paymentMethod, + PAYMENT_METHOD to paymentMethod, ), ) @@ -93,8 +101,8 @@ sealed class OnrampAnalyticsEvent( ) : OnrampAnalyticsEvent( event = "Provider Chosen", params = mapOf( - "Provider" to providerName, - "Token" to tokenSymbol, + PROVIDER to providerName, + TOKEN_PARAM to tokenSymbol, ), ) @@ -105,9 +113,9 @@ sealed class OnrampAnalyticsEvent( ) : OnrampAnalyticsEvent( event = "Button - Buy", params = mapOf( - "Provider" to providerName, - "Currency" to currency, - "Token" to tokenSymbol, + PROVIDER to providerName, + CURRENCY to currency, + TOKEN_PARAM to tokenSymbol, ), ) @@ -120,11 +128,11 @@ sealed class OnrampAnalyticsEvent( ) : OnrampAnalyticsEvent( event = "Buying In Progress Screen Opened", params = mapOf( - "Token" to tokenSymbol, - "Provider" to providerName, - "Residence" to residence, - "Currency" to currency, - "Method" to paymentMethod, + TOKEN_PARAM to tokenSymbol, + PROVIDER to providerName, + RESIDENCE to residence, + CURRENCY to currency, + PAYMENT_METHOD to paymentMethod, ), ) @@ -133,14 +141,25 @@ sealed class OnrampAnalyticsEvent( data class Errors( private val tokenSymbol: String, - private val providerName: String, private val errorCode: String, + private val providerName: String?, ) : OnrampAnalyticsEvent( event = "Errors", + params = buildMap { + put(TOKEN_PARAM, tokenSymbol) + providerName?.let { put(PROVIDER, providerName) } + put(ERROR_CODE, errorCode) + }, + ) + + data class AppErrors( + private val tokenSymbol: String, + private val errorDescription: String, + ) : OnrampAnalyticsEvent( + event = "App Errors", params = mapOf( - "Token" to tokenSymbol, - "Provider" to providerName, - "Error Code" to errorCode, + TOKEN_PARAM to tokenSymbol, + ERROR_DESCRIPTION to errorDescription, ), ) } \ No newline at end of file diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/analytics/TokenExchangeAnalyticsEvent.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/analytics/TokenExchangeAnalyticsEvent.kt index ae26e772f5..9df2d8a224 100644 --- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/analytics/TokenExchangeAnalyticsEvent.kt +++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/analytics/TokenExchangeAnalyticsEvent.kt @@ -4,13 +4,12 @@ import com.tangem.core.analytics.models.AnalyticsEvent import com.tangem.core.analytics.models.AnalyticsParam.Key.PLACE import com.tangem.core.analytics.models.AnalyticsParam.Key.PROVIDER import com.tangem.core.analytics.models.AnalyticsParam.Key.STATUS -import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN_CATEGORY import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN_PARAM class TokenExchangeAnalyticsEvent( event: String, params: Map = mapOf(), -) : AnalyticsEvent(TOKEN_CATEGORY, event, params, null) { +) : AnalyticsEvent("Token", event, params, null) { class CexTxStatusOpened(token: String) : TokenScreenAnalyticsEvent( event = "Swap Status Opened", diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/ConfirmResidencyComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/ConfirmResidencyComponent.kt index dd8bd0a162..feb6cd9c68 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/ConfirmResidencyComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/ConfirmResidencyComponent.kt @@ -3,10 +3,15 @@ package com.tangem.features.onramp.confirmresidency import com.tangem.core.decompose.factory.ComponentFactory import com.tangem.core.ui.decompose.ComposableBottomSheetComponent import com.tangem.domain.onramp.model.OnrampCountry +import com.tangem.domain.tokens.model.CryptoCurrency internal interface ConfirmResidencyComponent : ComposableBottomSheetComponent { - data class Params(val country: OnrampCountry, val onDismiss: (OnrampCountry) -> Unit) + data class Params( + val cryptoCurrency: CryptoCurrency, + val country: OnrampCountry, + val onDismiss: (OnrampCountry) -> Unit, + ) interface Factory : ComponentFactory } \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/DefaultConfirmResidencyComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/DefaultConfirmResidencyComponent.kt index fe1f307998..62dd39d0dd 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/DefaultConfirmResidencyComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/DefaultConfirmResidencyComponent.kt @@ -14,10 +14,10 @@ import com.tangem.core.decompose.model.getOrCreateModel import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent import com.tangem.core.ui.decompose.ComposableBottomSheetComponent +import com.tangem.features.onramp.confirmresidency.entity.ConfirmResidencyBottomSheetConfig import com.tangem.features.onramp.confirmresidency.model.ConfirmResidencyModel import com.tangem.features.onramp.confirmresidency.ui.ConfirmResidencyBottomSheet import com.tangem.features.onramp.confirmresidency.ui.ConfirmResidencyBottomSheetContent -import com.tangem.features.onramp.confirmresidency.entity.ConfirmResidencyBottomSheetConfig import com.tangem.features.onramp.selectcountry.SelectCountryComponent import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -68,7 +68,10 @@ internal class DefaultConfirmResidencyComponent @AssistedInject constructor( ): ComposableBottomSheetComponent = when (config) { ConfirmResidencyBottomSheetConfig.SelectCountry -> selectCountryComponentFactory.create( context = childByContext(componentContext), - params = SelectCountryComponent.Params(onDismiss = model.bottomSheetNavigation::dismiss), + params = SelectCountryComponent.Params( + cryptoCurrency = params.cryptoCurrency, + onDismiss = model.bottomSheetNavigation::dismiss, + ), ) } diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/model/ConfirmResidencyModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/model/ConfirmResidencyModel.kt index 460f0a03ad..d9d4c128ec 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/model/ConfirmResidencyModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/model/ConfirmResidencyModel.kt @@ -15,6 +15,7 @@ import com.tangem.features.onramp.confirmresidency.ConfirmResidencyComponent import com.tangem.features.onramp.confirmresidency.entity.ConfirmResidencyBottomSheetConfig import com.tangem.features.onramp.confirmresidency.entity.ConfirmResidencyUM import com.tangem.features.onramp.impl.R +import com.tangem.features.onramp.utils.sendOnrampErrorEvent import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.launchIn @@ -51,6 +52,9 @@ internal class ConfirmResidencyModel @Inject constructor( analyticsEventHandler.send(OnrampAnalyticsEvent.ResidenceConfirmScreenOpened(params.country.name)) getOnrampCountryUseCase.invoke() .onEach { maybeCountry -> + maybeCountry.onLeft { + analyticsEventHandler.sendOnrampErrorEvent(it, params.cryptoCurrency.symbol) + } val country = maybeCountry.getOrNull() if (country != null) { params.onDismiss(country) diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/DefaultOnrampMainComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/DefaultOnrampMainComponent.kt index e75146579a..739d1a4d6e 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/DefaultOnrampMainComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/DefaultOnrampMainComponent.kt @@ -54,6 +54,7 @@ internal class DefaultOnrampMainComponent @AssistedInject constructor( is OnrampMainBottomSheetConfig.ConfirmResidency -> confirmResidencyComponentFactory.create( context = childByContext(componentContext), params = ConfirmResidencyComponent.Params( + cryptoCurrency = params.cryptoCurrency, country = config.country, onDismiss = { model.bottomSheetNavigation.dismiss() @@ -63,7 +64,10 @@ internal class DefaultOnrampMainComponent @AssistedInject constructor( ) is OnrampMainBottomSheetConfig.CurrenciesList -> selectCurrencyComponentFactory.create( context = childByContext(componentContext), - params = SelectCurrencyComponent.Params(model.bottomSheetNavigation::dismiss), + params = SelectCurrencyComponent.Params( + cryptoCurrency = params.cryptoCurrency, + onDismiss = model.bottomSheetNavigation::dismiss, + ), ) is OnrampMainBottomSheetConfig.ProvidersList -> selectProviderComponentFactory.create( context = childByContext(componentContext), diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/entity/factory/amount/OnrampAmountStateFactory.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/entity/factory/amount/OnrampAmountStateFactory.kt index 7c58bb465f..f4ea0494ce 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/entity/factory/amount/OnrampAmountStateFactory.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/entity/factory/amount/OnrampAmountStateFactory.kt @@ -1,11 +1,13 @@ package com.tangem.features.onramp.main.entity.factory.amount +import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.format.bigdecimal.crypto import com.tangem.core.ui.format.bigdecimal.fiat import com.tangem.core.ui.format.bigdecimal.format +import com.tangem.domain.onramp.analytics.OnrampAnalyticsEvent import com.tangem.domain.onramp.model.OnrampCurrency import com.tangem.domain.onramp.model.OnrampProviderWithQuote import com.tangem.domain.onramp.model.OnrampQuote @@ -18,6 +20,7 @@ import com.tangem.utils.Provider internal class OnrampAmountStateFactory( private val currentStateProvider: Provider, + private val analyticsEventHandler: AnalyticsEventHandler, private val onrampIntents: OnrampIntents, ) { @@ -171,8 +174,14 @@ internal class OnrampAmountStateFactory( } val errorTextRes = when (error) { - is OnrampError.AmountError.TooBigError -> R.string.onramp_max_amount_restriction - is OnrampError.AmountError.TooSmallError -> R.string.onramp_min_amount_restriction + is OnrampError.AmountError.TooBigError -> { + analyticsEventHandler.send(OnrampAnalyticsEvent.MaxAmountError) + R.string.onramp_max_amount_restriction + } + is OnrampError.AmountError.TooSmallError -> { + analyticsEventHandler.send(OnrampAnalyticsEvent.MaxAmountError) + R.string.onramp_min_amount_restriction + } } return OnrampAmountSecondaryFieldUM.Error( diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt index 3d7d00260e..006544cb2a 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt @@ -21,6 +21,7 @@ import com.tangem.domain.onramp.model.OnrampAvailability import com.tangem.domain.onramp.model.OnrampCurrency import com.tangem.domain.onramp.model.OnrampProviderWithQuote import com.tangem.domain.onramp.model.OnrampQuote +import com.tangem.domain.onramp.model.error.OnrampError import com.tangem.domain.wallets.usecase.GetWalletsUseCase import com.tangem.features.onramp.impl.R import com.tangem.features.onramp.main.OnrampMainComponent @@ -32,6 +33,7 @@ import com.tangem.features.onramp.main.entity.factory.OnrampStateFactory import com.tangem.features.onramp.main.entity.factory.amount.OnrampAmountStateFactory import com.tangem.features.onramp.providers.entity.SelectProviderResult import com.tangem.features.onramp.utils.InputManager +import com.tangem.features.onramp.utils.sendOnrampErrorEvent import com.tangem.utils.Provider import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.PeriodicTask @@ -69,6 +71,7 @@ internal class OnrampMainComponentModel @Inject constructor( ) private val amountStateFactory = OnrampAmountStateFactory( currentStateProvider = Provider { _state.value }, + analyticsEventHandler = analyticsEventHandler, onrampIntents = this, ) private val selectedUserWallet = getWalletsUseCase.invokeSync().first { it.walletId == params.userWalletId } @@ -111,9 +114,12 @@ internal class OnrampMainComponentModel @Inject constructor( private fun checkResidenceCountry() { modelScope.launch { - checkOnrampAvailabilityUseCase.invoke() + checkOnrampAvailabilityUseCase() .onRight(::handleOnrampAvailability) - .onLeft { Timber.e(it.toString()) } + .onLeft { error -> + Timber.e(error.toString()) + sendOnrampErrorAnalytic(error) + } } } @@ -129,9 +135,14 @@ internal class OnrampMainComponentModel @Inject constructor( private fun subscribeToCurrencyUpdates() { getOnrampCurrencyUseCase.invoke() .onEach { maybeCurrency -> - val currency = maybeCurrency.getOrNull() ?: return@onEach - _state.update { amountStateFactory.getUpdatedCurrencyState(currency) } - updatePairsAndQuotes() + maybeCurrency.fold( + ifLeft = ::sendOnrampErrorAnalytic, + ifRight = { currency -> + if (currency == null) return@onEach + _state.update { amountStateFactory.getUpdatedCurrencyState(currency) } + updatePairsAndQuotes() + }, + ) } .launchIn(modelScope) } @@ -146,7 +157,7 @@ internal class OnrampMainComponentModel @Inject constructor( } private suspend fun updatePairsAndQuotes() { - fetchPairsUseCase.invoke(params.cryptoCurrency) + fetchPairsUseCase.invoke(params.cryptoCurrency).onLeft(::sendOnrampErrorAnalytic) startLoadingQuotes() } @@ -165,7 +176,7 @@ internal class OnrampMainComponentModel @Inject constructor( fetchQuotesUseCase.invoke( amount = content.amountBlockState.amountFieldModel.fiatAmount, cryptoCurrency = params.cryptoCurrency, - ) + ).onLeft(::sendOnrampErrorAnalytic) } }, onSuccess = {}, @@ -176,20 +187,27 @@ internal class OnrampMainComponentModel @Inject constructor( private fun subscribeToQuotesUpdate() { getOnrampQuotesUseCase.invoke() .onEach { maybeQuotes -> - val quotes = maybeQuotes.getOrNull() ?: return@onEach - val isNoQuotes = quotes.none { it is OnrampQuote.Data } - val quote = quotes.firstOrNull() ?: return@onEach - if (quote is OnrampQuote.Data && lastAmount.value != quote.fromAmount.value) { - lastAmount.value = quote.fromAmount.value - analyticsEventHandler.send( - OnrampAnalyticsEvent.ProviderCalculated( - providerName = quote.provider.info.name, - tokenSymbol = params.cryptoCurrency.symbol, - paymentMethod = quote.paymentMethod.name, - ), - ) - } - _state.update { amountStateFactory.getAmountSecondaryUpdatedState(quote, isNoQuotes) } + maybeQuotes.fold( + ifLeft = ::sendOnrampErrorAnalytic, + ifRight = { quotes -> + quotes.filterIsInstance().forEach { errorState -> + sendOnrampErrorAnalytic(errorState.error) + } + val isNoQuotes = quotes.none { it is OnrampQuote.Data } + val quote = quotes.firstOrNull() ?: return@onEach + if (quote is OnrampQuote.Data && lastAmount.value != quote.fromAmount.value) { + lastAmount.value = quote.fromAmount.value + analyticsEventHandler.send( + OnrampAnalyticsEvent.ProviderCalculated( + providerName = quote.provider.info.name, + tokenSymbol = params.cryptoCurrency.symbol, + paymentMethod = quote.paymentMethod.name, + ), + ) + } + _state.update { amountStateFactory.getAmountSecondaryUpdatedState(quote, isNoQuotes) } + }, + ) } .launchIn(modelScope) } @@ -270,6 +288,16 @@ internal class OnrampMainComponentModel @Inject constructor( ) } + private fun sendOnrampErrorAnalytic(error: OnrampError) { + val content = state.value as? OnrampMainComponentUM.Content + val providerContent = content?.providerBlockState as? OnrampProviderBlockUM.Content + analyticsEventHandler.sendOnrampErrorEvent( + error = error, + tokenSymbol = params.cryptoCurrency.symbol, + providerName = providerContent?.providerName, + ) + } + private companion object { const val UPDATE_DELAY = 10_000L } diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/entity/ProviderListItemUM.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/entity/ProviderListItemUM.kt index 0107136929..def8471d07 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/entity/ProviderListItemUM.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/entity/ProviderListItemUM.kt @@ -5,11 +5,12 @@ import com.tangem.core.ui.extensions.TextReference internal sealed interface ProviderListItemUM { val providerId: String + val name: String data class Available( override val providerId: String, + override val name: String, val imageUrl: String, - val name: String, val rate: String, val isBestRate: Boolean, val diffRate: TextReference, @@ -19,16 +20,16 @@ internal sealed interface ProviderListItemUM { data class AvailableWithError( override val providerId: String, + override val name: String, val imageUrl: String, - val name: String, val subtitle: TextReference, val onClick: () -> Unit, ) : ProviderListItemUM data class Unavailable( override val providerId: String, + override val name: String, val imageUrl: String, - val name: String, val subtitle: TextReference, ) : ProviderListItemUM } \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt index 45c6d33457..b044121515 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt @@ -25,6 +25,7 @@ import com.tangem.features.onramp.impl.R import com.tangem.features.onramp.paymentmethod.entity.PaymentMethodUM import com.tangem.features.onramp.providers.SelectProviderComponent import com.tangem.features.onramp.providers.entity.* +import com.tangem.features.onramp.utils.sendOnrampErrorEvent import com.tangem.utils.StringsSigns.MINUS import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.collections.immutable.ImmutableList @@ -60,7 +61,12 @@ internal class SelectProviderModel @Inject constructor( private fun subscribeToPaymentMethodUpdates() { getOnrampSelectedPaymentMethodUseCase.invoke() - .onEach { it.getOrNull()?.let(::getProviders) } + .onEach { maybePaymentMethod -> + maybePaymentMethod.fold( + ifLeft = ::sendOnrampErrorEvent, + ifRight = ::getProviders, + ) + } .launchIn(modelScope) } @@ -76,7 +82,10 @@ internal class SelectProviderModel @Inject constructor( ) } } - .onLeft { Timber.e(it.toString()) } + .onLeft { error -> + sendOnrampErrorEvent(error) + Timber.e(error.toString()) + } } } @@ -96,7 +105,13 @@ internal class SelectProviderModel @Inject constructor( private fun openPaymentMethods() { analyticsEventHandler.send(OnrampAnalyticsEvent.PaymentMethodsScreenOpened) modelScope.launch { - val methods = getSelectedPaymentMethodsUseCase.invoke().getOrNull().orEmpty() + val methods = getSelectedPaymentMethodsUseCase().fold( + ifLeft = { error -> + sendOnrampErrorEvent(error) + emptySet() + }, + ifRight = { it }, + ) bottomSheetNavigation.activate( ProviderListBottomSheetConfig.PaymentMethods( selectedMethodId = _state.value.paymentMethod.id, @@ -221,6 +236,17 @@ internal class SelectProviderModel @Inject constructor( params.onDismiss() } + private fun sendOnrampErrorEvent(error: OnrampError) { + val selectedProvider = state.value.providers.firstOrNull { + it.providerId == params.selectedProviderId + } + analyticsEventHandler.sendOnrampErrorEvent( + error = error, + tokenSymbol = params.cryptoCurrency.symbol, + providerName = selectedProvider?.name, + ) + } + /** * Sorting providers by rule: * diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/redirect/model/OnrampRedirectModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/redirect/model/OnrampRedirectModel.kt index c5657187c0..f15be660c5 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/redirect/model/OnrampRedirectModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/redirect/model/OnrampRedirectModel.kt @@ -1,6 +1,7 @@ package com.tangem.features.onramp.redirect.model import androidx.compose.ui.res.stringResource +import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router @@ -20,16 +21,19 @@ import com.tangem.features.onramp.impl.R import com.tangem.features.onramp.redirect.OnrampRedirectComponent import com.tangem.features.onramp.redirect.entity.OnrampRedirectTopBarUM import com.tangem.features.onramp.redirect.entity.OnrampRedirectUM +import com.tangem.features.onramp.utils.sendOnrampErrorEvent import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.launch import timber.log.Timber import javax.inject.Inject +@Suppress("LongParameterList") internal class OnrampRedirectModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val urlOpener: UrlOpener, private val getOnrampRedirectUrlUseCase: GetOnrampRedirectUrlUseCase, private val messageSender: UiMessageSender, + private val analyticsEventHandler: AnalyticsEventHandler, router: Router, paramsContainer: ParamsContainer, ) : Model() { @@ -79,7 +83,11 @@ internal class OnrampRedirectModel @Inject constructor( private fun handleError(error: OnrampError) { Timber.e(error.toString()) - + analyticsEventHandler.sendOnrampErrorEvent( + error = error, + tokenSymbol = params.cryptoCurrency.symbol, + providerName = params.onrampProviderWithQuote.provider.info.name, + ) val contentMessage = ContentMessage { onDismiss -> BasicDialog( message = stringResource(id = R.string.common_unknown_error), diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/root/DefaultOnrampComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/root/DefaultOnrampComponent.kt index 6e86c98f9a..02047a8939 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/root/DefaultOnrampComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/root/DefaultOnrampComponent.kt @@ -60,7 +60,10 @@ internal class DefaultOnrampComponent @AssistedInject constructor( when (config) { OnrampChild.Settings -> settingsComponentFactory.create( context = childByContext(componentContext), - params = OnrampSettingsComponent.Params(navigation::pop), + params = OnrampSettingsComponent.Params( + params.cryptoCurrency, + navigation::pop, + ), ) OnrampChild.Main -> onrampMainComponentFactory.create( context = childByContext(componentContext), diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/SelectCountryComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/SelectCountryComponent.kt index 96a98be090..ba72314dd6 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/SelectCountryComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/SelectCountryComponent.kt @@ -2,10 +2,11 @@ package com.tangem.features.onramp.selectcountry import com.tangem.core.decompose.factory.ComponentFactory import com.tangem.core.ui.decompose.ComposableBottomSheetComponent +import com.tangem.domain.tokens.model.CryptoCurrency internal interface SelectCountryComponent : ComposableBottomSheetComponent { - data class Params(val onDismiss: () -> Unit) + data class Params(val cryptoCurrency: CryptoCurrency, val onDismiss: () -> Unit) interface Factory : ComponentFactory } \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/model/OnrampSelectCountryModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/model/OnrampSelectCountryModel.kt index 6e8fdf903c..3b401da0a1 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/model/OnrampSelectCountryModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/model/OnrampSelectCountryModel.kt @@ -21,6 +21,7 @@ import com.tangem.features.onramp.selectcountry.entity.transformer.UpdateCountry import com.tangem.features.onramp.utils.InputManager import com.tangem.features.onramp.utils.UpdateSearchBarActiveStateTransformer import com.tangem.features.onramp.utils.UpdateSearchQueryTransformer +import com.tangem.features.onramp.utils.sendOnrampErrorEvent import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList @@ -61,10 +62,16 @@ internal class OnrampSelectCountryModel @Inject constructor( @OptIn(ExperimentalCoroutinesApi::class) private suspend fun subscribeOnUpdateState() { combine( - flow = refreshTrigger.onStart { emit(Unit) }.flatMapLatest { flowOf(getOnrampCountriesUseCase.invoke()) }, - flow2 = getOnrampCountryUseCase.invoke(), + flow = refreshTrigger.onStart { emit(Unit) }.flatMapLatest { flowOf(getOnrampCountriesUseCase()) }, + flow2 = getOnrampCountryUseCase(), flow3 = searchManager.query, ) { maybeCountries, maybeCountry, query -> + maybeCountries.onLeft { + analyticsEventHandler.sendOnrampErrorEvent(it, params.cryptoCurrency.symbol) + } + maybeCountry.onLeft { + analyticsEventHandler.sendOnrampErrorEvent(it, params.cryptoCurrency.symbol) + } UpdateCountryItemsTransformer( maybeCountries = maybeCountries, defaultCountry = maybeCountry.getOrNull(), diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/SelectCurrencyComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/SelectCurrencyComponent.kt index a6c69ab8f3..f8283864dd 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/SelectCurrencyComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/SelectCurrencyComponent.kt @@ -2,10 +2,11 @@ package com.tangem.features.onramp.selectcurrency import com.tangem.core.decompose.factory.ComponentFactory import com.tangem.core.ui.decompose.ComposableBottomSheetComponent +import com.tangem.domain.tokens.model.CryptoCurrency internal interface SelectCurrencyComponent : ComposableBottomSheetComponent { - data class Params(val onDismiss: () -> Unit) + data class Params(val cryptoCurrency: CryptoCurrency, val onDismiss: () -> Unit) interface Factory : ComponentFactory } \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/model/OnrampSelectCurrencyModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/model/OnrampSelectCurrencyModel.kt index ae4035b1e5..46a3aea5de 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/model/OnrampSelectCurrencyModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/model/OnrampSelectCurrencyModel.kt @@ -22,6 +22,7 @@ import com.tangem.features.onramp.selectcurrency.entity.transformer.UpdateCurren import com.tangem.features.onramp.utils.InputManager import com.tangem.features.onramp.utils.UpdateSearchBarActiveStateTransformer import com.tangem.features.onramp.utils.UpdateSearchQueryTransformer +import com.tangem.features.onramp.utils.sendOnrampErrorEvent import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList @@ -59,6 +60,9 @@ internal class OnrampSelectCurrencyModel @Inject constructor( flow = refreshTrigger.onStart { emit(Unit) }.flatMapLatest { flowOf(getOnrampCurrenciesUseCase.invoke()) }, flow2 = searchManager.query, ) { maybeCurrencies, query -> + maybeCurrencies.onLeft { + analyticsEventHandler.sendOnrampErrorEvent(it, params.cryptoCurrency.symbol) + } UpdateCurrencyItemsTransformer( maybeCurrencies = maybeCurrencies, query = query, diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/DefaultOnrampSettingsComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/DefaultOnrampSettingsComponent.kt index efec6676c4..36999376a3 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/DefaultOnrampSettingsComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/DefaultOnrampSettingsComponent.kt @@ -51,7 +51,10 @@ internal class DefaultOnrampSettingsComponent @AssistedInject constructor( ): ComposableBottomSheetComponent = when (config) { OnrampSettingsConfig.SelectCountry -> selectCountryComponentFactory.create( context = childByContext(componentContext), - params = SelectCountryComponent.Params(model.bottomSheetNavigation::dismiss), + params = SelectCountryComponent.Params( + params.cryptoCurrency, + model.bottomSheetNavigation::dismiss, + ), ) } diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/OnrampSettingsComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/OnrampSettingsComponent.kt index 2514bbb00b..4b3b8d1455 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/OnrampSettingsComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/OnrampSettingsComponent.kt @@ -2,10 +2,11 @@ package com.tangem.features.onramp.settings import com.tangem.core.decompose.factory.ComponentFactory import com.tangem.core.ui.decompose.ComposableContentComponent +import com.tangem.domain.tokens.model.CryptoCurrency internal interface OnrampSettingsComponent : ComposableContentComponent { - data class Params(val onBack: () -> Unit) + data class Params(val cryptoCurrency: CryptoCurrency, val onBack: () -> Unit) interface Factory : ComponentFactory } \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/model/OnrampSettingsModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/model/OnrampSettingsModel.kt index c62ccff591..a67426d614 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/model/OnrampSettingsModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/model/OnrampSettingsModel.kt @@ -15,6 +15,7 @@ import com.tangem.features.onramp.settings.OnrampSettingsComponent import com.tangem.features.onramp.settings.entity.OnrampSettingsConfig import com.tangem.features.onramp.settings.entity.OnrampSettingsItemUM import com.tangem.features.onramp.settings.entity.OnrampSettingsUM +import com.tangem.features.onramp.utils.sendOnrampErrorEvent import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.flow.* @@ -46,19 +47,24 @@ internal class OnrampSettingsModel @Inject constructor( } private fun updateResidenceState(maybeCountry: Either) { - maybeCountry.onRight { country -> - _state.update { state -> - state.copy( - items = listOf( - OnrampSettingsItemUM.Residence( - countryName = country?.name.orEmpty(), - flagUrl = country?.image.orEmpty(), - onClick = ::openSelectCountryBottomSheet, - ), - ).toImmutableList(), - ) - } - } + maybeCountry.fold( + ifLeft = { + analyticsEventHandler.sendOnrampErrorEvent(it, params.cryptoCurrency.symbol) + }, + ifRight = { country -> + _state.update { state -> + state.copy( + items = listOf( + OnrampSettingsItemUM.Residence( + countryName = country?.name.orEmpty(), + flagUrl = country?.image.orEmpty(), + onClick = ::openSelectCountryBottomSheet, + ), + ).toImmutableList(), + ) + } + }, + ) } private fun openSelectCountryBottomSheet() { diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/model/OnrampSuccessComponentModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/model/OnrampSuccessComponentModel.kt index 6d1c437423..348cbe0154 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/model/OnrampSuccessComponentModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/model/OnrampSuccessComponentModel.kt @@ -12,10 +12,12 @@ import com.tangem.domain.onramp.analytics.OnrampAnalyticsEvent import com.tangem.domain.onramp.model.OnrampStatus import com.tangem.domain.onramp.model.cache.OnrampTransaction import com.tangem.domain.tokens.GetCryptoCurrencyUseCase +import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.features.onramp.component.OnrampSuccessComponent import com.tangem.features.onramp.success.entity.OnrampSuccessClickIntents import com.tangem.features.onramp.success.entity.OnrampSuccessComponentUM import com.tangem.features.onramp.success.entity.conterter.SetOnrampSuccessContentConverter +import com.tangem.features.onramp.utils.sendOnrampErrorEvent import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -74,8 +76,13 @@ internal class OnrampSuccessComponentModel @Inject constructor( getOnrampStatusUseCase(externalTxId = params.externalTxId) .fold( - ifLeft = { - Timber.e(it.toString()) + ifLeft = { error -> + analyticsEventHandler.sendOnrampErrorEvent( + error = error, + tokenSymbol = cryptoCurrency.symbol, + providerName = transaction.providerName, + ) + Timber.e(error.toString()) }, ifRight = { status -> analyticsEventHandler.send( @@ -94,15 +101,25 @@ internal class OnrampSuccessComponentModel @Inject constructor( goToProviderClick = ::goToProviderClick, ).convert(status) } - removeTransactionIfTerminalStatus(status) + removeTransactionIfTerminalStatus(cryptoCurrency, transaction.providerName, status) }, ) } - private fun removeTransactionIfTerminalStatus(status: OnrampStatus) { + private fun removeTransactionIfTerminalStatus( + cryptoCurrency: CryptoCurrency, + providerName: String, + status: OnrampStatus, + ) { modelScope.launch { if (status.status.isTerminal) { - onrampRemoveTransactionUseCase(status.txId) + onrampRemoveTransactionUseCase(status.txId).onLeft { error -> + analyticsEventHandler.sendOnrampErrorEvent( + error = error, + tokenSymbol = cryptoCurrency.symbol, + providerName = providerName, + ) + } } } } diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/utils/OnrampErrorAnalyticsSender.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/utils/OnrampErrorAnalyticsSender.kt new file mode 100644 index 0000000000..275cd02a25 --- /dev/null +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/utils/OnrampErrorAnalyticsSender.kt @@ -0,0 +1,32 @@ +package com.tangem.features.onramp.utils + +import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.domain.onramp.analytics.OnrampAnalyticsEvent +import com.tangem.domain.onramp.model.error.OnrampError + +internal fun AnalyticsEventHandler.sendOnrampErrorEvent( + error: OnrampError, + tokenSymbol: String, + providerName: String? = null, +) = when (error) { + is OnrampError.DataError -> send( + OnrampAnalyticsEvent.Errors( + tokenSymbol = tokenSymbol, + providerName = providerName, + errorCode = error.code, + ), + ) + is OnrampError.DomainError -> { + send( + OnrampAnalyticsEvent.AppErrors( + tokenSymbol = tokenSymbol, + errorDescription = error.description.orEmpty(), + ), + ) + } + is OnrampError.AmountError.TooBigError, + is OnrampError.AmountError.TooSmallError, + OnrampError.RedirectError.VerificationFailed, + OnrampError.RedirectError.WrongRequestId, + -> { /* no-op */ } +} \ No newline at end of file