Updated on 2026-08-14
This commit is contained in:
parent
3fd066750f
commit
172efa81b2
10 changed files with 124 additions and 63 deletions
|
|
@ -2009,7 +2009,10 @@
|
||||||
<string name="tangempay_kyc_rejected_description">Sorry, we couldn\'t verify</string>
|
<string name="tangempay_kyc_rejected_description">Sorry, we couldn\'t verify</string>
|
||||||
<string name="tangempay_kyc_rejected_description_span">your profile.</string>
|
<string name="tangempay_kyc_rejected_description_span">your profile.</string>
|
||||||
<string name="tangempay_main_select_plan">Select plan</string>
|
<string name="tangempay_main_select_plan">Select plan</string>
|
||||||
<string name="tangempay_maximum_cards_issued_description">You can have up to 3 cards. Delete one to add a new card.</string>
|
<string name="tangempay_maximum_cards_issued_description">Delete one to add a new card</string>
|
||||||
|
<string name="tangempay_maximum_cards_issued_for_plan_description">Upgrade plan to have more cards</string>
|
||||||
|
<string name="tangempay_maximum_cards_issued_for_plan_title">Cards limit reached for this plan</string>
|
||||||
|
<string name="tangempay_maximum_cards_issued_for_plan_upgrade_btn">Upgrade plan</string>
|
||||||
<string name="tangempay_maximum_cards_issued_title">Maximum Cards Issued</string>
|
<string name="tangempay_maximum_cards_issued_title">Maximum Cards Issued</string>
|
||||||
<string name="tangempay_newonboard_Q1_body">Yes – to operate a regulated Visa card, identity verification is mandatory. KYC is handled by Sumsub (compliance partner).</string>
|
<string name="tangempay_newonboard_Q1_body">Yes – to operate a regulated Visa card, identity verification is mandatory. KYC is handled by Sumsub (compliance partner).</string>
|
||||||
<string name="tangempay_newonboard_Q1_title">Do I have to share my docs?</string>
|
<string name="tangempay_newonboard_Q1_title">Do I have to share my docs?</string>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
package com.tangem.data.pay.repository
|
package com.tangem.data.pay.repository
|
||||||
|
|
||||||
import arrow.core.Either
|
import arrow.core.Either
|
||||||
import arrow.core.right
|
|
||||||
import com.tangem.datasource.api.pay.TangemPayApi
|
import com.tangem.datasource.api.pay.TangemPayApi
|
||||||
import com.tangem.datasource.api.pay.models.response.CustomerOffersResponse
|
import com.tangem.datasource.api.pay.models.response.CustomerOffersResponse
|
||||||
import com.tangem.datasource.local.datastore.RuntimeSharedStore
|
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.domain.pay.model.Offer
|
import com.tangem.domain.pay.model.Offer
|
||||||
import com.tangem.domain.pay.model.OrderType
|
import com.tangem.domain.pay.model.OrderType
|
||||||
|
|
@ -18,18 +16,11 @@ internal class DefaultCustomerOffersRepository @Inject constructor(
|
||||||
private val requestHelper: TangemPayRequestPerformer,
|
private val requestHelper: TangemPayRequestPerformer,
|
||||||
) : CustomerOffersRepository {
|
) : CustomerOffersRepository {
|
||||||
|
|
||||||
private val offersCache = RuntimeSharedStore<Map<String, List<Offer>>>()
|
|
||||||
|
|
||||||
override suspend fun getOffers(userWalletId: UserWalletId): Either<VisaApiError, List<Offer>> {
|
override suspend fun getOffers(userWalletId: UserWalletId): Either<VisaApiError, List<Offer>> {
|
||||||
val key = userWalletId.stringValue
|
|
||||||
offersCache.getSyncOrNull()?.get(key)?.let { return it.right() }
|
|
||||||
|
|
||||||
return requestHelper.performRequest(userWalletId) { authHeader ->
|
return requestHelper.performRequest(userWalletId) { authHeader ->
|
||||||
tangemPayApi.getCustomerOffers(authHeader = authHeader)
|
tangemPayApi.getCustomerOffers(authHeader = authHeader)
|
||||||
}.map { response ->
|
}.map { response ->
|
||||||
response.result.map { it.toDomain() }
|
response.result.map { it.toDomain() }
|
||||||
}.onRight { offers ->
|
|
||||||
offersCache.update(default = emptyMap()) { it + (key to offers) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ internal class DefaultCustomerOffersRepositoryTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `GIVEN offers fetched once WHEN getOffers called twice THEN backend is hit only once`() = runTest {
|
fun `GIVEN offers response WHEN getOffers called twice THEN backend is hit each time`() = runTest {
|
||||||
// Arrange
|
// Arrange
|
||||||
val repository = createRepository()
|
val repository = createRepository()
|
||||||
|
|
||||||
|
|
@ -68,11 +68,11 @@ internal class DefaultCustomerOffersRepositoryTest {
|
||||||
// Assert
|
// Assert
|
||||||
assertThat(first.isRight()).isTrue()
|
assertThat(first.isRight()).isTrue()
|
||||||
assertThat(second).isEqualTo(first)
|
assertThat(second).isEqualTo(first)
|
||||||
coVerify(exactly = 1) { tangemPayApi.getCustomerOffers(any()) }
|
coVerify(exactly = 2) { tangemPayApi.getCustomerOffers(any()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `GIVEN backend error WHEN getOffers called again THEN error is not cached and backend is hit again`() = runTest {
|
fun `GIVEN backend error WHEN getOffers called again THEN backend is hit again`() = runTest {
|
||||||
// Arrange
|
// Arrange
|
||||||
coEvery { tangemPayApi.getCustomerOffers(any()) } returnsMany listOf(
|
coEvery { tangemPayApi.getCustomerOffers(any()) } returnsMany listOf(
|
||||||
ApiResponse.Error(ApiResponseError.NetworkException()) as ApiResponse<CustomerOffersResponse>,
|
ApiResponse.Error(ApiResponseError.NetworkException()) as ApiResponse<CustomerOffersResponse>,
|
||||||
|
|
|
||||||
|
|
@ -26,4 +26,8 @@ data class TangemPayTariffPlanState(
|
||||||
@SerialName("toPlan") val toPlan: TangemPayTariffPlan,
|
@SerialName("toPlan") val toPlan: TangemPayTariffPlan,
|
||||||
) : OrderStep
|
) : OrderStep
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val TangemPayTariffPlanState.isPlanTransitioningState
|
||||||
|
get() = order?.step is TangemPayTariffPlanState.OrderStep.AwaitingDeposit ||
|
||||||
|
tariff.status == TangemPayCustomerTariffPlan.Status.TRANSITIONING
|
||||||
|
|
@ -10,6 +10,7 @@ import com.tangem.core.ui.extensions.themedColor
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
import com.tangem.core.ui.res.generated.icons.Icons
|
import com.tangem.core.ui.res.generated.icons.Icons
|
||||||
import com.tangem.core.ui.res.generated.icons.ic_document_20
|
import com.tangem.core.ui.res.generated.icons.ic_document_20
|
||||||
|
import com.tangem.domain.models.StatusSource
|
||||||
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
||||||
import com.tangem.domain.models.account.TangemPayCustomerTariffPlan
|
import com.tangem.domain.models.account.TangemPayCustomerTariffPlan
|
||||||
import com.tangem.domain.models.account.TangemPayTariffPlanState
|
import com.tangem.domain.models.account.TangemPayTariffPlanState
|
||||||
|
|
@ -58,7 +59,7 @@ internal class TangemPayDetailsStateFactory(
|
||||||
actionButtons = persistentListOf(),
|
actionButtons = persistentListOf(),
|
||||||
cardsBlockState = TangemPayDetailsBalanceBlockState.CardsBlockState(
|
cardsBlockState = TangemPayDetailsBalanceBlockState.CardsBlockState(
|
||||||
cards = persistentListOf(),
|
cards = persistentListOf(),
|
||||||
onAddCardClick = intents::onAddCardClick,
|
onAddCardClick = {},
|
||||||
isAddCardEnabled = false,
|
isAddCardEnabled = false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -79,6 +80,7 @@ internal class TangemPayDetailsStateFactory(
|
||||||
val hasWithdrawableBalance = status.balance.hasWithdrawableAmount
|
val hasWithdrawableBalance = status.balance.hasWithdrawableAmount
|
||||||
val errorNotification = notificationFactory.createErrorConfig(status.error)
|
val errorNotification = notificationFactory.createErrorConfig(status.error)
|
||||||
val awaitingDepositNotification = notificationFactory.createAwaitingDepositConfig(status.tariffPlan)
|
val awaitingDepositNotification = notificationFactory.createAwaitingDepositConfig(status.tariffPlan)
|
||||||
|
val fiatBalance = status.balance.fiatBalance
|
||||||
return TangemPayDetailsUM(
|
return TangemPayDetailsUM(
|
||||||
topBarConfig = TangemPayDetailsTopBarConfig(
|
topBarConfig = TangemPayDetailsTopBarConfig(
|
||||||
onBackClick = onBack,
|
onBackClick = onBack,
|
||||||
|
|
@ -90,7 +92,12 @@ internal class TangemPayDetailsStateFactory(
|
||||||
isRefreshing = false,
|
isRefreshing = false,
|
||||||
onRefresh = intents::onRefreshSwipe,
|
onRefresh = intents::onRefreshSwipe,
|
||||||
),
|
),
|
||||||
balanceBlockState = TangemPayDetailsBalanceBlockState.Loading(
|
balanceBlockState = TangemPayDetailsBalanceBlockState.Content(
|
||||||
|
isBalanceFlickering = false,
|
||||||
|
fiatBalance = DetailsBalanceTransformer.getFiatBalanceText(fiatBalance),
|
||||||
|
isMuted = !isFresh,
|
||||||
|
isNegative = fiatBalance.availableBalance.signum() < 0,
|
||||||
|
isInactive = false,
|
||||||
actionButtons = getActionButtonsConfig(
|
actionButtons = getActionButtonsConfig(
|
||||||
isAddFundsEnabled = areActionButtonsEnabled,
|
isAddFundsEnabled = areActionButtonsEnabled,
|
||||||
isWithdrawEnabled = areActionButtonsEnabled && hasWithdrawableBalance,
|
isWithdrawEnabled = areActionButtonsEnabled && hasWithdrawableBalance,
|
||||||
|
|
@ -108,7 +115,7 @@ internal class TangemPayDetailsStateFactory(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.toImmutableList(),
|
.toImmutableList(),
|
||||||
onAddCardClick = intents::onAddCardClick,
|
onAddCardClick = { intents.onAddCardClick(status.tariffPlan) },
|
||||||
isAddCardEnabled = isAddCardEnabled,
|
isAddCardEnabled = isAddCardEnabled,
|
||||||
progressBanner = status.cards.resolveProgressBanner(),
|
progressBanner = status.cards.resolveProgressBanner(),
|
||||||
),
|
),
|
||||||
|
|
@ -127,8 +134,10 @@ internal class TangemPayDetailsStateFactory(
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getDeactivatedState(hasWithdrawableBalance: Boolean): TangemPayDetailsUM {
|
fun getDeactivatedState(status: PaymentAccountStatusValue.Deactivated): TangemPayDetailsUM {
|
||||||
|
val hasWithdrawableBalance: Boolean = status.balance.hasWithdrawableAmount
|
||||||
val accountDeactivatedNotification = notificationFactory.createAccountDeactivatedConfig()
|
val accountDeactivatedNotification = notificationFactory.createAccountDeactivatedConfig()
|
||||||
|
val fiatBalance = status.balance.fiatBalance
|
||||||
return TangemPayDetailsUM(
|
return TangemPayDetailsUM(
|
||||||
topBarConfig = TangemPayDetailsTopBarConfig(
|
topBarConfig = TangemPayDetailsTopBarConfig(
|
||||||
onBackClick = onBack,
|
onBackClick = onBack,
|
||||||
|
|
@ -140,7 +149,12 @@ internal class TangemPayDetailsStateFactory(
|
||||||
isRefreshing = false,
|
isRefreshing = false,
|
||||||
onRefresh = intents::onRefreshSwipe,
|
onRefresh = intents::onRefreshSwipe,
|
||||||
),
|
),
|
||||||
balanceBlockState = TangemPayDetailsBalanceBlockState.Loading(
|
balanceBlockState = TangemPayDetailsBalanceBlockState.Content(
|
||||||
|
isBalanceFlickering = false,
|
||||||
|
fiatBalance = DetailsBalanceTransformer.getFiatBalanceText(fiatBalance),
|
||||||
|
isMuted = status.source != StatusSource.ACTUAL,
|
||||||
|
isNegative = fiatBalance.availableBalance.signum() < 0,
|
||||||
|
isInactive = false,
|
||||||
actionButtons = getActionButtonsConfig(
|
actionButtons = getActionButtonsConfig(
|
||||||
isAddFundsEnabled = true,
|
isAddFundsEnabled = true,
|
||||||
isWithdrawEnabled = hasWithdrawableBalance,
|
isWithdrawEnabled = hasWithdrawableBalance,
|
||||||
|
|
@ -184,7 +198,7 @@ internal class TangemPayDetailsStateFactory(
|
||||||
state = TangemPayCardUiState.InProgress,
|
state = TangemPayCardUiState.InProgress,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onAddCardClick = intents::onAddCardClick,
|
onAddCardClick = {},
|
||||||
isAddCardEnabled = false,
|
isAddCardEnabled = false,
|
||||||
),
|
),
|
||||||
fiatBalance = DetailsBalanceTransformer.getFiatBalanceText(status.fiatBalance),
|
fiatBalance = DetailsBalanceTransformer.getFiatBalanceText(status.fiatBalance),
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,12 @@ import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||||
import com.tangem.domain.feedback.models.WalletMetaInfo
|
import com.tangem.domain.feedback.models.WalletMetaInfo
|
||||||
import com.tangem.domain.models.StatusSource
|
|
||||||
import com.tangem.domain.models.TokenReceiveConfig
|
import com.tangem.domain.models.TokenReceiveConfig
|
||||||
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
||||||
import com.tangem.domain.models.account.TangemPayCustomerTariffPlan
|
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.VirtualAccountOnramp
|
||||||
|
import com.tangem.domain.models.account.isPlanTransitioningState
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.pay.flow.PaymentAccountStatusFetcher
|
import com.tangem.domain.pay.flow.PaymentAccountStatusFetcher
|
||||||
import com.tangem.domain.pay.flow.PaymentAccountStatusSupplier
|
import com.tangem.domain.pay.flow.PaymentAccountStatusSupplier
|
||||||
|
|
@ -122,9 +123,11 @@ internal class TangemPayDetailsModel @Inject constructor(
|
||||||
val uiState: StateFlow<TangemPayDetailsUM>
|
val uiState: StateFlow<TangemPayDetailsUM>
|
||||||
field = MutableStateFlow(
|
field = MutableStateFlow(
|
||||||
when {
|
when {
|
||||||
params.initialStatus.isDeactivated -> stateFactory.getDeactivatedState(
|
params.initialStatus.value is PaymentAccountStatusValue.Deactivated -> {
|
||||||
hasWithdrawableBalance = params.initialStatus.balanceOrNull()?.hasWithdrawableAmount == true,
|
stateFactory.getDeactivatedState(
|
||||||
)
|
params.initialStatus.value as PaymentAccountStatusValue.Deactivated,
|
||||||
|
)
|
||||||
|
}
|
||||||
else -> stateFactory.getLoadingState()
|
else -> stateFactory.getLoadingState()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -145,27 +148,13 @@ internal class TangemPayDetailsModel @Inject constructor(
|
||||||
.map { it.value }
|
.map { it.value }
|
||||||
.onEach { state ->
|
.onEach { state ->
|
||||||
when (state) {
|
when (state) {
|
||||||
is PaymentAccountStatusValue.Deactivated -> {
|
is PaymentAccountStatusValue.Deactivated -> uiState.update {
|
||||||
val balanceTransformer = DetailsBalanceTransformer(
|
stateFactory.getDeactivatedState(state)
|
||||||
fiatBalance = state.balance.fiatBalance,
|
|
||||||
isMuted = state.source != StatusSource.ACTUAL,
|
|
||||||
)
|
|
||||||
uiState.update {
|
|
||||||
balanceTransformer.transform(
|
|
||||||
stateFactory.getDeactivatedState(
|
|
||||||
hasWithdrawableBalance = state.balance.hasWithdrawableAmount,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
is PaymentAccountStatusValue.Loaded -> {
|
is PaymentAccountStatusValue.Loaded -> {
|
||||||
fetchAddToWalletBanner()
|
fetchAddToWalletBanner()
|
||||||
fetchCashbackBlock()
|
fetchCashbackBlock()
|
||||||
val balanceTransformer = DetailsBalanceTransformer(
|
uiState.update { stateFactory.getLoadedState(state) }
|
||||||
fiatBalance = state.balance.fiatBalance,
|
|
||||||
isMuted = !state.isFresh,
|
|
||||||
)
|
|
||||||
uiState.update { balanceTransformer.transform(stateFactory.getLoadedState(state)) }
|
|
||||||
}
|
}
|
||||||
is PaymentAccountStatusValue.Inactive -> uiState.update {
|
is PaymentAccountStatusValue.Inactive -> uiState.update {
|
||||||
stateFactory.getInactiveState(state)
|
stateFactory.getInactiveState(state)
|
||||||
|
|
@ -468,12 +457,20 @@ internal class TangemPayDetailsModel @Inject constructor(
|
||||||
router.push(TangemPayAccountDetailsInnerRoute.CardDetails(cardId = cardId))
|
router.push(TangemPayAccountDetailsInnerRoute.CardDetails(cardId = cardId))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAddCardClick() {
|
override fun onAddCardClick(tariffState: TangemPayTariffPlanState?) {
|
||||||
analytics.send(TangemPayAnalyticsEvents.AddExtraCardClicked())
|
analytics.send(TangemPayAnalyticsEvents.AddExtraCardClicked())
|
||||||
modelScope.launch {
|
modelScope.launch {
|
||||||
val offer = getCustomerOffers.additionalCardOffer(userWalletId).getOrNull()
|
val offer = getCustomerOffers.additionalCardOffer(userWalletId).getOrNull()
|
||||||
if (offer == null) {
|
if (offer == null) {
|
||||||
uiMessageSender.send(message = TangemPayMessagesFactory.createGenericError())
|
val message = if (tariffState != null && tariffState.tariff.plan.isBasicTier) {
|
||||||
|
TangemPayMessagesFactory.createMaximumCardsForPlanIssuedMessage(
|
||||||
|
onUpgradeClick = { onClickCurrentPlan(tariffState.tariff) }
|
||||||
|
.takeIf { !tariffState.isPlanTransitioningState },
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
TangemPayMessagesFactory.createMaximumCardsIssuedMessage()
|
||||||
|
}
|
||||||
|
uiMessageSender.send(message)
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
analytics.send(TangemPayAnalyticsEvents.IssueAdditionalCardPopupShown())
|
analytics.send(TangemPayAnalyticsEvents.IssueAdditionalCardPopupShown())
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,6 @@ internal val AccountStatus.Payment.tariffPlan: TangemPayCustomerTariffPlan?
|
||||||
else -> error("TangemPayDetails opened with unsupported status: $v")
|
else -> error("TangemPayDetails opened with unsupported status: $v")
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val AccountStatus.Payment.isDeactivated: Boolean
|
|
||||||
get() = value is PaymentAccountStatusValue.Deactivated
|
|
||||||
|
|
||||||
internal val PaymentAccountStatusValue.Loaded.isFresh: Boolean
|
internal val PaymentAccountStatusValue.Loaded.isFresh: Boolean
|
||||||
get() = source.isActual() && error == null
|
get() = source.isActual() && error == null
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package com.tangem.features.tangempay.utils
|
||||||
|
|
||||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig.ShowRefreshState
|
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig.ShowRefreshState
|
||||||
import com.tangem.domain.models.account.TangemPayCustomerTariffPlan
|
import com.tangem.domain.models.account.TangemPayCustomerTariffPlan
|
||||||
|
import com.tangem.domain.models.account.TangemPayTariffPlanState
|
||||||
|
|
||||||
internal interface TangemPayDetailIntents {
|
internal interface TangemPayDetailIntents {
|
||||||
fun onContactSupportClicked()
|
fun onContactSupportClicked()
|
||||||
|
|
@ -15,6 +16,6 @@ internal interface TangemPayDetailIntents {
|
||||||
fun onClickCurrentPlan(tariffPlan: TangemPayCustomerTariffPlan)
|
fun onClickCurrentPlan(tariffPlan: TangemPayCustomerTariffPlan)
|
||||||
fun onCancelPlusTransition(orderId: String)
|
fun onCancelPlusTransition(orderId: String)
|
||||||
fun onCardClick(cardId: String)
|
fun onCardClick(cardId: String)
|
||||||
fun onAddCardClick()
|
fun onAddCardClick(tariffState: TangemPayTariffPlanState?)
|
||||||
fun onRemoveAccount()
|
fun onRemoveAccount()
|
||||||
}
|
}
|
||||||
|
|
@ -187,4 +187,50 @@ internal object TangemPayMessagesFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun createMaximumCardsIssuedMessage(): BottomSheetMessage {
|
||||||
|
return bottomSheetMessage {
|
||||||
|
infoBlock {
|
||||||
|
icon(R.drawable.ic_warning_20) {
|
||||||
|
backgroundType = MessageBottomSheetUM.Icon.BackgroundType.Warning
|
||||||
|
}
|
||||||
|
title = resourceReference(R.string.tangempay_maximum_cards_issued_title)
|
||||||
|
body = resourceReference(R.string.tangempay_maximum_cards_issued_description)
|
||||||
|
}
|
||||||
|
primaryButton {
|
||||||
|
text = resourceReference(R.string.common_got_it)
|
||||||
|
onClick { closeBs() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createMaximumCardsForPlanIssuedMessage(onUpgradeClick: (() -> Unit)?): BottomSheetMessage {
|
||||||
|
return bottomSheetMessage {
|
||||||
|
infoBlock {
|
||||||
|
icon(R.drawable.ic_warning_20) {
|
||||||
|
backgroundType = MessageBottomSheetUM.Icon.BackgroundType.Warning
|
||||||
|
}
|
||||||
|
title = resourceReference(R.string.tangempay_maximum_cards_issued_for_plan_title)
|
||||||
|
body = resourceReference(R.string.tangempay_maximum_cards_issued_for_plan_description)
|
||||||
|
}
|
||||||
|
if (onUpgradeClick != null) {
|
||||||
|
secondaryButton {
|
||||||
|
text = resourceReference(R.string.common_cancel)
|
||||||
|
onClick { closeBs() }
|
||||||
|
}
|
||||||
|
primaryButton {
|
||||||
|
text = resourceReference(R.string.tangempay_maximum_cards_issued_for_plan_upgrade_btn)
|
||||||
|
onClick {
|
||||||
|
onUpgradeClick()
|
||||||
|
closeBs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
primaryButton {
|
||||||
|
text = resourceReference(R.string.common_got_it)
|
||||||
|
onClick { closeBs() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -113,7 +113,7 @@ internal class TangemPayDetailsStateFactoryTest {
|
||||||
@Test
|
@Test
|
||||||
fun `GIVEN deactivated with positive balance WHEN getDeactivatedState THEN withdraw enabled`() {
|
fun `GIVEN deactivated with positive balance WHEN getDeactivatedState THEN withdraw enabled`() {
|
||||||
// Act
|
// Act
|
||||||
val state = factory.getDeactivatedState(hasWithdrawableBalance = true)
|
val state = factory.getDeactivatedState(deactivatedStatus(availableForWithdrawal = BigDecimal.TEN))
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
assertThat(state.addFundsButton.isEnabled).isTrue()
|
assertThat(state.addFundsButton.isEnabled).isTrue()
|
||||||
|
|
@ -123,7 +123,7 @@ internal class TangemPayDetailsStateFactoryTest {
|
||||||
@Test
|
@Test
|
||||||
fun `GIVEN deactivated with zero balance WHEN getDeactivatedState THEN withdraw disabled`() {
|
fun `GIVEN deactivated with zero balance WHEN getDeactivatedState THEN withdraw disabled`() {
|
||||||
// Act
|
// Act
|
||||||
val state = factory.getDeactivatedState(hasWithdrawableBalance = false)
|
val state = factory.getDeactivatedState(deactivatedStatus(availableForWithdrawal = BigDecimal.ZERO))
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
assertThat(state.addFundsButton.isEnabled).isTrue()
|
assertThat(state.addFundsButton.isEnabled).isTrue()
|
||||||
|
|
@ -159,22 +159,30 @@ internal class TangemPayDetailsStateFactoryTest {
|
||||||
every { source } returns statusSource
|
every { source } returns statusSource
|
||||||
every { error } returns statusError
|
every { error } returns statusError
|
||||||
every { cards } returns statusCards
|
every { cards } returns statusCards
|
||||||
every { balance } returns PaymentAccountStatusValue.Balance(
|
every { balance } returns balance(availableForWithdrawal)
|
||||||
fiatBalance = PaymentAccountStatusValue.FiatBalance(
|
|
||||||
availableBalance = BigDecimal.ZERO,
|
|
||||||
currency = "USD",
|
|
||||||
),
|
|
||||||
cryptoBalance = PaymentAccountStatusValue.CryptoBalance(
|
|
||||||
id = "id",
|
|
||||||
chainId = 1L,
|
|
||||||
depositAddress = "address",
|
|
||||||
tokenContractAddress = "contract",
|
|
||||||
balance = BigDecimal.ZERO,
|
|
||||||
),
|
|
||||||
availableForWithdrawal = availableForWithdrawal,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun deactivatedStatus(availableForWithdrawal: BigDecimal): PaymentAccountStatusValue.Deactivated =
|
||||||
|
mockk(relaxed = true) {
|
||||||
|
every { source } returns StatusSource.ACTUAL
|
||||||
|
every { balance } returns balance(availableForWithdrawal)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun balance(availableForWithdrawal: BigDecimal) = PaymentAccountStatusValue.Balance(
|
||||||
|
fiatBalance = PaymentAccountStatusValue.FiatBalance(
|
||||||
|
availableBalance = BigDecimal.ZERO,
|
||||||
|
currency = "USD",
|
||||||
|
),
|
||||||
|
cryptoBalance = PaymentAccountStatusValue.CryptoBalance(
|
||||||
|
id = "id",
|
||||||
|
chainId = 1L,
|
||||||
|
depositAddress = "address",
|
||||||
|
tokenContractAddress = "contract",
|
||||||
|
balance = BigDecimal.ZERO,
|
||||||
|
),
|
||||||
|
availableForWithdrawal = availableForWithdrawal,
|
||||||
|
)
|
||||||
|
|
||||||
internal data class ButtonStateCase(
|
internal data class ButtonStateCase(
|
||||||
val source: StatusSource,
|
val source: StatusSource,
|
||||||
val error: PaymentAccountStatusValue.Error?,
|
val error: PaymentAccountStatusValue.Error?,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue