Updated on 2026-08-14
This commit is contained in:
parent
e73c7b7426
commit
0727b381ca
16 changed files with 277 additions and 18 deletions
|
|
@ -22,9 +22,35 @@ sealed class MainScreenAnalyticsEvent(
|
|||
)
|
||||
|
||||
// region Action Buttons feature
|
||||
data class ButtonBuy(val status: AnalyticsParam.Status) : MainScreenAnalyticsEvent(
|
||||
data class ButtonBuy(
|
||||
val status: AnalyticsParam.Status,
|
||||
val screenType: String? = null,
|
||||
) : MainScreenAnalyticsEvent(
|
||||
event = "Button - Buy",
|
||||
params = mapOf(AnalyticsParam.STATUS to status.value),
|
||||
params = buildMap {
|
||||
put(AnalyticsParam.STATUS, status.value)
|
||||
screenType?.let { put(AnalyticsParam.TYPE, it) }
|
||||
},
|
||||
)
|
||||
|
||||
data object ButtonReceive : MainScreenAnalyticsEvent(
|
||||
event = "Button - Receive",
|
||||
)
|
||||
|
||||
data object LimitsClicked : MainScreenAnalyticsEvent(
|
||||
event = "Limits Clicked",
|
||||
)
|
||||
|
||||
data object NoticeBalancesInfo : MainScreenAnalyticsEvent(
|
||||
event = "Notice - Balances Info",
|
||||
)
|
||||
|
||||
data object NoticeLimitsInfo : MainScreenAnalyticsEvent(
|
||||
event = "Notice - Limits Info",
|
||||
)
|
||||
|
||||
data object ButtonExplore : MainScreenAnalyticsEvent(
|
||||
event = "Button - Explore",
|
||||
)
|
||||
|
||||
data class ButtonSwap(val status: AnalyticsParam.Status) : MainScreenAnalyticsEvent(
|
||||
|
|
@ -83,4 +109,9 @@ sealed class MainScreenAnalyticsEvent(
|
|||
params = mapOf(ERROR_CODE to errorCode),
|
||||
)
|
||||
// endregion
|
||||
|
||||
companion object {
|
||||
const val VISA_TYPE = "Visa"
|
||||
const val WALLET_TYPE = "Wallet"
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import com.arkivanov.decompose.router.stack.StackNavigation
|
|||
import com.arkivanov.decompose.router.stack.replaceAll
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
|
|
@ -12,7 +13,6 @@ import com.tangem.core.decompose.ui.UiMessageSender
|
|||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
|
|
@ -29,6 +29,7 @@ import com.tangem.features.onboarding.v2.entry.impl.analytics.OnboardingEntryEve
|
|||
import com.tangem.features.onboarding.v2.entry.impl.routing.OnboardingRoute
|
||||
import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent
|
||||
import com.tangem.features.onboarding.v2.twin.api.OnboardingTwinComponent
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.welcome.model.analytics.OnboardingVisaAnalyticsEvent
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.NonCancellable
|
||||
|
|
@ -150,10 +151,16 @@ internal class OnboardingEntryModel @Inject constructor(
|
|||
if (askBiometryFeatureToggles.isAskForBiometryEnabled) {
|
||||
modelScope.launch {
|
||||
if (tangemSdkManager.checkCanUseBiometry() && settingsRepository.shouldShowSaveUserWalletScreen()) {
|
||||
doIfVisa {
|
||||
analyticsEventHandler.send(OnboardingVisaAnalyticsEvent.BiometricScreenOpened)
|
||||
}
|
||||
stackNavigation.replaceAll(
|
||||
OnboardingRoute.AskBiometry(modelCallbacks = AskBiometryModelCallbacks(doneMode)),
|
||||
)
|
||||
} else {
|
||||
doIfVisa {
|
||||
analyticsEventHandler.send(OnboardingVisaAnalyticsEvent.SuccessScreenOpened)
|
||||
}
|
||||
stackNavigation.replaceAll(
|
||||
OnboardingRoute.Done(
|
||||
mode = doneMode,
|
||||
|
|
@ -163,6 +170,9 @@ internal class OnboardingEntryModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
doIfVisa {
|
||||
analyticsEventHandler.send(OnboardingVisaAnalyticsEvent.SuccessScreenOpened)
|
||||
}
|
||||
stackNavigation.replaceAll(
|
||||
OnboardingRoute.Done(
|
||||
mode = doneMode,
|
||||
|
|
@ -177,6 +187,9 @@ internal class OnboardingEntryModel @Inject constructor(
|
|||
) : AskBiometryComponent.ModelCallbacks {
|
||||
override fun onAllowed() {
|
||||
analyticsEventHandler.send(OnboardingEntryEvent.Biometric(OnboardingEntryEvent.Biometric.State.On))
|
||||
doIfVisa {
|
||||
analyticsEventHandler.send(OnboardingVisaAnalyticsEvent.SuccessScreenOpened)
|
||||
}
|
||||
stackNavigation.replaceAll(
|
||||
OnboardingRoute.Done(
|
||||
mode = doneMode,
|
||||
|
|
@ -187,6 +200,9 @@ internal class OnboardingEntryModel @Inject constructor(
|
|||
|
||||
override fun onDenied() {
|
||||
analyticsEventHandler.send(OnboardingEntryEvent.Biometric(OnboardingEntryEvent.Biometric.State.Off))
|
||||
doIfVisa {
|
||||
analyticsEventHandler.send(OnboardingVisaAnalyticsEvent.SuccessScreenOpened)
|
||||
}
|
||||
stackNavigation.replaceAll(
|
||||
OnboardingRoute.Done(
|
||||
mode = doneMode,
|
||||
|
|
@ -232,6 +248,12 @@ internal class OnboardingEntryModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private inline fun doIfVisa(function: () -> Unit) {
|
||||
if (params.scanResponse.productType == ProductType.Visa) {
|
||||
function()
|
||||
}
|
||||
}
|
||||
|
||||
inner class OnboardingTwinModelCallbacks : OnboardingTwinComponent.ModelCallbacks {
|
||||
override fun onDone() {
|
||||
navigateToFinalScreenFlow()
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import androidx.compose.runtime.Stable
|
|||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
|
|
@ -19,6 +20,9 @@ import com.tangem.domain.visa.repository.VisaActivationRepository
|
|||
import com.tangem.domain.visa.repository.VisaAuthRepository
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.accesscode.OnboardingVisaAccessCodeComponent
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.accesscode.ui.state.OnboardingVisaAccessCodeUM
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.welcome.model.analytics.ONBOARDING_SOURCE
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.welcome.model.analytics.OnboardingVisaAnalyticsEvent
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.welcome.model.analytics.VisaAnalyticsEvent
|
||||
import com.tangem.features.onboarding.v2.visa.impl.common.ActivationReadyEvent
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
import com.tangem.sdk.api.visa.VisaCardActivationTaskMode
|
||||
|
|
@ -30,6 +34,7 @@ import kotlinx.coroutines.flow.update
|
|||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Stable
|
||||
@ModelScoped
|
||||
internal class OnboardingVisaAccessCodeModel @Inject constructor(
|
||||
|
|
@ -40,6 +45,7 @@ internal class OnboardingVisaAccessCodeModel @Inject constructor(
|
|||
private val tangemSdkManager: TangemSdkManager,
|
||||
private val visaAuthRepository: VisaAuthRepository,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
private val analyticsEventsHandler: AnalyticsEventHandler,
|
||||
) : Model() {
|
||||
|
||||
private val params: OnboardingVisaAccessCodeComponent.Config = paramsContainer.require()
|
||||
|
|
@ -59,6 +65,10 @@ internal class OnboardingVisaAccessCodeModel @Inject constructor(
|
|||
val onBack = MutableSharedFlow<Unit>()
|
||||
val onDone = MutableSharedFlow<ActivationReadyEvent>()
|
||||
|
||||
init {
|
||||
analyticsEventsHandler.send(OnboardingVisaAnalyticsEvent.SettingAccessCodeStarted)
|
||||
}
|
||||
|
||||
fun onBack() {
|
||||
if (uiState.value.buttonLoading) return
|
||||
|
||||
|
|
@ -99,11 +109,14 @@ internal class OnboardingVisaAccessCodeModel @Inject constructor(
|
|||
private fun onContinue() {
|
||||
when (uiState.value.step) {
|
||||
OnboardingVisaAccessCodeUM.Step.Enter -> {
|
||||
analyticsEventsHandler.send(OnboardingVisaAnalyticsEvent.AccessCodeEntered)
|
||||
if (checkAccessCodeMinChars().not()) return
|
||||
_uiState.update { it.copy(step = OnboardingVisaAccessCodeUM.Step.ReEnter) }
|
||||
analyticsEventsHandler.send(OnboardingVisaAnalyticsEvent.AccessCodeReenterScreen)
|
||||
}
|
||||
OnboardingVisaAccessCodeUM.Step.ReEnter -> {
|
||||
if (checkAccessCodesMatch().not()) return
|
||||
analyticsEventsHandler.send(OnboardingVisaAnalyticsEvent.OnboardingVisa)
|
||||
startActivationProcess(accessCode = uiState.value.accessCodeFirst.text)
|
||||
}
|
||||
}
|
||||
|
|
@ -160,6 +173,9 @@ internal class OnboardingVisaAccessCodeModel @Inject constructor(
|
|||
is CompletionResult.Failure -> {
|
||||
loading(false)
|
||||
uiMessageSender.showErrorDialog(result.error.universalError)
|
||||
analyticsEventsHandler.send(
|
||||
VisaAnalyticsEvent.Errors(result.error.code.toString(), ONBOARDING_SOURCE),
|
||||
)
|
||||
return@launch
|
||||
}
|
||||
is CompletionResult.Success -> result.data
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.features.onboarding.v2.visa.impl.child.approve.model
|
|||
import androidx.compose.runtime.Stable
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
|
|
@ -15,6 +16,9 @@ import com.tangem.domain.visa.model.VisaDataForApprove
|
|||
import com.tangem.domain.visa.repository.VisaActivationRepository
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.approve.OnboardingVisaApproveComponent
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.approve.ui.state.OnboardingVisaApproveUM
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.welcome.model.analytics.ONBOARDING_SOURCE
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.welcome.model.analytics.OnboardingVisaAnalyticsEvent
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.welcome.model.analytics.VisaAnalyticsEvent
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
|
|
@ -32,6 +36,7 @@ internal class OnboardingVisaApproveModel @Inject constructor(
|
|||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val tangemSdkManager: TangemSdkManager,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<OnboardingVisaApproveComponent.Config>()
|
||||
|
|
@ -47,6 +52,10 @@ internal class OnboardingVisaApproveModel @Inject constructor(
|
|||
val uiState = _uiState.asStateFlow()
|
||||
val onDone = MutableSharedFlow<Unit>()
|
||||
|
||||
init {
|
||||
analyticsEventHandler.send(OnboardingVisaAnalyticsEvent.WalletPrepare)
|
||||
}
|
||||
|
||||
private fun getInitialState(): OnboardingVisaApproveUM {
|
||||
return OnboardingVisaApproveUM(
|
||||
onApproveClick = ::onApproveClick,
|
||||
|
|
@ -56,6 +65,8 @@ internal class OnboardingVisaApproveModel @Inject constructor(
|
|||
private fun onApproveClick() {
|
||||
loading(true)
|
||||
|
||||
analyticsEventHandler.send(OnboardingVisaAnalyticsEvent.ButtonApprove)
|
||||
|
||||
modelScope.launch {
|
||||
val dataToSign = runCatching {
|
||||
visaActivationRepository.getCustomerWalletAcceptanceData(params.preparationDataForApprove.request)
|
||||
|
|
@ -77,6 +88,9 @@ internal class OnboardingVisaApproveModel @Inject constructor(
|
|||
is CompletionResult.Failure -> {
|
||||
loading(false)
|
||||
uiMessageSender.showErrorDialog(result.error.universalError)
|
||||
analyticsEventHandler.send(
|
||||
VisaAnalyticsEvent.Errors(result.error.code.toString(), ONBOARDING_SOURCE),
|
||||
)
|
||||
return@launch
|
||||
}
|
||||
is CompletionResult.Success -> result.data
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.features.onboarding.v2.visa.impl.child.choosewallet.model
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
|
|
@ -8,6 +9,7 @@ import com.tangem.features.onboarding.v2.impl.R
|
|||
import com.tangem.features.onboarding.v2.visa.impl.child.choosewallet.OnboardingVisaChooseWalletComponent.Params.Event
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.choosewallet.ui.state.OnboardingVisaChooseWalletUM
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.choosewallet.ui.state.SelectableChainRowUM
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.welcome.model.analytics.OnboardingVisaAnalyticsEvent
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
|
|
@ -21,6 +23,7 @@ import javax.inject.Inject
|
|||
@ModelScoped
|
||||
internal class OnboardingVisaChooseWalletModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
) : Model() {
|
||||
|
||||
private val _uiState = MutableStateFlow(getInitialState())
|
||||
|
|
@ -53,7 +56,18 @@ internal class OnboardingVisaChooseWalletModel @Inject constructor(
|
|||
private fun onContinueClicked() {
|
||||
modelScope.launch {
|
||||
val selectedOption = _uiState.value.selectedOption ?: return@launch
|
||||
val value = getAnalyticsValue(selectedOption.event)
|
||||
analyticsEventHandler.send(OnboardingVisaAnalyticsEvent.ChooseWalletScreen(value))
|
||||
onEvent.emit(selectedOption.event)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAnalyticsValue(event: Event) = when (event) {
|
||||
Event.TangemWallet -> {
|
||||
"Tangem"
|
||||
}
|
||||
Event.OtherWallet -> {
|
||||
"Other"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.tangem.features.onboarding.v2.visa.impl.child.inprogress.model
|
|||
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
|
|
@ -20,6 +21,7 @@ import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
|||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.inprogress.OnboardingVisaInProgressComponent.Config
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.inprogress.OnboardingVisaInProgressComponent.Params
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.welcome.model.analytics.OnboardingVisaAnalyticsEvent
|
||||
import com.tangem.features.onboarding.v2.visa.impl.route.OnboardingVisaRoute
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.delay
|
||||
|
|
@ -41,6 +43,7 @@ internal class OnboardingVisaInProgressModel @Inject constructor(
|
|||
private val userWalletBuilderFactory: UserWalletBuilder.Factory,
|
||||
private val userWalletsListManager: UserWalletsListManager,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<Config>()
|
||||
|
|
@ -53,6 +56,7 @@ internal class OnboardingVisaInProgressModel @Inject constructor(
|
|||
val onDone = MutableSharedFlow<Params.DoneEvent>()
|
||||
|
||||
init {
|
||||
analyticsEventHandler.send(OnboardingVisaAnalyticsEvent.ActivationInProgressScreen)
|
||||
modelScope.launch {
|
||||
while (true) {
|
||||
val result = runCatching {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.features.onboarding.v2.visa.impl.child.otherwallet.model
|
|||
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
|
|
@ -13,6 +14,7 @@ import com.tangem.domain.visa.model.VisaCardId
|
|||
import com.tangem.domain.visa.repository.VisaActivationRepository
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.otherwallet.OnboardingVisaOtherWalletComponent
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.otherwallet.ui.state.OnboardingVisaOtherWalletUM
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.welcome.model.analytics.OnboardingVisaAnalyticsEvent
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
|
|
@ -29,6 +31,7 @@ internal class OnboardingVisaOtherWalletModel @Inject constructor(
|
|||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val urlOpener: UrlOpener,
|
||||
private val shareManager: ShareManager,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
) : Model() {
|
||||
|
||||
private val config = paramsContainer.require<OnboardingVisaOtherWalletComponent.Config>()
|
||||
|
|
@ -44,6 +47,7 @@ internal class OnboardingVisaOtherWalletModel @Inject constructor(
|
|||
val onDone = MutableSharedFlow<VisaActivationOrderInfo>()
|
||||
|
||||
init {
|
||||
analyticsEventHandler.send(OnboardingVisaAnalyticsEvent.GoToWebsiteOpened)
|
||||
modelScope.launch {
|
||||
while (true) {
|
||||
val result = runCatching {
|
||||
|
|
@ -68,10 +72,12 @@ internal class OnboardingVisaOtherWalletModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun onShareClicked() {
|
||||
analyticsEventHandler.send(OnboardingVisaAnalyticsEvent.ButtonShareLink)
|
||||
shareManager.shareText("https://tangem.com/") // TODO
|
||||
}
|
||||
|
||||
private fun onOpenInBrowserClicked() {
|
||||
analyticsEventHandler.send(OnboardingVisaAnalyticsEvent.ButtonBrowser)
|
||||
urlOpener.openUrl("https://tangem.com/") // TODO
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.tangem.features.onboarding.v2.visa.impl.child.pincode.model
|
|||
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
|
|
@ -17,6 +18,7 @@ import com.tangem.domain.wallets.models.UserWallet
|
|||
import com.tangem.features.onboarding.v2.impl.R
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.pincode.OnboardingVisaPinCodeComponent
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.pincode.ui.state.OnboardingVisaPinCodeUM
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.welcome.model.analytics.OnboardingVisaAnalyticsEvent
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
|
@ -37,6 +39,7 @@ internal class OnboardingVisaPinCodeModel @Inject constructor(
|
|||
private val authTokenStorage: VisaAuthTokenStorage,
|
||||
private val otpStorage: VisaAuthTokenStorage,
|
||||
private val setVisaPinCodeUseCase: SetVisaPinCodeUseCase,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<OnboardingVisaPinCodeComponent.Config>()
|
||||
|
|
@ -49,6 +52,10 @@ internal class OnboardingVisaPinCodeModel @Inject constructor(
|
|||
val uiState = _uiState.asStateFlow()
|
||||
val onDone = MutableSharedFlow<Unit>()
|
||||
|
||||
init {
|
||||
analyticsEventHandler.send(OnboardingVisaAnalyticsEvent.PinCodeScreenOpened)
|
||||
}
|
||||
|
||||
private fun getInitialState(): OnboardingVisaPinCodeUM {
|
||||
return OnboardingVisaPinCodeUM(
|
||||
submitButtonEnabled = false,
|
||||
|
|
@ -66,6 +73,7 @@ internal class OnboardingVisaPinCodeModel @Inject constructor(
|
|||
pinCode = pin,
|
||||
submitButtonEnabled = PinCodeValidation.validate(pin),
|
||||
error = if (isError) {
|
||||
analyticsEventHandler.send(OnboardingVisaAnalyticsEvent.ErrorPinValidation)
|
||||
resourceReference(R.string.visa_onboarding_pin_validation_error_message)
|
||||
} else {
|
||||
null
|
||||
|
|
@ -76,6 +84,7 @@ internal class OnboardingVisaPinCodeModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun onSubmitClick() {
|
||||
analyticsEventHandler.send(OnboardingVisaAnalyticsEvent.PinEntered)
|
||||
val pinCode = _uiState.value.pinCode
|
||||
if (PinCodeValidation.validate(pinCode).not()) return
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.features.onboarding.v2.visa.impl.child.welcome.model
|
|||
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
|
|
@ -14,6 +15,9 @@ import com.tangem.domain.visa.model.VisaCustomerWalletDataToSignRequest
|
|||
import com.tangem.domain.visa.repository.VisaActivationRepository
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.welcome.OnboardingVisaWelcomeComponent.Config
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.welcome.OnboardingVisaWelcomeComponent.DoneEvent
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.welcome.model.analytics.ONBOARDING_SOURCE
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.welcome.model.analytics.OnboardingVisaAnalyticsEvent
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.welcome.model.analytics.VisaAnalyticsEvent
|
||||
import com.tangem.features.onboarding.v2.visa.impl.child.welcome.ui.state.OnboardingVisaWelcomeUM
|
||||
import com.tangem.features.onboarding.v2.visa.impl.common.ActivationReadyEvent
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
|
|
@ -33,6 +37,7 @@ internal class OnboardingVisaWelcomeModel @Inject constructor(
|
|||
private val tangemSdkManager: TangemSdkManager,
|
||||
private val visaActivationRepositoryFactory: VisaActivationRepository.Factory,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
private val analyticsEventsHandler: AnalyticsEventHandler,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<Config>()
|
||||
|
|
@ -42,6 +47,10 @@ internal class OnboardingVisaWelcomeModel @Inject constructor(
|
|||
val uiState = _uiState.asStateFlow()
|
||||
val onDone = MutableSharedFlow<DoneEvent>()
|
||||
|
||||
init {
|
||||
analyticsEventsHandler.send(OnboardingVisaAnalyticsEvent.ActivationScreenOpened)
|
||||
}
|
||||
|
||||
private fun getInitialState(): OnboardingVisaWelcomeUM {
|
||||
return OnboardingVisaWelcomeUM(
|
||||
mode = if (params is Config.WelcomeBack) {
|
||||
|
|
@ -54,6 +63,7 @@ internal class OnboardingVisaWelcomeModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun onContinueClick() {
|
||||
analyticsEventsHandler.send(OnboardingVisaAnalyticsEvent.ButtonActivate)
|
||||
if (params !is Config.WelcomeBack) {
|
||||
modelScope.launch { onDone.emit(DoneEvent.WelcomeDone) }
|
||||
return
|
||||
|
|
@ -86,6 +96,9 @@ internal class OnboardingVisaWelcomeModel @Inject constructor(
|
|||
is CompletionResult.Failure -> {
|
||||
loading(false)
|
||||
uiMessageSender.showErrorDialog(result.error.universalError)
|
||||
analyticsEventsHandler.send(
|
||||
VisaAnalyticsEvent.Errors(result.error.code.toString(), ONBOARDING_SOURCE),
|
||||
)
|
||||
return@launch
|
||||
}
|
||||
is CompletionResult.Success -> result.data
|
||||
|
|
|
|||
|
|
@ -0,0 +1,85 @@
|
|||
package com.tangem.features.onboarding.v2.visa.impl.child.welcome.model.analytics
|
||||
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
|
||||
internal sealed class OnboardingVisaAnalyticsEvent(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
) : AnalyticsEvent("Onboarding / Visa", event, params) {
|
||||
|
||||
data object ActivationScreenOpened : OnboardingVisaAnalyticsEvent(
|
||||
event = "Activation Screen Opened",
|
||||
)
|
||||
|
||||
data object ButtonActivate : OnboardingVisaAnalyticsEvent(
|
||||
event = "Button - Activate",
|
||||
)
|
||||
|
||||
data object SettingAccessCodeStarted : OnboardingVisaAnalyticsEvent(
|
||||
event = "Setting Access Code Started",
|
||||
)
|
||||
|
||||
data object AccessCodeEntered : OnboardingVisaAnalyticsEvent(
|
||||
event = "Access Code Entered",
|
||||
)
|
||||
|
||||
data object AccessCodeReenterScreen : OnboardingVisaAnalyticsEvent(
|
||||
event = "Access Code Re-enter Screen",
|
||||
)
|
||||
|
||||
data object OnboardingVisa : OnboardingVisaAnalyticsEvent(
|
||||
event = "Onboarding / Visa",
|
||||
)
|
||||
|
||||
data class ChooseWalletScreen(
|
||||
val type: String,
|
||||
) : OnboardingVisaAnalyticsEvent(
|
||||
event = "Choose Wallet Screen",
|
||||
params = mapOf("Type" to type),
|
||||
)
|
||||
|
||||
data object WalletPrepare : OnboardingVisaAnalyticsEvent(
|
||||
event = "Wallet Prepare",
|
||||
)
|
||||
|
||||
data object ButtonApprove : OnboardingVisaAnalyticsEvent(
|
||||
event = "Button - Approve",
|
||||
)
|
||||
|
||||
data object GoToWebsiteOpened : OnboardingVisaAnalyticsEvent(
|
||||
event = "Go To Website Opened",
|
||||
)
|
||||
|
||||
data object ButtonBrowser : OnboardingVisaAnalyticsEvent(
|
||||
event = "Button - Browser",
|
||||
)
|
||||
|
||||
data object ButtonShareLink : OnboardingVisaAnalyticsEvent(
|
||||
event = "Button - Share Link",
|
||||
)
|
||||
|
||||
data object ActivationInProgressScreen : OnboardingVisaAnalyticsEvent(
|
||||
event = "Activation In Progress Screen",
|
||||
)
|
||||
|
||||
data object PinCodeScreenOpened : OnboardingVisaAnalyticsEvent(
|
||||
event = "PIN Code Screen Opened",
|
||||
)
|
||||
|
||||
data object PinEntered : OnboardingVisaAnalyticsEvent(
|
||||
event = "PIN Entered",
|
||||
params = mapOf("Type" to "Visa"),
|
||||
)
|
||||
|
||||
data object BiometricScreenOpened : OnboardingVisaAnalyticsEvent(
|
||||
event = "Biometric Screen Opened",
|
||||
)
|
||||
|
||||
data object SuccessScreenOpened : OnboardingVisaAnalyticsEvent(
|
||||
event = "Success Screen Opened",
|
||||
)
|
||||
|
||||
data object ErrorPinValidation : OnboardingVisaAnalyticsEvent(
|
||||
event = "Error - Pin Validation",
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.tangem.features.onboarding.v2.visa.impl.child.welcome.model.analytics
|
||||
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
|
||||
internal const val ONBOARDING_SOURCE = "Onboarding"
|
||||
internal const val MAIN_SOURCE = "Main"
|
||||
|
||||
internal sealed class VisaAnalyticsEvent(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
) : AnalyticsEvent("Visa", event, params) {
|
||||
|
||||
data class Errors(
|
||||
val errorCode: String,
|
||||
val source: String,
|
||||
) : VisaAnalyticsEvent(
|
||||
event = "Errors",
|
||||
params = mapOf(
|
||||
"Error Code" to errorCode,
|
||||
"Source" to source,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
package com.tangem.feature.wallet.child.wallet.model.intents
|
||||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.domain.feedback.GetCardInfoUseCase
|
||||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||
|
|
@ -40,13 +42,15 @@ internal class VisaWalletIntentsImplementor @Inject constructor(
|
|||
private val getUserWalletsUseCase: GetWalletsUseCase,
|
||||
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
) : BaseWalletClickIntents(), VisaWalletIntents {
|
||||
|
||||
private val balancesAndLimitsBottomSheetConverter by lazy(mode = LazyThreadSafetyMode.NONE) {
|
||||
BalancesAndLimitsBottomSheetConverter(eventSender)
|
||||
BalancesAndLimitsBottomSheetConverter(eventSender, analyticsEventHandler)
|
||||
}
|
||||
|
||||
override fun onBalancesAndLimitsClick() {
|
||||
analyticsEventHandler.send(MainScreenAnalyticsEvent.LimitsClicked)
|
||||
modelScope.launch(dispatchers.main) {
|
||||
val userWalletId = stateController.getSelectedWalletId()
|
||||
val balancesAndLimits = getVisaCurrencyUseCase(userWalletId)
|
||||
|
|
@ -87,6 +91,7 @@ internal class VisaWalletIntentsImplementor @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onExploreClick(exploreUrl: String) {
|
||||
analyticsEventHandler.send(MainScreenAnalyticsEvent.ButtonExplore)
|
||||
router.openUrl(exploreUrl)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import com.tangem.common.ui.bottomsheet.chooseaddress.ChooseAddressBottomSheetCo
|
|||
import com.tangem.common.ui.bottomsheet.receive.AddressModel
|
||||
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheetConfig
|
||||
import com.tangem.common.ui.bottomsheet.receive.mapToAddressModels
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.WrappedList
|
||||
|
|
@ -78,7 +79,7 @@ interface WalletCurrencyActionsClickIntents {
|
|||
unavailabilityReason: ScenarioUnavailabilityReason,
|
||||
)
|
||||
|
||||
fun onReceiveClick(cryptoCurrencyStatus: CryptoCurrencyStatus)
|
||||
fun onReceiveClick(cryptoCurrencyStatus: CryptoCurrencyStatus, event: AnalyticsEvent? = null)
|
||||
|
||||
fun onStakeClick(cryptoCurrencyStatus: CryptoCurrencyStatus, yield: Yield?)
|
||||
|
||||
|
|
@ -94,7 +95,7 @@ interface WalletCurrencyActionsClickIntents {
|
|||
|
||||
fun onAnalyticsClick(cryptoCurrencyStatus: CryptoCurrencyStatus)
|
||||
|
||||
fun onMultiWalletBuyClick(userWalletId: UserWalletId)
|
||||
fun onMultiWalletBuyClick(userWalletId: UserWalletId, screenType: String)
|
||||
|
||||
fun onMultiWalletSellClick(userWalletId: UserWalletId)
|
||||
|
||||
|
|
@ -151,7 +152,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
|
|||
appRouter.push(route)
|
||||
}
|
||||
|
||||
override fun onReceiveClick(cryptoCurrencyStatus: CryptoCurrencyStatus) {
|
||||
override fun onReceiveClick(cryptoCurrencyStatus: CryptoCurrencyStatus, event: AnalyticsEvent?) {
|
||||
val userWalletId = stateHolder.getSelectedWalletId()
|
||||
|
||||
analyticsEventHandler.send(
|
||||
|
|
@ -166,6 +167,8 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
|
|||
event = TokenReceiveAnalyticsEvent.ReceiveScreenOpened(cryptoCurrencyStatus.currency.symbol),
|
||||
)
|
||||
|
||||
event?.let { analyticsEventHandler.send(it) }
|
||||
|
||||
stateHolder.showBottomSheet(
|
||||
createReceiveBottomSheetContent(
|
||||
currency = cryptoCurrencyStatus.currency,
|
||||
|
|
@ -470,7 +473,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun onMultiWalletBuyClick(userWalletId: UserWalletId) {
|
||||
override fun onMultiWalletBuyClick(userWalletId: UserWalletId, screenType: String) {
|
||||
onMultiWalletActionClick(
|
||||
statusFlow = if (onrampFeatureToggles.isFeatureEnabled) {
|
||||
rampStateManager.getExpressInitializationStatus(userWalletId)
|
||||
|
|
@ -478,7 +481,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
|
|||
rampStateManager.getBuyInitializationStatus()
|
||||
},
|
||||
route = AppRoute.BuyCrypto(userWalletId = userWalletId),
|
||||
eventCreator = MainScreenAnalyticsEvent::ButtonBuy,
|
||||
eventCreator = { MainScreenAnalyticsEvent.ButtonBuy(status = it, screenType = screenType) },
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers
|
|||
|
||||
import arrow.core.Either
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent
|
||||
import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent.Companion.VISA_TYPE
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
|
|
@ -144,17 +146,23 @@ internal class SetVisaInfoTransformer(
|
|||
),
|
||||
)
|
||||
|
||||
return return persistentListOf(
|
||||
return persistentListOf(
|
||||
WalletManageButton.Receive(
|
||||
enabled = true,
|
||||
dimContent = false,
|
||||
onClick = { clickIntents.onReceiveClick(cryptoCurrencyStatus = cryptoCurrencyStatus) },
|
||||
onLongClick = { clickIntents.onCopyAddressLongClick(cryptoCurrencyStatus = cryptoCurrencyStatus) },
|
||||
onClick = {
|
||||
clickIntents.onReceiveClick(cryptoCurrencyStatus, MainScreenAnalyticsEvent.ButtonReceive)
|
||||
},
|
||||
onLongClick = {
|
||||
clickIntents.onCopyAddressLongClick(cryptoCurrencyStatus)
|
||||
},
|
||||
),
|
||||
WalletManageButton.Buy(
|
||||
enabled = true,
|
||||
dimContent = false,
|
||||
onClick = { clickIntents.onMultiWalletBuyClick(userWalletId = userWallet.walletId) },
|
||||
onClick = {
|
||||
clickIntents.onMultiWalletBuyClick(userWalletId = userWallet.walletId, screenType = VISA_TYPE)
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.transformers.converter
|
||||
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.core.ui.utils.DateTimeFormatters
|
||||
|
|
@ -13,6 +15,7 @@ import java.math.BigDecimal
|
|||
|
||||
internal class BalancesAndLimitsBottomSheetConverter(
|
||||
private val eventSender: WalletEventSender,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
) : Converter<VisaCurrency, BalancesAndLimitsBottomSheetConfig> {
|
||||
|
||||
override fun convert(value: VisaCurrency): BalancesAndLimitsBottomSheetConfig {
|
||||
|
|
@ -28,23 +31,25 @@ internal class BalancesAndLimitsBottomSheetConverter(
|
|||
blockedBalance = value.balances.blocked.let(::formatAmount),
|
||||
debit = value.balances.debt.let(::formatAmount),
|
||||
amlVerified = value.balances.verified.let(::formatAmount),
|
||||
onInfoClick = this::showBalanceInfo,
|
||||
onInfoClick = this::balanceInfoOnClick,
|
||||
),
|
||||
limit = BalancesAndLimitsBottomSheetConfig.Limit(
|
||||
availableBy = DateTimeFormatters.formatDate(date = value.limits.expirationDate),
|
||||
total = otpLimit,
|
||||
other = noOtpLimit,
|
||||
singleTransaction = value.limits.singleTransaction.let(::formatAmount),
|
||||
onInfoClick = { showLimitInfo(otpLimit, noOtpLimit) },
|
||||
onInfoClick = { limitInfoOnClick(otpLimit, noOtpLimit) },
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun showBalanceInfo() {
|
||||
private fun balanceInfoOnClick() {
|
||||
analyticsEventHandler.send(MainScreenAnalyticsEvent.NoticeBalancesInfo)
|
||||
eventSender.send(WalletEvent.ShowAlert(WalletAlertState.VisaBalancesInfo))
|
||||
}
|
||||
|
||||
private fun showLimitInfo(totalLimit: String, otherLimit: String) {
|
||||
private fun limitInfoOnClick(totalLimit: String, otherLimit: String) {
|
||||
analyticsEventHandler.send(MainScreenAnalyticsEvent.NoticeLimitsInfo)
|
||||
eventSender.send(WalletEvent.ShowAlert(WalletAlertState.VisaLimitsInfo(totalLimit, otherLimit)))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.utils
|
||||
|
||||
import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent.Companion.WALLET_TYPE
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
|
||||
import com.tangem.core.ui.components.transactions.state.TxHistoryState
|
||||
|
|
@ -103,7 +104,7 @@ internal class WalletLoadingStateFactory(
|
|||
WalletManageButton.Buy(
|
||||
enabled = true,
|
||||
dimContent = false,
|
||||
onClick = { clickIntents.onMultiWalletBuyClick(userWalletId = userWallet.walletId) },
|
||||
onClick = { clickIntents.onMultiWalletBuyClick(userWalletId = userWallet.walletId, WALLET_TYPE) },
|
||||
),
|
||||
WalletManageButton.Swap(
|
||||
enabled = true,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue