Updated on 2026-08-14

This commit is contained in:
Tangem 2026-03-02 20:17:20 +05:00
parent 282ab7a56a
commit 922b197172
27 changed files with 90 additions and 4 deletions

View file

@ -1,6 +1,7 @@
package com.tangem.tap.di package com.tangem.tap.di
import android.content.Context import android.content.Context
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.api.AnalyticsExceptionHandler import com.tangem.core.analytics.api.AnalyticsExceptionHandler
import com.tangem.core.decompose.di.GlobalUiMessageSender import com.tangem.core.decompose.di.GlobalUiMessageSender
import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.decompose.ui.UiMessageSender
@ -42,6 +43,7 @@ internal class TangemSdkManagerModule {
sendFeedbackEmailUseCase: SendFeedbackEmailUseCase, sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
analyticsExceptionHandler: AnalyticsExceptionHandler, analyticsExceptionHandler: AnalyticsExceptionHandler,
blockchainToDeriveFinder: BlockchainToDeriveFinder, blockchainToDeriveFinder: BlockchainToDeriveFinder,
analyticsEventHandler: AnalyticsEventHandler,
dispatchers: CoroutineDispatcherProvider, dispatchers: CoroutineDispatcherProvider,
): TangemSdkManager { ): TangemSdkManager {
return if (BuildConfig.MOCK_DATA_SOURCE) { return if (BuildConfig.MOCK_DATA_SOURCE) {
@ -59,6 +61,7 @@ internal class TangemSdkManagerModule {
sendFeedbackEmailUseCase = sendFeedbackEmailUseCase, sendFeedbackEmailUseCase = sendFeedbackEmailUseCase,
analyticsExceptionHandler = analyticsExceptionHandler, analyticsExceptionHandler = analyticsExceptionHandler,
blockchainToDeriveFinder = blockchainToDeriveFinder, blockchainToDeriveFinder = blockchainToDeriveFinder,
analyticsEventHandler = analyticsEventHandler,
dispatchers = dispatchers, dispatchers = dispatchers,
) )
} }

View file

@ -18,7 +18,10 @@ import com.tangem.common.extensions.hexToBytes
import com.tangem.common.services.secure.SecureStorage import com.tangem.common.services.secure.SecureStorage
import com.tangem.common.usersCode.UserCodeRepository import com.tangem.common.usersCode.UserCodeRepository
import com.tangem.core.analytics.Analytics import com.tangem.core.analytics.Analytics
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.api.AnalyticsExceptionHandler import com.tangem.core.analytics.api.AnalyticsExceptionHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.analytics.models.ExceptionAnalyticsEvent import com.tangem.core.analytics.models.ExceptionAnalyticsEvent
import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.navigation.finisher.AppFinisher import com.tangem.core.navigation.finisher.AppFinisher
@ -82,6 +85,7 @@ internal class DefaultTangemSdkManager(
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase, private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
private val analyticsExceptionHandler: AnalyticsExceptionHandler, private val analyticsExceptionHandler: AnalyticsExceptionHandler,
private val blockchainToDeriveFinder: BlockchainToDeriveFinder, private val blockchainToDeriveFinder: BlockchainToDeriveFinder,
private val analyticsEventHandler: AnalyticsEventHandler,
dispatchers: CoroutineDispatcherProvider, dispatchers: CoroutineDispatcherProvider,
) : TangemSdkManager { ) : TangemSdkManager {
@ -470,6 +474,9 @@ internal class DefaultTangemSdkManager(
title = resourceReference(R.string.alert_button_request_support), title = resourceReference(R.string.alert_button_request_support),
onClick = { onClick = {
coroutineScope.launch { coroutineScope.launch {
analyticsEventHandler.send(
Basic.ButtonSupport(source = AnalyticsParam.ScreensSources.SignIn),
)
sendFeedbackEmailUseCase(FeedbackEmailType.BiometricsAuthenticationFailed) sendFeedbackEmailUseCase(FeedbackEmailType.BiometricsAuthenticationFailed)
} }
}, },

View file

@ -98,6 +98,7 @@ sealed class AnalyticsParam {
data object NewsLink : ScreensSources("News Link") data object NewsLink : ScreensSources("News Link")
data object NewsPage : ScreensSources("News Page") data object NewsPage : ScreensSources("News Page")
data object Portfolio : ScreensSources("Portfolio") data object Portfolio : ScreensSources("Portfolio")
data object Staking : ScreensSources("Staking")
} }
sealed class TxSentFrom(val value: String) { sealed class TxSentFrom(val value: String) {

View file

@ -11,9 +11,12 @@ class TokenExchangeAnalyticsEvent(
params: Map<String, String> = mapOf(), params: Map<String, String> = mapOf(),
) : AnalyticsEvent("Token", event, params) { ) : AnalyticsEvent("Token", event, params) {
class CexTxStatusOpened(token: String) : TokenScreenAnalyticsEvent( class CexTxStatusOpened(token: String, provider: String) : TokenScreenAnalyticsEvent(
event = "Swap Status Opened", event = "Swap Status Opened",
params = mapOf(TOKEN_PARAM to token), params = mapOf(
TOKEN_PARAM to token,
PROVIDER to provider,
),
) )
class CexTxStatusChanged(token: String, status: String, provider: String) : TokenScreenAnalyticsEvent( class CexTxStatusChanged(token: String, status: String, provider: String) : TokenScreenAnalyticsEvent(

View file

@ -150,6 +150,7 @@ internal class DetailsModel @Inject constructor(
} }
} }
analyticsEventHandler.send(Basic.ButtonSupport(source = AnalyticsParam.ScreensSources.Settings))
sendFeedbackEmailUseCase(feedbackType) sendFeedbackEmailUseCase(feedbackType)
} }
} }
@ -230,6 +231,7 @@ internal class DetailsModel @Inject constructor(
} }
} }
analyticsEventHandler.send(Basic.ButtonSupport(source = AnalyticsParam.ScreensSources.Settings))
sendFeedbackEmailUseCase(feedbackType) sendFeedbackEmailUseCase(feedbackType)
} }
} }

View file

@ -9,6 +9,8 @@ import com.tangem.common.ui.charts.state.MarketChartData
import com.tangem.common.ui.charts.state.MarketChartDataProducer import com.tangem.common.ui.charts.state.MarketChartDataProducer
import com.tangem.common.ui.charts.state.sorted import com.tangem.common.ui.charts.state.sorted
import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.model.ParamsContainer
@ -163,6 +165,7 @@ internal class MarketsTokenDetailsModel @Inject constructor(
}, },
onGeneratedAINotificationClick = { onGeneratedAINotificationClick = {
modelScope.launch { modelScope.launch {
analyticsEventHandler.send(Basic.ButtonSupport(source = AnalyticsParam.ScreensSources.Market))
sendFeedbackEmailUseCase( sendFeedbackEmailUseCase(
type = FeedbackEmailType.CurrencyDescriptionError( type = FeedbackEmailType.CurrencyDescriptionError(
currencyId = params.token.id.value, currencyId = params.token.id.value,

View file

@ -179,6 +179,9 @@ internal class UpgradeWalletModel @Inject constructor(
title = resourceReference(id = R.string.alert_button_request_support), title = resourceReference(id = R.string.alert_button_request_support),
onClick = { onClick = {
modelScope.launch { modelScope.launch {
analyticsEventHandler.send(
Basic.ButtonSupport(source = AnalyticsParam.ScreensSources.Upgrade),
)
sendFeedbackEmailUseCase(type = FeedbackEmailType.CardAttestationFailed) sendFeedbackEmailUseCase(type = FeedbackEmailType.CardAttestationFailed)
} }
}, },

View file

@ -6,6 +6,7 @@ import com.tangem.common.core.TangemSdkError
import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.api.AnalyticsExceptionHandler import com.tangem.core.analytics.api.AnalyticsExceptionHandler
import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.analytics.models.ExceptionAnalyticsEvent import com.tangem.core.analytics.models.ExceptionAnalyticsEvent
import com.tangem.core.analytics.models.event.OnboardingAnalyticsEvent import com.tangem.core.analytics.models.event.OnboardingAnalyticsEvent
import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.di.ModelScoped
@ -262,6 +263,9 @@ class MultiWalletBackupModel @Inject constructor(
errorDescription = resourceReference(id = resId, resArgs.toWrappedList()), errorDescription = resourceReference(id = resId, resArgs.toWrappedList()),
onRequestSupport = { onRequestSupport = {
modelScope.launch { modelScope.launch {
analyticsEventHandler.send(
Basic.ButtonSupport(source = AnalyticsParam.ScreensSources.Onboarding),
)
sendFeedbackEmailUseCase(type = FeedbackEmailType.CardAttestationFailed) sendFeedbackEmailUseCase(type = FeedbackEmailType.CardAttestationFailed)
} }
}, },

View file

@ -5,6 +5,7 @@ import com.tangem.common.CompletionResult
import com.tangem.common.core.TangemSdkError import com.tangem.common.core.TangemSdkError
import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.model.ParamsContainer
@ -182,6 +183,7 @@ internal class MultiWalletCreateWalletModel @Inject constructor(
modelScope.launch { modelScope.launch {
val cardInfo = val cardInfo =
getWalletMetaInfoUseCase(multiWalletState.value.currentScanResponse).getOrNull() ?: return@launch getWalletMetaInfoUseCase(multiWalletState.value.currentScanResponse).getOrNull() ?: return@launch
analyticsHandler.send(Basic.ButtonSupport(source = AnalyticsParam.ScreensSources.Onboarding))
sendFeedbackEmailUseCase(FeedbackEmailType.DirectUserRequest(cardInfo)) sendFeedbackEmailUseCase(FeedbackEmailType.DirectUserRequest(cardInfo))
} }
} }

View file

@ -5,7 +5,9 @@ import arrow.core.getOrElse
import com.tangem.common.CompletionResult import com.tangem.common.CompletionResult
import com.tangem.common.core.TangemSdkError import com.tangem.common.core.TangemSdkError
import com.tangem.common.extensions.ByteArrayKey import com.tangem.common.extensions.ByteArrayKey
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.model.ParamsContainer
@ -71,6 +73,7 @@ internal class MultiWalletFinalizeModel @Inject constructor(
private val walletsRepository: WalletsRepository, private val walletsRepository: WalletsRepository,
private val uiMessageSender: UiMessageSender, private val uiMessageSender: UiMessageSender,
private val backupValidator: BackupValidator, private val backupValidator: BackupValidator,
private val analyticsEventHandler: AnalyticsEventHandler,
) : Model() { ) : Model() {
private val params = paramsContainer.require<MultiWalletChildParams>() private val params = paramsContainer.require<MultiWalletChildParams>()
@ -392,6 +395,7 @@ internal class MultiWalletFinalizeModel @Inject constructor(
modelScope.launch { modelScope.launch {
val cardInfo = val cardInfo =
getWalletMetaInfoUseCase(multiWalletState.value.currentScanResponse).getOrNull() ?: return@launch getWalletMetaInfoUseCase(multiWalletState.value.currentScanResponse).getOrNull() ?: return@launch
analyticsEventHandler.send(Basic.ButtonSupport(source = AnalyticsParam.ScreensSources.Onboarding))
sendFeedbackEmailUseCase(FeedbackEmailType.BackupProblem(cardInfo)) sendFeedbackEmailUseCase(FeedbackEmailType.BackupProblem(cardInfo))
} }
} }

View file

@ -7,6 +7,7 @@ import com.tangem.common.TangemBlogUrlBuilder
import com.tangem.common.core.TangemSdkError import com.tangem.common.core.TangemSdkError
import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.analytics.models.event.OnboardingAnalyticsEvent import com.tangem.core.analytics.models.event.OnboardingAnalyticsEvent
import com.tangem.core.decompose.di.GlobalUiMessageSender import com.tangem.core.decompose.di.GlobalUiMessageSender
import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.di.ModelScoped
@ -310,6 +311,7 @@ internal class MultiWalletSeedPhraseModel @Inject constructor(
modelScope.launch { modelScope.launch {
val cardInfo = val cardInfo =
getWalletMetaInfoUseCase(multiWalletState.value.currentScanResponse).getOrNull() ?: return@launch getWalletMetaInfoUseCase(multiWalletState.value.currentScanResponse).getOrNull() ?: return@launch
analyticsHandler.send(Basic.ButtonSupport(source = AnalyticsParam.ScreensSources.Onboarding))
sendFeedbackEmailUseCase(FeedbackEmailType.DirectUserRequest(cardInfo)) sendFeedbackEmailUseCase(FeedbackEmailType.DirectUserRequest(cardInfo))
} }
} }

View file

@ -4,7 +4,9 @@ import androidx.compose.runtime.Stable
import arrow.core.getOrElse import arrow.core.getOrElse
import com.tangem.common.CompletionResult import com.tangem.common.CompletionResult
import com.tangem.common.core.TangemSdkError import com.tangem.common.core.TangemSdkError
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.model.ParamsContainer
@ -48,6 +50,7 @@ internal class MultiWalletUpgradeWalletModel @Inject constructor(
private val saveWalletUseCase: SaveWalletUseCase, private val saveWalletUseCase: SaveWalletUseCase,
private val getUserWalletUseCase: GetUserWalletUseCase, private val getUserWalletUseCase: GetUserWalletUseCase,
private val exportSeedPhraseUseCase: ExportSeedPhraseUseCase, private val exportSeedPhraseUseCase: ExportSeedPhraseUseCase,
private val analyticsEventHandler: AnalyticsEventHandler,
) : Model() { ) : Model() {
private val params = paramsContainer.require<MultiWalletChildParams>() private val params = paramsContainer.require<MultiWalletChildParams>()
@ -179,6 +182,7 @@ internal class MultiWalletUpgradeWalletModel @Inject constructor(
modelScope.launch { modelScope.launch {
val cardInfo = val cardInfo =
getWalletMetaInfoUseCase(multiWalletState.value.currentScanResponse).getOrNull() ?: return@launch getWalletMetaInfoUseCase(multiWalletState.value.currentScanResponse).getOrNull() ?: return@launch
analyticsEventHandler.send(Basic.ButtonSupport(source = AnalyticsParam.ScreensSources.Onboarding))
sendFeedbackEmailUseCase(FeedbackEmailType.DirectUserRequest(cardInfo)) sendFeedbackEmailUseCase(FeedbackEmailType.DirectUserRequest(cardInfo))
} }
} }

View file

@ -8,6 +8,8 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.arkivanov.essenty.instancekeeper.getOrCreateSimple import com.arkivanov.essenty.instancekeeper.getOrCreateSimple
import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsEvent import com.tangem.core.analytics.models.AnalyticsEvent
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.domain.card.common.TapWorkarounds.isVisa import com.tangem.domain.card.common.TapWorkarounds.isVisa
import com.tangem.domain.feedback.GetWalletMetaInfoUseCase import com.tangem.domain.feedback.GetWalletMetaInfoUseCase
@ -45,6 +47,7 @@ internal class DefaultOnboardingStepperComponent @AssistedInject constructor(
val cardInfo = getWalletMetaInfoUseCase(params.scanResponse).getOrNull() ?: return@launch val cardInfo = getWalletMetaInfoUseCase(params.scanResponse).getOrNull() ?: return@launch
val userWalletId = cardInfo.userWalletId val userWalletId = cardInfo.userWalletId
val visaCustomerId = userWalletId?.let { id -> getTangemPayCustomerIdUseCase(id).getOrNull() } val visaCustomerId = userWalletId?.let { id -> getTangemPayCustomerIdUseCase(id).getOrNull() }
analyticsHandler.send(Basic.ButtonSupport(source = AnalyticsParam.ScreensSources.Onboarding))
sendFeedbackEmailUseCase( sendFeedbackEmailUseCase(
if (params.scanResponse.card.isVisa && !visaCustomerId.isNullOrEmpty()) { if (params.scanResponse.card.isVisa && !visaCustomerId.isNullOrEmpty()) {
FeedbackEmailType.Visa.Activation(walletMetaInfo = cardInfo, customerId = visaCustomerId) FeedbackEmailType.Visa.Activation(walletMetaInfo = cardInfo, customerId = visaCustomerId)

View file

@ -9,6 +9,7 @@ import com.tangem.common.extensions.hexToBytes
import com.tangem.common.extensions.toHexString import com.tangem.common.extensions.toHexString
import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.model.ParamsContainer
@ -358,6 +359,9 @@ internal class OnboardingTwinModel @Inject constructor(
errorDescription = resourceReference(id = resId, resArgs.toWrappedList()), errorDescription = resourceReference(id = resId, resArgs.toWrappedList()),
onRequestSupport = { onRequestSupport = {
modelScope.launch { modelScope.launch {
analyticsEventHandler.send(
Basic.ButtonSupport(source = AnalyticsParam.ScreensSources.Onboarding),
)
sendFeedbackEmailUseCase(type = FeedbackEmailType.CardAttestationFailed) sendFeedbackEmailUseCase(type = FeedbackEmailType.CardAttestationFailed)
} }
}, },

View file

@ -13,6 +13,8 @@ import com.tangem.common.ui.navigationButtons.NavigationButton
import com.tangem.common.ui.navigationButtons.NavigationUM import com.tangem.common.ui.navigationButtons.NavigationUM
import com.tangem.common.ui.userwallet.ext.walletInterationIcon import com.tangem.common.ui.userwallet.ext.walletInterationIcon
import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.model.ParamsContainer
@ -295,6 +297,7 @@ internal class SendConfirmModel @Inject constructor(
modelScope.launch { modelScope.launch {
val metaInfo = getWalletMetaInfoUseCase.invoke(userWallet.walletId).getOrNull() ?: return@launch val metaInfo = getWalletMetaInfoUseCase.invoke(userWallet.walletId).getOrNull() ?: return@launch
analyticsEventHandler.send(Basic.ButtonSupport(source = AnalyticsParam.ScreensSources.Send))
sendFeedbackEmailUseCase(type = FeedbackEmailType.TransactionSendingProblem(walletMetaInfo = metaInfo)) sendFeedbackEmailUseCase(type = FeedbackEmailType.TransactionSendingProblem(walletMetaInfo = metaInfo))
} }
} }

View file

@ -9,6 +9,8 @@ import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.common.ui.amountScreen.models.AmountState import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.common.ui.navigationButtons.NavigationUM import com.tangem.common.ui.navigationButtons.NavigationUM
import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.model.ParamsContainer
@ -426,6 +428,7 @@ internal class SendModel @Inject constructor(
modelScope.launch { modelScope.launch {
val metaInfo = getWalletMetaInfoUseCase(userWallet.walletId).getOrNull() ?: return@launch val metaInfo = getWalletMetaInfoUseCase(userWallet.walletId).getOrNull() ?: return@launch
analyticsEventHandler.send(Basic.ButtonSupport(source = AnalyticsParam.ScreensSources.Send))
sendFeedbackEmailUseCase(type = FeedbackEmailType.TransactionSendingProblem(walletMetaInfo = metaInfo)) sendFeedbackEmailUseCase(type = FeedbackEmailType.TransactionSendingProblem(walletMetaInfo = metaInfo))
} }
} }

View file

@ -8,6 +8,8 @@ import com.tangem.common.ui.navigationButtons.NavigationButton
import com.tangem.common.ui.navigationButtons.NavigationUM import com.tangem.common.ui.navigationButtons.NavigationUM
import com.tangem.common.ui.userwallet.ext.walletInterationIcon import com.tangem.common.ui.userwallet.ext.walletInterationIcon
import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.model.ParamsContainer
@ -202,6 +204,7 @@ internal class NFTSendConfirmModel @Inject constructor(
modelScope.launch { modelScope.launch {
val metaInfo = getWalletMetaInfoUseCase(userWallet.walletId).getOrNull() ?: return@launch val metaInfo = getWalletMetaInfoUseCase(userWallet.walletId).getOrNull() ?: return@launch
analyticsEventHandler.send(Basic.ButtonSupport(source = AnalyticsParam.ScreensSources.Send))
sendFeedbackEmailUseCase(type = FeedbackEmailType.TransactionSendingProblem(walletMetaInfo = metaInfo)) sendFeedbackEmailUseCase(type = FeedbackEmailType.TransactionSendingProblem(walletMetaInfo = metaInfo))
} }
} }

View file

@ -6,6 +6,9 @@ import arrow.core.getOrElse
import arrow.core.left import arrow.core.left
import com.tangem.blockchain.common.transaction.TransactionFee import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.common.ui.navigationButtons.NavigationUM import com.tangem.common.ui.navigationButtons.NavigationUM
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.model.ParamsContainer
@ -73,6 +76,7 @@ internal class NFTSendModel @Inject constructor(
private val nftSendSuccessTrigger: NFTSendSuccessTrigger, private val nftSendSuccessTrigger: NFTSendSuccessTrigger,
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase, private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
private val getAccountCurrencyStatusUseCase: GetAccountCurrencyStatusUseCase, private val getAccountCurrencyStatusUseCase: GetAccountCurrencyStatusUseCase,
private val analyticsEventHandler: AnalyticsEventHandler,
) : Model(), SendNFTComponentCallback, NFTSendSuccessComponent.ModelCallback { ) : Model(), SendNFTComponentCallback, NFTSendSuccessComponent.ModelCallback {
val params: NFTSendComponent.Params = paramsContainer.require() val params: NFTSendComponent.Params = paramsContainer.require()
@ -230,6 +234,7 @@ internal class NFTSendModel @Inject constructor(
modelScope.launch { modelScope.launch {
val metaInfo = getWalletMetaInfoUseCase(userWallet.walletId).getOrNull() ?: return@launch val metaInfo = getWalletMetaInfoUseCase(userWallet.walletId).getOrNull() ?: return@launch
analyticsEventHandler.send(Basic.ButtonSupport(source = AnalyticsParam.ScreensSources.Send))
sendFeedbackEmailUseCase(type = FeedbackEmailType.TransactionSendingProblem(walletMetaInfo = metaInfo)) sendFeedbackEmailUseCase(type = FeedbackEmailType.TransactionSendingProblem(walletMetaInfo = metaInfo))
} }
} }

View file

@ -20,6 +20,8 @@ import com.tangem.features.approval.api.GiveApprovalFeatureToggles
import com.tangem.common.ui.notifications.NotificationUM import com.tangem.common.ui.notifications.NotificationUM
import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.api.ParamsInterceptorHolder import com.tangem.core.analytics.api.ParamsInterceptorHolder
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.model.ParamsContainer
@ -1080,6 +1082,7 @@ internal class StakingModel @Inject constructor(
unsignedTransactions = transactionsInProgress.map { it.unsignedTransaction }, unsignedTransactions = transactionsInProgress.map { it.unsignedTransaction },
) )
analyticsEventHandler.send(Basic.ButtonSupport(source = AnalyticsParam.ScreensSources.Staking))
sendFeedbackEmailUseCase(email) sendFeedbackEmailUseCase(email)
} }
} }

View file

@ -1,6 +1,9 @@
package com.tangem.features.swap.v2.impl.common package com.tangem.features.swap.v2.impl.common
import com.tangem.common.ui.alerts.TransactionErrorDialogFactory import com.tangem.common.ui.alerts.TransactionErrorDialogFactory
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.resourceReference
@ -25,6 +28,7 @@ internal class SwapAlertFactory @Inject constructor(
private val getWalletMetaInfoUseCase: GetWalletMetaInfoUseCase, private val getWalletMetaInfoUseCase: GetWalletMetaInfoUseCase,
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase, private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
private val transactionErrorDialogFactory: TransactionErrorDialogFactory, private val transactionErrorDialogFactory: TransactionErrorDialogFactory,
private val analyticsEventHandler: AnalyticsEventHandler,
) { ) {
fun getGenericErrorState(expressError: ExpressError, onFailedTxEmailClick: () -> Unit, popBack: () -> Unit = {}) { fun getGenericErrorState(expressError: ExpressError, onFailedTxEmailClick: () -> Unit, popBack: () -> Unit = {}) {
uiMessageSender.send( uiMessageSender.send(
@ -83,6 +87,7 @@ internal class SwapAlertFactory @Inject constructor(
val metaInfo = getWalletMetaInfoUseCase(userWallet.walletId).getOrNull() ?: return val metaInfo = getWalletMetaInfoUseCase(userWallet.walletId).getOrNull() ?: return
analyticsEventHandler.send(Basic.ButtonSupport(source = AnalyticsParam.ScreensSources.Swap))
sendFeedbackEmailUseCase( sendFeedbackEmailUseCase(
type = FeedbackEmailType.SwapProblem( type = FeedbackEmailType.SwapProblem(
walletMetaInfo = metaInfo, walletMetaInfo = metaInfo,

View file

@ -1648,6 +1648,7 @@ internal class SwapModel @Inject constructor(
providerName = dataState.selectedProvider?.name.orEmpty(), providerName = dataState.selectedProvider?.name.orEmpty(),
txId = txId, txId = txId,
) )
analyticsEventHandler.send(Basic.ButtonSupport(source = ScreensSources.Swap))
sendFeedbackEmailUseCase(email) sendFeedbackEmailUseCase(email)
} }
} }
@ -2179,6 +2180,7 @@ internal class SwapModel @Inject constructor(
txId = transaction?.txId.orEmpty(), txId = transaction?.txId.orEmpty(),
) )
analyticsEventHandler.send(Basic.ButtonSupport(source = ScreensSources.Swap))
sendFeedbackEmailUseCase(email) sendFeedbackEmailUseCase(email)
} }
} }

View file

@ -7,6 +7,7 @@ import com.arkivanov.decompose.router.slot.dismiss
import com.tangem.common.routing.AppRoute import com.tangem.common.routing.AppRoute
import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.model.ParamsContainer
@ -380,6 +381,7 @@ internal class TangemPayDetailsModel @Inject constructor(
override fun onContactSupportClicked() { override fun onContactSupportClicked() {
analytics.send(TangemPayAnalyticsEvents.GoToSupportOnBetaBannerClicked()) analytics.send(TangemPayAnalyticsEvents.GoToSupportOnBetaBannerClicked())
analytics.send(Basic.ButtonSupport(source = AnalyticsParam.ScreensSources.TangemPay))
modelScope.launch { modelScope.launch {
sendFeedbackEmailUseCase.invoke( sendFeedbackEmailUseCase.invoke(
type = FeedbackEmailType.Visa.FeatureIsBeta( type = FeedbackEmailType.Visa.FeatureIsBeta(

View file

@ -2,6 +2,8 @@ package com.tangem.features.tangempay.model
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.model.ParamsContainer
@ -66,6 +68,7 @@ internal class TangemPayTxHistoryDetailsModel @Inject constructor(
private fun dispute(customerId: String) { private fun dispute(customerId: String) {
analytics.send(TangemPayAnalyticsEvents.SupportOnTransactionPopupClicked()) analytics.send(TangemPayAnalyticsEvents.SupportOnTransactionPopupClicked())
analytics.send(Basic.ButtonSupport(source = AnalyticsParam.ScreensSources.TangemPay))
modelScope.launch { modelScope.launch {
val walletMetaInfo = getWalletMetaInfoUseCase.invoke(params.userWalletId).getOrNull() ?: return@launch val walletMetaInfo = getWalletMetaInfoUseCase.invoke(params.userWalletId).getOrNull() ?: return@launch

View file

@ -122,7 +122,8 @@ internal class ExpressStatusFactory @AssistedInject constructor(
val analyticEvents = when (expressState) { val analyticEvents = when (expressState) {
is ExchangeUM -> listOfNotNull( is ExchangeUM -> listOfNotNull(
TokenExchangeAnalyticsEvent.CexTxStatusOpened( TokenExchangeAnalyticsEvent.CexTxStatusOpened(
cryptoCurrency.symbol, token = cryptoCurrency.symbol,
provider = expressState.provider.name,
), ),
maybeGetLongTimeExchangeNotificationShowEvent( maybeGetLongTimeExchangeNotificationShowEvent(
expressState = expressState, expressState = expressState,

View file

@ -118,7 +118,8 @@ internal class TokenDetailsExpressStatusFactory @AssistedInject constructor(
val analyticEvents = when (expressState) { val analyticEvents = when (expressState) {
is ExchangeUM -> listOfNotNull( is ExchangeUM -> listOfNotNull(
TokenExchangeAnalyticsEvent.CexTxStatusOpened( TokenExchangeAnalyticsEvent.CexTxStatusOpened(
cryptoCurrency.symbol, token = cryptoCurrency.symbol,
provider = expressState.provider.name,
), ),
maybeGetLongTimeExchangeNotificationShowEvent( maybeGetLongTimeExchangeNotificationShowEvent(
expressState = expressState, expressState = expressState,

View file

@ -2,6 +2,9 @@ package com.tangem.feature.wallet.child.wallet.model.intents
import com.arkivanov.decompose.router.slot.activate import com.arkivanov.decompose.router.slot.activate
import com.tangem.common.routing.AppRoute import com.tangem.common.routing.AppRoute
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.res.R import com.tangem.core.res.R
@ -71,6 +74,7 @@ internal class TangemPayClickIntentsImplementor @Inject constructor(
private val tangemPayOnboardingRepository: OnboardingRepository, private val tangemPayOnboardingRepository: OnboardingRepository,
private val tangemPayEligibilityManager: TangemPayEligibilityManager, private val tangemPayEligibilityManager: TangemPayEligibilityManager,
private val uiMessageSender: UiMessageSender, private val uiMessageSender: UiMessageSender,
private val analyticsEventHandler: AnalyticsEventHandler,
) : BaseWalletClickIntents(), TangemPayIntents { ) : BaseWalletClickIntents(), TangemPayIntents {
override suspend fun onPullToRefresh() { override suspend fun onPullToRefresh() {
@ -169,6 +173,7 @@ internal class TangemPayClickIntentsImplementor @Inject constructor(
private fun goToSupportForRejectKyc(customerId: String) { private fun goToSupportForRejectKyc(customerId: String) {
modelScope.launch { modelScope.launch {
analyticsEventHandler.send(Basic.ButtonSupport(source = AnalyticsParam.ScreensSources.TangemPay))
sendFeedbackEmailUseCase( sendFeedbackEmailUseCase(
type = FeedbackEmailType.Visa.KycRejected( type = FeedbackEmailType.Visa.KycRejected(
walletMetaInfo = WalletMetaInfo( walletMetaInfo = WalletMetaInfo(
@ -227,6 +232,7 @@ internal class TangemPayClickIntentsImplementor @Inject constructor(
userWalletId = stateHolder.getSelectedWalletId(), userWalletId = stateHolder.getSelectedWalletId(),
).getOrNull() ?: return@launch ).getOrNull() ?: return@launch
analyticsEventHandler.send(Basic.ButtonSupport(source = AnalyticsParam.ScreensSources.TangemPay))
sendFeedbackEmailUseCase( sendFeedbackEmailUseCase(
FeedbackEmailType.Visa.FailedIssueCard( FeedbackEmailType.Visa.FailedIssueCard(
walletMetaInfo = cardInfo, walletMetaInfo = cardInfo,

View file

@ -8,6 +8,7 @@ import com.tangem.common.ui.notifications.NotificationId
import com.tangem.common.ui.userwallet.handle import com.tangem.common.ui.userwallet.handle
import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic.ButtonSupport
import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.navigation.url.UrlOpener import com.tangem.core.navigation.url.UrlOpener
@ -234,6 +235,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
val userWallet = getSelectedUserWallet() ?: return@launch val userWallet = getSelectedUserWallet() ?: return@launch
val cardInfo = getWalletMetaInfoUseCase(userWallet.walletId).getOrNull() ?: return@launch val cardInfo = getWalletMetaInfoUseCase(userWallet.walletId).getOrNull() ?: return@launch
analyticsEventHandler.send(ButtonSupport(source = AnalyticsParam.ScreensSources.Main))
sendFeedbackEmailUseCase(type = FeedbackEmailType.RateCanBeBetter(walletMetaInfo = cardInfo)) sendFeedbackEmailUseCase(type = FeedbackEmailType.RateCanBeBetter(walletMetaInfo = cardInfo))
} }
} }
@ -336,6 +338,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
modelScope.launch { modelScope.launch {
val metaInfo = getWalletMetaInfoUseCase(userWallet.walletId).getOrNull() ?: return@launch val metaInfo = getWalletMetaInfoUseCase(userWallet.walletId).getOrNull() ?: return@launch
analyticsEventHandler.send(ButtonSupport(source = AnalyticsParam.ScreensSources.Main))
sendFeedbackEmailUseCase(type = FeedbackEmailType.DirectUserRequest(walletMetaInfo = metaInfo)) sendFeedbackEmailUseCase(type = FeedbackEmailType.DirectUserRequest(walletMetaInfo = metaInfo))
} }
} }
@ -345,6 +348,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
modelScope.launch { modelScope.launch {
val metaInfo = getWalletMetaInfoUseCase(userWallet.walletId).getOrNull() ?: return@launch val metaInfo = getWalletMetaInfoUseCase(userWallet.walletId).getOrNull() ?: return@launch
analyticsEventHandler.send(ButtonSupport(source = AnalyticsParam.ScreensSources.Main))
sendFeedbackEmailUseCase(type = FeedbackEmailType.BackupProblem(walletMetaInfo = metaInfo)) sendFeedbackEmailUseCase(type = FeedbackEmailType.BackupProblem(walletMetaInfo = metaInfo))
} }
} }