Updated on 2026-08-14
This commit is contained in:
parent
dd59d9f92e
commit
081a9c6408
5 changed files with 190 additions and 24 deletions
|
|
@ -37,17 +37,18 @@ internal class TangemPayDetailsNotificationFactory(
|
|||
)
|
||||
|
||||
fun createAwaitingDepositConfig(tariffPlan: TangemPayTariffPlanState?): NotificationConfig? {
|
||||
if (!isTiersPlusPlanEnabled) return null
|
||||
if (tariffPlan == null) return null
|
||||
|
||||
if (tariffPlan.tariff.status == TangemPayCustomerTariffPlan.Status.SYSTEM_DOWNGRADE_PENDING) {
|
||||
return createTariffSystemDownGradePendingConfig(tariffPlan)
|
||||
tariffPlan ?: return null
|
||||
return when (TangemPayTiersBannerType.fromPlan(isTiersPlusPlanEnabled, tariffPlan)) {
|
||||
null -> null
|
||||
TangemPayTiersBannerType.TierSystemDowngrade -> createTariffSystemDowngradePendingConfig(tariffPlan)
|
||||
TangemPayTiersBannerType.TopUpForTierUpgrade -> createTopUpForTierUpgradeConfig(tariffPlan)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createTopUpForTierUpgradeConfig(tariffPlan: TangemPayTariffPlanState): NotificationConfig? {
|
||||
val order = tariffPlan.order ?: return null
|
||||
val orderStep = order.step
|
||||
if (orderStep !is TangemPayTariffPlanState.OrderStep.AwaitingDeposit) return null
|
||||
|
||||
val feeText = orderStep.toPlan.formatRecurringFeeOrNull() ?: return null
|
||||
|
||||
return NotificationConfig(
|
||||
|
|
@ -81,7 +82,7 @@ internal class TangemPayDetailsNotificationFactory(
|
|||
iconResId = R.drawable.ic_alert_circle_24,
|
||||
)
|
||||
|
||||
private fun createTariffSystemDownGradePendingConfig(tariffPlan: TangemPayTariffPlanState): NotificationConfig? {
|
||||
private fun createTariffSystemDowngradePendingConfig(tariffPlan: TangemPayTariffPlanState): NotificationConfig? {
|
||||
val date = tariffPlan.tariff.formatNextBillingDateOrNull() ?: return null
|
||||
val planName = tariffPlan.tariff.plan.name
|
||||
return NotificationConfig(
|
||||
|
|
@ -97,4 +98,30 @@ internal class TangemPayDetailsNotificationFactory(
|
|||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal enum class TangemPayTiersBannerType {
|
||||
TopUpForTierUpgrade,
|
||||
TierSystemDowngrade,
|
||||
;
|
||||
|
||||
internal companion object {
|
||||
fun fromPlan(
|
||||
isTiersPlusPlanEnabled: Boolean,
|
||||
tariffPlan: TangemPayTariffPlanState,
|
||||
): TangemPayTiersBannerType? {
|
||||
if (!isTiersPlusPlanEnabled) return null
|
||||
|
||||
if (tariffPlan.tariff.status == TangemPayCustomerTariffPlan.Status.SYSTEM_DOWNGRADE_PENDING) {
|
||||
tariffPlan.tariff.formatNextBillingDateOrNull() ?: return null
|
||||
return TierSystemDowngrade
|
||||
}
|
||||
|
||||
val orderStep = tariffPlan.order?.step
|
||||
if (orderStep !is TangemPayTariffPlanState.OrderStep.AwaitingDeposit) return null
|
||||
orderStep.toPlan.formatRecurringFeeOrNull() ?: return null
|
||||
|
||||
return TopUpForTierUpgrade
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -24,11 +24,7 @@ import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
|||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||
import com.tangem.domain.feedback.models.WalletMetaInfo
|
||||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
||||
import com.tangem.domain.models.account.TangemPayCustomerTariffPlan
|
||||
import com.tangem.domain.models.account.TangemPayTariffPlanState
|
||||
import com.tangem.domain.models.account.VirtualAccountOnramp
|
||||
import com.tangem.domain.models.account.isPlanTransitioningState
|
||||
import com.tangem.domain.models.account.*
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.pay.flow.PaymentAccountStatusFetcher
|
||||
import com.tangem.domain.pay.flow.PaymentAccountStatusSupplier
|
||||
|
|
@ -36,12 +32,7 @@ import com.tangem.domain.pay.model.TangemPayTopUpData
|
|||
import com.tangem.domain.pay.repository.OnboardingRepository
|
||||
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
||||
import com.tangem.domain.pay.repository.TangemPayWithdrawRepository
|
||||
import com.tangem.domain.pay.usecase.CancelTangemPayOrderUseCase
|
||||
import com.tangem.domain.pay.usecase.GetCashbackDeactivationDismissedUseCase
|
||||
import com.tangem.domain.pay.usecase.GetCashbackSummaryUseCase
|
||||
import com.tangem.domain.pay.usecase.GetCustomerOffersUseCase
|
||||
import com.tangem.domain.pay.usecase.ProduceTangemPayInitialDataUseCase
|
||||
import com.tangem.domain.pay.usecase.SetCashbackDeactivationDismissedUseCase
|
||||
import com.tangem.domain.pay.usecase.*
|
||||
import com.tangem.domain.tangempay.TangemPayAnalyticsEvents
|
||||
import com.tangem.domain.visa.model.TangemPayTxHistoryItem
|
||||
import com.tangem.features.tangempay.TangemPayConstants
|
||||
|
|
@ -51,10 +42,7 @@ import com.tangem.features.tangempay.components.AddFundsListener
|
|||
import com.tangem.features.tangempay.components.TangemPayDetailsContainerComponent
|
||||
import com.tangem.features.tangempay.components.TangemPayIssueAdditionalCardComponent
|
||||
import com.tangem.features.tangempay.details.impl.R
|
||||
import com.tangem.features.tangempay.entity.TangemPayDetailsErrorType
|
||||
import com.tangem.features.tangempay.entity.TangemPayDetailsNavigation
|
||||
import com.tangem.features.tangempay.entity.TangemPayDetailsStateFactory
|
||||
import com.tangem.features.tangempay.entity.TangemPayDetailsUM
|
||||
import com.tangem.features.tangempay.entity.*
|
||||
import com.tangem.features.tangempay.model.transformers.*
|
||||
import com.tangem.features.tangempay.navigation.TangemPayAccountDetailsInnerRoute
|
||||
import com.tangem.features.tangempay.utils.*
|
||||
|
|
@ -139,6 +127,8 @@ internal class TangemPayDetailsModel @Inject constructor(
|
|||
|
||||
val bottomSheetNavigation: SlotNavigation<TangemPayDetailsNavigation> = SlotNavigation()
|
||||
|
||||
private var shownTiersBanner: TangemPayTiersBannerType? = null
|
||||
|
||||
init {
|
||||
analytics.send(TangemPayAnalyticsEvents.MainScreenOpened())
|
||||
handleBalanceHiding()
|
||||
|
|
@ -147,6 +137,7 @@ internal class TangemPayDetailsModel @Inject constructor(
|
|||
.onEach { status -> currentStatus.update { status } }
|
||||
.map { it.value }
|
||||
.onEach { state ->
|
||||
sendTiersAnalytics(state)
|
||||
when (state) {
|
||||
is PaymentAccountStatusValue.Deactivated -> uiState.update {
|
||||
stateFactory.getDeactivatedState(state)
|
||||
|
|
@ -166,6 +157,7 @@ internal class TangemPayDetailsModel @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onCancelPlusTransition(orderId: String) {
|
||||
analytics.send(TangemPayAnalyticsEvents.Tiers.CancelPlusMoveToBasicClicked())
|
||||
uiState.update(TangemPayErrorNotificationTransformer(shouldShowProgress = true))
|
||||
modelScope.launch {
|
||||
cancelTangemPayOrderUseCase(userWalletId = userWalletId, orderId = orderId)
|
||||
|
|
@ -445,6 +437,7 @@ internal class TangemPayDetailsModel @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onClickCurrentPlan(tariffPlan: TangemPayCustomerTariffPlan) {
|
||||
analytics.send(TangemPayAnalyticsEvents.Tiers.CurrentPlanClicked())
|
||||
router.push(TangemPayAccountDetailsInnerRoute.CurrentPlan(tariffPlan))
|
||||
}
|
||||
|
||||
|
|
@ -547,4 +540,30 @@ internal class TangemPayDetailsModel @Inject constructor(
|
|||
private fun showBottomSheetError(type: TangemPayDetailsErrorType) {
|
||||
uiMessageSender.send(message = TangemPayMessagesFactory.createErrorMessage(errorType = type))
|
||||
}
|
||||
|
||||
private fun sendTiersAnalytics(state: PaymentAccountStatusValue) {
|
||||
val tariffPlan = when (state) {
|
||||
is PaymentAccountStatusValue.Loaded -> state.tariffPlan
|
||||
is PaymentAccountStatusValue.Inactive -> state.tariffPlan
|
||||
else -> null
|
||||
}
|
||||
val banner = tariffPlan?.let {
|
||||
TangemPayTiersBannerType.fromPlan(tangemPayFeatureToggles.isTiersPlusPlanEnabled, tariffPlan)
|
||||
}
|
||||
|
||||
if (banner == shownTiersBanner) return
|
||||
shownTiersBanner = banner
|
||||
|
||||
val event = when (banner) {
|
||||
TangemPayTiersBannerType.TopUpForTierUpgrade -> {
|
||||
TangemPayAnalyticsEvents.Tiers.TopUpBannerForPlusShowed()
|
||||
}
|
||||
TangemPayTiersBannerType.TierSystemDowngrade -> {
|
||||
TangemPayAnalyticsEvents.Tiers.PlusCardsClosureWarningBannerShowed()
|
||||
}
|
||||
null -> null
|
||||
}
|
||||
|
||||
event?.let { analytics.send(it) }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.features.tangempay.tiers.current
|
||||
|
||||
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.decompose.model.ParamsContainer
|
||||
|
|
@ -13,6 +14,7 @@ import com.tangem.core.ui.utils.DateTimeFormatters
|
|||
import com.tangem.domain.models.account.TangemPayCustomerTariffPlan
|
||||
import com.tangem.domain.models.account.TangemPayTariffPlan
|
||||
import com.tangem.domain.pay.usecase.CancelTariffPlanPendingTransitionUseCase
|
||||
import com.tangem.domain.tangempay.TangemPayAnalyticsEvents
|
||||
import com.tangem.features.tangempay.details.impl.R
|
||||
import com.tangem.features.tangempay.navigation.TangemPayAccountDetailsInnerRoute
|
||||
import com.tangem.features.tangempay.tiers.formatNextBillingDateOrNull
|
||||
|
|
@ -34,6 +36,7 @@ internal class TangemPayCurrentPlanModel @Inject constructor(
|
|||
private val router: Router,
|
||||
private val cancelPendingTransition: CancelTariffPlanPendingTransitionUseCase,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
private val analytics: AnalyticsEventHandler,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<TangemPayCurrentPlanComponent.Params>()
|
||||
|
|
@ -48,12 +51,17 @@ internal class TangemPayCurrentPlanModel @Inject constructor(
|
|||
notification = createNotification(customerPlan),
|
||||
sections = buildSections(customerPlan.plan),
|
||||
onBackClick = router::pop,
|
||||
onChangePlanClick = { router.push(TangemPayAccountDetailsInnerRoute.SelectPlan(params.tariffPlan)) }
|
||||
onChangePlanClick = ::onChangePlanClick
|
||||
.takeIf {
|
||||
customerPlan.status != TangemPayCustomerTariffPlan.Status.DOWNGRADE_PENDING
|
||||
},
|
||||
)
|
||||
|
||||
private fun onChangePlanClick() {
|
||||
analytics.send(TangemPayAnalyticsEvents.Tiers.ChangePlanClicked())
|
||||
router.push(TangemPayAccountDetailsInnerRoute.SelectPlan(params.tariffPlan))
|
||||
}
|
||||
|
||||
private fun createNotification(customerPlan: TangemPayCustomerTariffPlan): TangemPayCurrentPlanUM.Notification? {
|
||||
val date = customerPlan.formatNextBillingDateOrNull(formatter = DateTimeFormatters.dateMMMd) ?: return null
|
||||
val feeText = customerPlan.plan.formatRecurringFeeOrNull() ?: return null
|
||||
|
|
@ -89,6 +97,8 @@ internal class TangemPayCurrentPlanModel @Inject constructor(
|
|||
if (isProcessing) return
|
||||
val customerPlan = params.tariffPlan
|
||||
val targetPlanName = customerPlan.pendingPlan?.name ?: return
|
||||
analytics.send(TangemPayAnalyticsEvents.Tiers.StayOnPlusConditionsClicked())
|
||||
analytics.send(TangemPayAnalyticsEvents.Tiers.StayOnPlusPopupShowed())
|
||||
uiMessageSender.send(
|
||||
message = TangemPayMessagesFactory.createStayOnPlanMessage(
|
||||
planName = customerPlan.plan.name,
|
||||
|
|
@ -100,6 +110,7 @@ internal class TangemPayCurrentPlanModel @Inject constructor(
|
|||
|
||||
private fun confirmStayOnPlan() {
|
||||
if (isProcessing) return
|
||||
analytics.send(TangemPayAnalyticsEvents.Tiers.StayOnPlusPopupClicked())
|
||||
isProcessing = true
|
||||
state.value = createState(params.tariffPlan)
|
||||
modelScope.launch {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.features.tangempay.tiers.select
|
|||
|
||||
import androidx.compose.runtime.Stable
|
||||
import arrow.core.Either
|
||||
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
|
||||
|
|
@ -16,6 +17,7 @@ import com.tangem.domain.models.account.TangemPayTariffPlanTransition
|
|||
import com.tangem.domain.pay.usecase.CreateTariffPlanTransitionOrderUseCase
|
||||
import com.tangem.domain.pay.usecase.GetTangemPayTariffPlanTransitionsUseCase
|
||||
import com.tangem.domain.pay.usecase.SetTariffPlanPendingTransitionUseCase
|
||||
import com.tangem.domain.tangempay.TangemPayAnalyticsEvents
|
||||
import com.tangem.domain.visa.error.VisaApiError
|
||||
import com.tangem.features.tangempay.details.impl.R
|
||||
import com.tangem.features.tangempay.navigation.TangemPayAccountDetailsInnerRoute
|
||||
|
|
@ -42,6 +44,7 @@ internal class TangemPaySelectPlanModel @Inject constructor(
|
|||
private val createTransitionOrder: CreateTariffPlanTransitionOrderUseCase,
|
||||
private val setPendingTransition: SetTariffPlanPendingTransitionUseCase,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
private val analytics: AnalyticsEventHandler,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<TangemPaySelectPlanComponent.Params>()
|
||||
|
|
@ -62,6 +65,7 @@ internal class TangemPaySelectPlanModel @Inject constructor(
|
|||
field = MutableStateFlow(buildState())
|
||||
|
||||
init {
|
||||
analytics.send(TangemPayAnalyticsEvents.Tiers.TierSelectionScreenShowed())
|
||||
loadTransitions()
|
||||
}
|
||||
|
||||
|
|
@ -77,27 +81,37 @@ internal class TangemPaySelectPlanModel @Inject constructor(
|
|||
private fun onPlanSelected(index: Int) {
|
||||
if (index == selectedIndex) return
|
||||
selectedIndex = index
|
||||
analytics.send(TangemPayAnalyticsEvents.Tiers.TiersSwiped())
|
||||
state.update { buildState() }
|
||||
}
|
||||
|
||||
private fun onSelectClick() {
|
||||
if (allowedTransitions.isEmpty()) return
|
||||
val transition = allowedTransitions.getOrNull(selectedIndex) ?: return
|
||||
|
||||
val tierId = transition.plan.tierId
|
||||
analytics.send(TangemPayAnalyticsEvents.Tiers.PlanSelectedClick(tierId))
|
||||
analytics.send(TangemPayAnalyticsEvents.Tiers.PlanChangeConfirmationScreenShowed(tierId))
|
||||
|
||||
isConfirm = true
|
||||
state.update { buildState() }
|
||||
}
|
||||
|
||||
private fun onComparePlansClick() {
|
||||
if (allowedTransitions.isEmpty()) return
|
||||
analytics.send(TangemPayAnalyticsEvents.Tiers.ComparePlansClicked())
|
||||
analytics.send(TangemPayAnalyticsEvents.Tiers.PlansComparisonPopupShowed())
|
||||
state.update { buildState(showPlanCompare = true) }
|
||||
}
|
||||
|
||||
private fun onCompareDismiss() {
|
||||
analytics.send(TangemPayAnalyticsEvents.Tiers.PlansComparisonPopupClosed())
|
||||
state.update { buildState(showPlanCompare = false) }
|
||||
}
|
||||
|
||||
private fun onBackClick() {
|
||||
if (isProcessing) return
|
||||
if (isConfirm) {
|
||||
analytics.send(TangemPayAnalyticsEvents.Tiers.PlanChangeCancelClicked())
|
||||
isConfirm = false
|
||||
state.update { buildState() }
|
||||
} else {
|
||||
|
|
@ -109,6 +123,9 @@ internal class TangemPaySelectPlanModel @Inject constructor(
|
|||
if (isProcessing) return
|
||||
|
||||
val transition = allowedTransitions.getOrNull(selectedIndex) ?: return
|
||||
if (transition.type == TangemPayTariffPlanTransition.Type.UPGRADE) {
|
||||
analytics.send(TangemPayAnalyticsEvents.Tiers.PlanChangeUpgradeClicked())
|
||||
}
|
||||
when (transition.type) {
|
||||
TangemPayTariffPlanTransition.Type.ACTIVATION,
|
||||
TangemPayTariffPlanTransition.Type.UPGRADE,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue