Updated on 2026-08-14
This commit is contained in:
parent
fc7b758aff
commit
c5d0ba8f58
25 changed files with 448 additions and 133 deletions
|
|
@ -53,6 +53,7 @@ class MoshiModule {
|
|||
.withSubtype(PaymentAccountStatusValueDM.UnderReview::class.java, "kyc_status")
|
||||
.withSubtype(PaymentAccountStatusValueDM.IssuingCard::class.java, "issuing_card")
|
||||
.withSubtype(PaymentAccountStatusValueDM.ActiveCard::class.java, "active_card")
|
||||
.withSubtype(PaymentAccountStatusValueDM.DeactivatedAccount::class.java, "deactivated_account")
|
||||
.withSubtype(PaymentAccountStatusValueDM.CardIssueFailed::class.java, "card_issue_failed"),
|
||||
)
|
||||
.add(
|
||||
|
|
|
|||
|
|
@ -56,6 +56,12 @@ sealed interface PaymentAccountStatusValueDM {
|
|||
@Json(name = "customer_id") val customerId: String,
|
||||
) : PaymentAccountStatusValueDM
|
||||
|
||||
@NameLabel("deactivated_account")
|
||||
data class DeactivatedAccount(
|
||||
@Json(name = "deactivated_account") val marker: Boolean = true,
|
||||
@Json(name = "fiat_balance") val fiatBalance: FiatBalanceDM,
|
||||
) : PaymentAccountStatusValueDM
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class FiatBalanceDM(
|
||||
@Json(name = "available_balance") val availableBalance: BigDecimal,
|
||||
|
|
|
|||
|
|
@ -1568,6 +1568,8 @@
|
|||
<string name="tangem_pay_unfreeze_card_success">Your card is unfrozen.</string>
|
||||
<string name="tangem_pay_withdrawal">Withdrawal</string>
|
||||
<string name="tangempay_account_unable_to_use_rooted">Unable to use on rooted device</string>
|
||||
<string name="tangempay_account_deactivated_message_title">Your card was deactivated</string>
|
||||
<string name="tangempay_account_deactivated_message_subtitle">This was done due to regulatory requirements. Anyway withdrawals are still available.</string>
|
||||
<string name="tangempay_cancel_kyc">Hide KYC from main screen</string>
|
||||
<string name="tangempay_card_details_add_funds">Add funds</string>
|
||||
<string name="tangempay_card_details_add_funds_subtitle">Top-up options</string>
|
||||
|
|
@ -1632,6 +1634,7 @@
|
|||
<string name="tangempay_kyc_failed_title">Unfortunately, we couldn\'t verify your identity </string>
|
||||
<string name="tangempay_kyc_has_failed">KYC rejected</string>
|
||||
<string name="tangempay_kyc_in_progress">KYC in progress</string>
|
||||
<string name="tangempay_status_deactivated">Card deactivated</string>
|
||||
<string name="tangempay_kyc_in_progress_notification_button">View Status</string>
|
||||
<string name="tangempay_kyc_in_progress_notification_title">KYC in progress for Tangem Pay</string>
|
||||
<string name="tangempay_kyc_in_progress_popup_description">Documents are usually verified automatically within 5 minutes. In rare cases, if manual review is required, it may take up to 48 hours.</string>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@ android {
|
|||
namespace = "com.tangem.data.visa"
|
||||
}
|
||||
|
||||
tasks.withType<Test>().configureEach {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
/** Project - Data */
|
||||
|
|
@ -68,4 +72,9 @@ dependencies {
|
|||
/** DI */
|
||||
implementation(deps.hilt.android)
|
||||
kapt(deps.hilt.kapt)
|
||||
|
||||
/** Test */
|
||||
testRuntimeOnly(deps.test.junit5.engine)
|
||||
testImplementation(projects.common.test)
|
||||
testImplementation(projects.test.core)
|
||||
}
|
||||
|
|
@ -52,6 +52,9 @@ internal object PaymentAccountStatusValueDMConverter :
|
|||
customerId = value.customerId,
|
||||
)
|
||||
is PaymentAccountStatusValue.Empty -> PaymentAccountStatusValueDM.Empty()
|
||||
is PaymentAccountStatusValue.Deactivated -> PaymentAccountStatusValueDM.DeactivatedAccount(
|
||||
fiatBalance = value.fiatBalance.toDM(),
|
||||
)
|
||||
// Transient statuses are not persisted
|
||||
is PaymentAccountStatusValue.Loading,
|
||||
is PaymentAccountStatusValue.Error.ExposedDevice,
|
||||
|
|
@ -101,6 +104,10 @@ internal object PaymentAccountStatusValueDMConverter :
|
|||
kycStatus = value.kycStatus,
|
||||
customerId = value.customerId,
|
||||
)
|
||||
is PaymentAccountStatusValueDM.DeactivatedAccount -> PaymentAccountStatusValue.Deactivated(
|
||||
source = StatusSource.CACHE,
|
||||
fiatBalance = value.fiatBalance.toDomain(),
|
||||
)
|
||||
null -> PaymentAccountStatusValue.Error.Unavailable
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,16 +48,6 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
val account = Account.Payment(userWalletId = params.userWalletId)
|
||||
logger.i("fetch: ${params.userWalletId.stringValue}")
|
||||
|
||||
if (onboardingRepository.isTangemPayDeactivated(params.userWalletId)) {
|
||||
return@catchOn paymentAccountStatusesStore.store(
|
||||
userWalletId = params.userWalletId,
|
||||
status = AccountStatus.Payment(
|
||||
account = account,
|
||||
value = PaymentAccountStatusValue.Empty,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if (deviceSecurity.isSecurityExposed()) {
|
||||
logger.i("fetch security info: rooted: ${deviceSecurity.isRooted}")
|
||||
logger.i("fetch security info: xposed: ${deviceSecurity.isXposed}")
|
||||
|
|
@ -254,20 +244,31 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
private fun CustomerInfo.mapToPaymentAccountStatus(): PaymentAccountStatusValue {
|
||||
val cardInfo = this.cardInfo
|
||||
val productInstance = this.productInstance
|
||||
return if (kycStatus != KycStatus.APPROVED && !customerId.isNullOrEmpty()) {
|
||||
PaymentAccountStatusValue.UnderReview(
|
||||
source = StatusSource.ACTUAL,
|
||||
kycStatus = kycStatus,
|
||||
customerId = requireNotNull(customerId) { "CustomerId must not be null" },
|
||||
)
|
||||
} else if (cardInfo != null && productInstance != null && !customerId.isNullOrEmpty()) {
|
||||
convertToContentState(
|
||||
|
||||
val isDeactivated = productInstance?.status == CustomerInfo.ProductInstance.Status.DEACTIVATED
|
||||
val isFormer = state == CustomerInfo.State.FORMER
|
||||
val fiatBalance = fiatBalance
|
||||
|
||||
return when {
|
||||
kycStatus != KycStatus.APPROVED && !customerId.isNullOrEmpty() -> {
|
||||
PaymentAccountStatusValue.UnderReview(
|
||||
source = StatusSource.ACTUAL,
|
||||
kycStatus = kycStatus,
|
||||
customerId = requireNotNull(customerId) { "CustomerId must not be null" },
|
||||
)
|
||||
}
|
||||
fiatBalance != null && (isDeactivated || isFormer) -> {
|
||||
PaymentAccountStatusValue.Deactivated(
|
||||
source = StatusSource.ACTUAL,
|
||||
fiatBalance = fiatBalance,
|
||||
)
|
||||
}
|
||||
cardInfo != null && productInstance != null && !customerId.isNullOrEmpty() -> convertToContentState(
|
||||
productInstance = productInstance,
|
||||
cardInfo = cardInfo,
|
||||
customerId = requireNotNull(customerId) { "CustomerId must not be null" },
|
||||
)
|
||||
} else {
|
||||
PaymentAccountStatusValue.IssuingCard(source = StatusSource.ACTUAL)
|
||||
else -> PaymentAccountStatusValue.IssuingCard(source = StatusSource.ACTUAL)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -306,7 +307,6 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
return when (this) {
|
||||
is VisaApiError.RefreshTokenExpired -> PaymentAccountStatusValue.Error.NotSynced
|
||||
is VisaApiError.NotPaeraCustomer -> constructNotCreatedOrEmptyStatus(userWalletId)
|
||||
is VisaApiError.Deactivated -> constructNotCreatedOrEmptyStatus(userWalletId)
|
||||
else -> PaymentAccountStatusValue.Error.Unavailable
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package com.tangem.data.pay.repository
|
|||
|
||||
import arrow.core.Either
|
||||
import arrow.core.flatMap
|
||||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.data.pay.store.PaymentAccountStatusesStore
|
||||
|
|
@ -11,6 +10,7 @@ import com.tangem.datasource.api.pay.models.request.DeeplinkValidityRequest
|
|||
import com.tangem.datasource.api.pay.models.request.OrderRequest
|
||||
import com.tangem.datasource.api.pay.models.request.SetTangemPayEnabledRequest
|
||||
import com.tangem.datasource.api.pay.models.response.CustomerMeResponse
|
||||
import com.tangem.datasource.api.pay.models.response.FiatBalance
|
||||
import com.tangem.datasource.api.pay.models.response.OrderResponse
|
||||
import com.tangem.datasource.local.visa.TangemPayCardFrozenStateStore
|
||||
import com.tangem.datasource.local.visa.TangemPayStorage
|
||||
|
|
@ -101,10 +101,8 @@ internal class DefaultOnboardingRepository @Inject constructor(
|
|||
val isFormer = result?.state?.let { CustomerInfo.State.fromString(it) } == CustomerInfo.State.FORMER
|
||||
if (isDeactivated || isFormer) {
|
||||
tangemPayStorage.storeIsTangemPayDeactivated(userWalletId)
|
||||
VisaApiError.Deactivated.left()
|
||||
} else {
|
||||
getCustomerInfo(userWalletId = userWalletId, response = result).right()
|
||||
}
|
||||
getCustomerInfo(userWalletId = userWalletId, response = result).right()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -180,10 +178,7 @@ internal class DefaultOnboardingRepository @Inject constructor(
|
|||
currencyCode = fiatBalance.currency,
|
||||
depositAddress = response.depositAddress,
|
||||
isPinSet = response.card?.isPinSet == true,
|
||||
fiatBalance = PaymentAccountStatusValue.FiatBalance(
|
||||
availableBalance = fiatBalance.availableBalance,
|
||||
currency = fiatBalance.currency,
|
||||
),
|
||||
fiatBalance = fiatBalance.toDomain(),
|
||||
cryptoBalance = PaymentAccountStatusValue.CryptoBalance(
|
||||
id = cryptoBalance.id,
|
||||
chainId = cryptoBalance.chainId.toLong(),
|
||||
|
|
@ -202,13 +197,20 @@ internal class DefaultOnboardingRepository @Inject constructor(
|
|||
}
|
||||
cardFrozenStateStore.store(key = instance.cardId, value = cardFrozenState)
|
||||
|
||||
ProductInstance(id = instance.id, cardId = instance.cardId, frozenState = cardFrozenState)
|
||||
ProductInstance(
|
||||
id = instance.id,
|
||||
cardId = instance.cardId,
|
||||
frozenState = cardFrozenState,
|
||||
status = instance.status.toDomain(),
|
||||
)
|
||||
}
|
||||
return CustomerInfo(
|
||||
customerId = response?.id,
|
||||
productInstance = productInstance,
|
||||
kycStatus = kycStatus,
|
||||
cardInfo = cardInfo,
|
||||
state = response?.state?.let { CustomerInfo.State.fromString(it) } ?: CustomerInfo.State.UNDEFINED,
|
||||
fiatBalance = fiatBalance?.toDomain(),
|
||||
).also {
|
||||
lastFetchedCustomerInfoMap[userWalletId] = it
|
||||
}
|
||||
|
|
@ -290,4 +292,24 @@ internal class DefaultOnboardingRepository @Inject constructor(
|
|||
setHideMainOnboardingBanner(userWalletId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun FiatBalance.toDomain() = PaymentAccountStatusValue.FiatBalance(
|
||||
availableBalance = availableBalance,
|
||||
currency = currency,
|
||||
)
|
||||
|
||||
private fun CustomerMeResponse.ProductInstance.Status.toDomain() = when (this) {
|
||||
CustomerMeResponse.ProductInstance.Status.NEW -> ProductInstance.Status.NEW
|
||||
CustomerMeResponse.ProductInstance.Status.READY_FOR_MANUFACTURING -> ProductInstance.Status.READY_FOR_MANUFACTURING
|
||||
CustomerMeResponse.ProductInstance.Status.MANUFACTURING -> ProductInstance.Status.MANUFACTURING
|
||||
CustomerMeResponse.ProductInstance.Status.SENT_TO_DELIVERY -> ProductInstance.Status.SENT_TO_DELIVERY
|
||||
CustomerMeResponse.ProductInstance.Status.DELIVERED -> ProductInstance.Status.DELIVERED
|
||||
CustomerMeResponse.ProductInstance.Status.ACTIVATING -> ProductInstance.Status.ACTIVATING
|
||||
CustomerMeResponse.ProductInstance.Status.ACTIVE -> ProductInstance.Status.ACTIVE
|
||||
CustomerMeResponse.ProductInstance.Status.BLOCKED -> ProductInstance.Status.BLOCKED
|
||||
CustomerMeResponse.ProductInstance.Status.DEACTIVATING -> ProductInstance.Status.DEACTIVATING
|
||||
CustomerMeResponse.ProductInstance.Status.DEACTIVATED -> ProductInstance.Status.DEACTIVATED
|
||||
CustomerMeResponse.ProductInstance.Status.CANCELED -> ProductInstance.Status.CANCELED
|
||||
CustomerMeResponse.ProductInstance.Status.UNKNOWN -> ProductInstance.Status.UNKNOWN
|
||||
}
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
package com.tangem.data.pay.converter
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.tangem.datasource.local.visa.entity.PaymentAccountStatusValueDM
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import java.math.BigDecimal
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
internal class PaymentAccountStatusValueDMConverterTest {
|
||||
|
||||
@Nested
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
inner class Convert {
|
||||
|
||||
@Test
|
||||
fun `GIVEN domain Empty WHEN convert THEN returns DM Empty`() {
|
||||
// GIVEN
|
||||
val domain = PaymentAccountStatusValue.Empty
|
||||
|
||||
// WHEN
|
||||
val result = PaymentAccountStatusValueDMConverter.convert(domain)
|
||||
|
||||
// THEN
|
||||
assertThat(result).isInstanceOf(PaymentAccountStatusValueDM.Empty::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN domain Deactivated with balance WHEN convert THEN returns DM DeactivatedAccount with same balance`() {
|
||||
// GIVEN
|
||||
val domain = PaymentAccountStatusValue.Deactivated(
|
||||
source = StatusSource.ACTUAL,
|
||||
fiatBalance = PaymentAccountStatusValue.FiatBalance(
|
||||
availableBalance = BigDecimal("100"),
|
||||
currency = "USD",
|
||||
)
|
||||
)
|
||||
|
||||
// WHEN
|
||||
val result = PaymentAccountStatusValueDMConverter.convert(domain)
|
||||
|
||||
// THEN
|
||||
assertThat(result).isInstanceOf(PaymentAccountStatusValueDM.DeactivatedAccount::class.java)
|
||||
val dm = result as PaymentAccountStatusValueDM.DeactivatedAccount
|
||||
assertThat(dm.fiatBalance.availableBalance).isEqualTo(BigDecimal("100"))
|
||||
assertThat(dm.fiatBalance.currency).isEqualTo("USD")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN domain Loading WHEN convert THEN returns null (transient, not persisted)`() {
|
||||
// GIVEN
|
||||
val domain = PaymentAccountStatusValue.Loading
|
||||
|
||||
// WHEN
|
||||
val result = PaymentAccountStatusValueDMConverter.convert(domain)
|
||||
|
||||
// THEN
|
||||
assertThat(result).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN domain Error Unavailable WHEN convert THEN returns null (transient, not persisted)`() {
|
||||
// GIVEN
|
||||
val domain = PaymentAccountStatusValue.Error.Unavailable
|
||||
|
||||
// WHEN
|
||||
val result = PaymentAccountStatusValueDMConverter.convert(domain)
|
||||
|
||||
// THEN
|
||||
assertThat(result).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN domain NotCreated WHEN convert THEN returns DM NotCreated`() {
|
||||
// GIVEN
|
||||
val domain = PaymentAccountStatusValue.NotCreated
|
||||
|
||||
// WHEN
|
||||
val result = PaymentAccountStatusValueDMConverter.convert(domain)
|
||||
|
||||
// THEN
|
||||
assertThat(result).isInstanceOf(PaymentAccountStatusValueDM.NotCreated::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
inner class ConvertBack {
|
||||
|
||||
@Test
|
||||
fun `GIVEN DM Empty WHEN convertBack THEN returns domain Empty`() {
|
||||
// GIVEN
|
||||
val dm = PaymentAccountStatusValueDM.Empty()
|
||||
|
||||
// WHEN
|
||||
val result = PaymentAccountStatusValueDMConverter.convertBack(dm)
|
||||
|
||||
// THEN
|
||||
assertThat(result).isEqualTo(PaymentAccountStatusValue.Empty)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN DM DeactivatedAccount WHEN convertBack THEN returns domain Deactivated with CACHE source`() {
|
||||
// GIVEN
|
||||
val dm = PaymentAccountStatusValueDM.DeactivatedAccount(
|
||||
fiatBalance = PaymentAccountStatusValueDM.FiatBalanceDM(
|
||||
availableBalance = BigDecimal("200"),
|
||||
currency = "EUR",
|
||||
)
|
||||
)
|
||||
|
||||
// WHEN
|
||||
val result = PaymentAccountStatusValueDMConverter.convertBack(dm)
|
||||
|
||||
// THEN
|
||||
assertThat(result).isInstanceOf(PaymentAccountStatusValue.Deactivated::class.java)
|
||||
val deactivated = result as PaymentAccountStatusValue.Deactivated
|
||||
assertThat(deactivated.source).isEqualTo(StatusSource.CACHE)
|
||||
assertThat(deactivated.fiatBalance.availableBalance).isEqualTo(BigDecimal("200"))
|
||||
assertThat(deactivated.fiatBalance.currency).isEqualTo("EUR")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN null DM WHEN convertBack THEN returns Error Unavailable`() {
|
||||
// GIVEN / WHEN
|
||||
val result = PaymentAccountStatusValueDMConverter.convertBack(null)
|
||||
|
||||
// THEN
|
||||
assertThat(result).isEqualTo(PaymentAccountStatusValue.Error.Unavailable)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN DM NotCreated WHEN convertBack THEN returns domain NotCreated`() {
|
||||
// GIVEN
|
||||
val dm = PaymentAccountStatusValueDM.NotCreated()
|
||||
|
||||
// WHEN
|
||||
val result = PaymentAccountStatusValueDMConverter.convertBack(dm)
|
||||
|
||||
// THEN
|
||||
assertThat(result).isEqualTo(PaymentAccountStatusValue.NotCreated)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -56,6 +56,7 @@ class IsAccountsModeEnabledUseCase(
|
|||
is PaymentAccountStatusValue.Loading,
|
||||
is PaymentAccountStatusValue.Locked,
|
||||
is PaymentAccountStatusValue.UnderReview,
|
||||
is PaymentAccountStatusValue.Deactivated,
|
||||
-> true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,6 +150,21 @@ class IsAccountsModeEnabledUseCaseTest {
|
|||
Truth.assertThat(actual).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN payment account is Deactivated WHEN invoke THEN returns true`() = runTest {
|
||||
// GIVEN
|
||||
val statusList = createAccountStatusList(
|
||||
statuses = listOf(mockCryptoPortfolio(), mockPayment(mockk<PaymentAccountStatusValue.Deactivated>())),
|
||||
)
|
||||
every { multiAccountStatusListSupplier.invoke() } returns flowOf(listOf(statusList))
|
||||
|
||||
// WHEN
|
||||
val actual = useCase.invoke().first()
|
||||
|
||||
// THEN
|
||||
Truth.assertThat(actual).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `returns true when multiple status lists and one has two crypto portfolios`() = runTest {
|
||||
val statusList1 = createAccountStatusList(statuses = listOf(mockCryptoPortfolio()))
|
||||
|
|
@ -270,6 +285,21 @@ class IsAccountsModeEnabledUseCaseTest {
|
|||
Truth.assertThat(actual).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN payment account is Deactivated WHEN invokeSync THEN returns true`() = runTest {
|
||||
// GIVEN
|
||||
val statusList = createAccountStatusList(
|
||||
statuses = listOf(mockCryptoPortfolio(), mockPayment(mockk<PaymentAccountStatusValue.Deactivated>())),
|
||||
)
|
||||
coEvery { multiAccountStatusListSupplier.getSyncOrNull(Unit, any()) } returns listOf(statusList)
|
||||
|
||||
// WHEN
|
||||
val actual = useCase.invokeSync()
|
||||
|
||||
// THEN
|
||||
Truth.assertThat(actual).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `returns true when multiple status lists and one has loaded payment`() = runTest {
|
||||
val statusList1 = createAccountStatusList(statuses = listOf(mockCryptoPortfolio()))
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ sealed class PaymentAccountStatusValue {
|
|||
is Loading -> TotalFiatBalance.Loading
|
||||
is Locked -> TotalFiatBalance.Loaded(amount = fiatBalance.availableBalance, source = source)
|
||||
is Loaded -> TotalFiatBalance.Loaded(amount = fiatBalance.availableBalance, source = source)
|
||||
is Deactivated -> TotalFiatBalance.Loaded(amount = fiatBalance.availableBalance, source = source)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -40,6 +41,7 @@ sealed class PaymentAccountStatusValue {
|
|||
is Loaded -> copy(source = source)
|
||||
is Locked -> copy(source = source)
|
||||
is UnderReview -> copy(source = source)
|
||||
is Deactivated -> copy(source = source)
|
||||
is Loading,
|
||||
is Empty,
|
||||
is NotCreated,
|
||||
|
|
@ -88,6 +90,18 @@ sealed class PaymentAccountStatusValue {
|
|||
@Serializable
|
||||
data class IssuingCard(override val source: StatusSource) : PaymentAccountStatusValue()
|
||||
|
||||
/**
|
||||
* Represents a state where the account is deactivated.
|
||||
*
|
||||
* @property source The source of the status information.
|
||||
* @property fiatBalance The fiat balance details.
|
||||
*/
|
||||
@Serializable
|
||||
data class Deactivated(
|
||||
override val source: StatusSource,
|
||||
val fiatBalance: FiatBalance,
|
||||
) : PaymentAccountStatusValue()
|
||||
|
||||
/**
|
||||
* Represents a state where the payment account is locked.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -11,4 +11,5 @@ data class TangemPayDetailsConfig(
|
|||
val cardFrozenState: TangemPayCardFrozenState,
|
||||
val cardNumberEnd: String,
|
||||
val chainId: Int,
|
||||
val isTangemPayDeactivated: Boolean,
|
||||
)
|
||||
|
|
@ -57,7 +57,6 @@ sealed class VisaApiError(
|
|||
data object CustomerIsBlocked : VisaApiError(104110210)
|
||||
data object UnknownWithoutCode : VisaApiError(104110999)
|
||||
data class Unknown(override val errorCode: Int) : VisaApiError(errorCode)
|
||||
data object Deactivated : VisaApiError(0)
|
||||
|
||||
fun isUnknown() = this is UnknownWithoutCode || this is Unknown
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ data class CustomerInfo(
|
|||
val productInstance: ProductInstance?,
|
||||
val kycStatus: KycStatus,
|
||||
val cardInfo: CardInfo?,
|
||||
val state: State,
|
||||
val fiatBalance: PaymentAccountStatusValue.FiatBalance?,
|
||||
) {
|
||||
enum class State {
|
||||
NEW,
|
||||
|
|
@ -49,7 +51,23 @@ data class CustomerInfo(
|
|||
val id: String,
|
||||
val cardId: String,
|
||||
val frozenState: TangemPayCardFrozenState,
|
||||
)
|
||||
val status: Status,
|
||||
) {
|
||||
enum class Status {
|
||||
NEW,
|
||||
READY_FOR_MANUFACTURING,
|
||||
MANUFACTURING,
|
||||
SENT_TO_DELIVERY,
|
||||
DELIVERED,
|
||||
ACTIVATING,
|
||||
ACTIVE,
|
||||
BLOCKED,
|
||||
DEACTIVATING,
|
||||
DEACTIVATED,
|
||||
CANCELED,
|
||||
UNKNOWN,
|
||||
}
|
||||
}
|
||||
|
||||
data class CardInfo(
|
||||
val lastFourDigits: String,
|
||||
|
|
|
|||
|
|
@ -6,5 +6,4 @@ sealed interface TangemPayCustomerInfoError {
|
|||
data object RefreshNeededError : TangemPayCustomerInfoError
|
||||
data object UnknownError : TangemPayCustomerInfoError
|
||||
data object ExposedDeviceError : TangemPayCustomerInfoError
|
||||
data object DeactivatedError : TangemPayCustomerInfoError
|
||||
}
|
||||
|
|
@ -62,10 +62,6 @@ class TangemPayMainScreenCustomerInfoUseCase(
|
|||
}
|
||||
|
||||
val result = proceedWithPaeraCustomerResult(userWalletId)
|
||||
if (result.leftOrNull() is TangemPayCustomerInfoError.DeactivatedError) {
|
||||
updateState(userWalletId, MainCustomerInfoContentState.Empty.right())
|
||||
return
|
||||
}
|
||||
updateState(userWalletId, result.map(MainCustomerInfoContentState::Content))
|
||||
} else {
|
||||
// if there's no tangem pay, check eligibility and show onboarding banner
|
||||
|
|
@ -172,7 +168,6 @@ class TangemPayMainScreenCustomerInfoUseCase(
|
|||
return when (this) {
|
||||
is VisaApiError.RefreshTokenExpired -> TangemPayCustomerInfoError.RefreshNeededError
|
||||
is VisaApiError.NotPaeraCustomer -> TangemPayCustomerInfoError.UnknownError
|
||||
is VisaApiError.Deactivated -> TangemPayCustomerInfoError.DeactivatedError
|
||||
else -> TangemPayCustomerInfoError.UnavailableError
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
|
|||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
import com.tangem.core.ui.components.dropdownmenu.TangemDropdownMenuItem
|
||||
import com.tangem.core.ui.components.notifications.NotificationConfig
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.themedColor
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
|
@ -12,6 +13,7 @@ import com.tangem.domain.visa.model.TangemPayCardFrozenState
|
|||
import com.tangem.features.tangempay.details.impl.R
|
||||
import com.tangem.features.tangempay.model.transformers.TangemPayCardFrozenStateConverter
|
||||
import com.tangem.features.tangempay.utils.TangemPayDetailIntents
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
|
|
@ -23,51 +25,13 @@ internal class TangemPayDetailsStateFactory(
|
|||
private val cardFrozenState: TangemPayCardFrozenState,
|
||||
private val converter: TangemPayCardFrozenStateConverter,
|
||||
) {
|
||||
|
||||
@Suppress("LongMethod")
|
||||
fun getInitialState(): TangemPayDetailsUM {
|
||||
val cardFrozenStateItem = when (cardFrozenState) {
|
||||
is TangemPayCardFrozenState.Pending -> null
|
||||
is TangemPayCardFrozenState.Frozen -> TangemPayDetailsTopBarMenuItem(
|
||||
type = TangemPayDetailsTopBarMenuItemType.UnfreezeCard,
|
||||
dropdownItem = TangemDropdownMenuItem(
|
||||
title = resourceReference(R.string.tangempay_card_details_unfreeze_card),
|
||||
textColor = themedColor { TangemTheme.colors.text.primary1 },
|
||||
onClick = intents::onClickUnfreezeCard,
|
||||
),
|
||||
)
|
||||
is TangemPayCardFrozenState.Unfrozen -> TangemPayDetailsTopBarMenuItem(
|
||||
type = TangemPayDetailsTopBarMenuItemType.FreezeCard,
|
||||
dropdownItem = TangemDropdownMenuItem(
|
||||
title = resourceReference(R.string.tangempay_card_details_freeze_card),
|
||||
textColor = themedColor { TangemTheme.colors.text.primary1 },
|
||||
onClick = intents::onClickFreezeCard,
|
||||
),
|
||||
)
|
||||
}
|
||||
fun getInitialState(isTangemPayDeactivated: Boolean): TangemPayDetailsUM {
|
||||
return TangemPayDetailsUM(
|
||||
topBarConfig = TangemPayDetailsTopBarConfig(
|
||||
onBackClick = onBack,
|
||||
onOpenMenu = onOpenMenu,
|
||||
items = listOfNotNull(
|
||||
TangemPayDetailsTopBarMenuItem(
|
||||
type = TangemPayDetailsTopBarMenuItemType.ChangePin,
|
||||
dropdownItem = TangemDropdownMenuItem(
|
||||
title = resourceReference(R.string.tangempay_card_details_pin_code),
|
||||
textColor = themedColor { TangemTheme.colors.text.primary1 },
|
||||
onClick = intents::onClickPinCode,
|
||||
),
|
||||
),
|
||||
TangemPayDetailsTopBarMenuItem(
|
||||
type = TangemPayDetailsTopBarMenuItemType.TermsAndLimits,
|
||||
dropdownItem = TangemDropdownMenuItem(
|
||||
title = resourceReference(R.string.tangem_pay_terms_limits),
|
||||
textColor = themedColor { TangemTheme.colors.text.primary1 },
|
||||
onClick = intents::onClickTermsAndLimits,
|
||||
),
|
||||
),
|
||||
cardFrozenStateItem,
|
||||
).toPersistentList(),
|
||||
items = getTopBarMenuItems().takeIf { !isTangemPayDeactivated },
|
||||
),
|
||||
pullToRefreshConfig = PullToRefreshConfig(
|
||||
isRefreshing = false,
|
||||
|
|
@ -92,17 +56,67 @@ internal class TangemPayDetailsStateFactory(
|
|||
addToWalletBlockState = null,
|
||||
isBalanceHidden = false,
|
||||
addFundsEnabled = true,
|
||||
cardFrozenState = converter.convert(cardFrozenState),
|
||||
betaNotificationConfig = NotificationConfig(
|
||||
title = resourceReference(R.string.tangem_pay_beta_notification_title),
|
||||
subtitle = resourceReference(R.string.tangem_pay_beta_notification_subtitle),
|
||||
iconResId = R.drawable.img_visa_notification,
|
||||
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
|
||||
text = resourceReference(R.string.common_contact_support),
|
||||
onClick = intents::onContactSupportClicked,
|
||||
),
|
||||
iconSize = 36.dp,
|
||||
),
|
||||
cardFrozenState = getCardFrozenState().takeIf { !isTangemPayDeactivated },
|
||||
betaNotificationConfig = getBetaNotificationConfig().takeIf { !isTangemPayDeactivated },
|
||||
accountDeactivatedNotificationConfig = NotificationConfig(
|
||||
title = TextReference.Res(R.string.tangempay_account_deactivated_message_title),
|
||||
subtitle = TextReference.Res(R.string.tangempay_account_deactivated_message_subtitle),
|
||||
iconResId = R.drawable.img_attention_20,
|
||||
).takeIf { isTangemPayDeactivated },
|
||||
)
|
||||
}
|
||||
|
||||
private fun getCardFrozenState() = converter.convert(cardFrozenState)
|
||||
|
||||
private fun getBetaNotificationConfig() = NotificationConfig(
|
||||
title = resourceReference(R.string.tangem_pay_beta_notification_title),
|
||||
subtitle = resourceReference(R.string.tangem_pay_beta_notification_subtitle),
|
||||
iconResId = R.drawable.img_visa_notification,
|
||||
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
|
||||
text = resourceReference(R.string.common_contact_support),
|
||||
onClick = intents::onContactSupportClicked,
|
||||
),
|
||||
iconSize = 36.dp,
|
||||
)
|
||||
|
||||
private fun getTopBarMenuItems(): ImmutableList<TangemPayDetailsTopBarMenuItem> {
|
||||
val cardFrozenStateItem = when (cardFrozenState) {
|
||||
is TangemPayCardFrozenState.Pending -> null
|
||||
is TangemPayCardFrozenState.Frozen -> TangemPayDetailsTopBarMenuItem(
|
||||
type = TangemPayDetailsTopBarMenuItemType.UnfreezeCard,
|
||||
dropdownItem = TangemDropdownMenuItem(
|
||||
title = resourceReference(R.string.tangempay_card_details_unfreeze_card),
|
||||
textColor = themedColor { TangemTheme.colors.text.primary1 },
|
||||
onClick = intents::onClickUnfreezeCard,
|
||||
),
|
||||
)
|
||||
is TangemPayCardFrozenState.Unfrozen -> TangemPayDetailsTopBarMenuItem(
|
||||
type = TangemPayDetailsTopBarMenuItemType.FreezeCard,
|
||||
dropdownItem = TangemDropdownMenuItem(
|
||||
title = resourceReference(R.string.tangempay_card_details_freeze_card),
|
||||
textColor = themedColor { TangemTheme.colors.text.primary1 },
|
||||
onClick = intents::onClickFreezeCard,
|
||||
),
|
||||
)
|
||||
}
|
||||
return listOfNotNull(
|
||||
TangemPayDetailsTopBarMenuItem(
|
||||
type = TangemPayDetailsTopBarMenuItemType.ChangePin,
|
||||
dropdownItem = TangemDropdownMenuItem(
|
||||
title = resourceReference(R.string.tangempay_card_details_pin_code),
|
||||
textColor = themedColor { TangemTheme.colors.text.primary1 },
|
||||
onClick = intents::onClickPinCode,
|
||||
),
|
||||
),
|
||||
TangemPayDetailsTopBarMenuItem(
|
||||
type = TangemPayDetailsTopBarMenuItemType.TermsAndLimits,
|
||||
dropdownItem = TangemDropdownMenuItem(
|
||||
title = resourceReference(R.string.tangem_pay_terms_limits),
|
||||
textColor = themedColor { TangemTheme.colors.text.primary1 },
|
||||
onClick = intents::onClickTermsAndLimits,
|
||||
),
|
||||
),
|
||||
cardFrozenStateItem,
|
||||
).toPersistentList()
|
||||
}
|
||||
}
|
||||
|
|
@ -15,8 +15,9 @@ internal data class TangemPayDetailsUM(
|
|||
val addToWalletBlockState: AddToWalletBlockState?,
|
||||
val isBalanceHidden: Boolean,
|
||||
val addFundsEnabled: Boolean,
|
||||
val cardFrozenState: CardFrozenState,
|
||||
val betaNotificationConfig: NotificationConfig,
|
||||
val cardFrozenState: CardFrozenState?,
|
||||
val betaNotificationConfig: NotificationConfig?,
|
||||
val accountDeactivatedNotificationConfig: NotificationConfig?,
|
||||
)
|
||||
|
||||
internal data class TangemPayCardDetailsUM(
|
||||
|
|
|
|||
|
|
@ -55,14 +55,11 @@ import com.tangem.features.tokendetails.ExpressTransactionsEventListener
|
|||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveIn
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import com.tangem.utils.transformer.update
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("LongParameterList", "LargeClass")
|
||||
|
|
@ -98,7 +95,7 @@ internal class TangemPayDetailsModel @Inject constructor(
|
|||
)
|
||||
|
||||
val uiState: StateFlow<TangemPayDetailsUM>
|
||||
field = MutableStateFlow(stateFactory.getInitialState())
|
||||
field = MutableStateFlow(stateFactory.getInitialState(params.config.isTangemPayDeactivated))
|
||||
|
||||
private val refreshStateJobHolder = JobHolder()
|
||||
private val fetchBalanceJobHolder = JobHolder()
|
||||
|
|
@ -116,9 +113,11 @@ internal class TangemPayDetailsModel @Inject constructor(
|
|||
init {
|
||||
analytics.send(TangemPayAnalyticsEvents.MainScreenOpened())
|
||||
handleBalanceHiding()
|
||||
fetchAddToWalletBanner()
|
||||
fetchBalance()
|
||||
subscribeToCardFrozenState()
|
||||
if (!params.config.isTangemPayDeactivated) {
|
||||
fetchAddToWalletBanner()
|
||||
subscribeToCardFrozenState()
|
||||
}
|
||||
}
|
||||
|
||||
fun onResume() {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import androidx.compose.ui.util.fastForEach
|
|||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.ui.components.PrimaryButton
|
||||
import com.tangem.core.ui.components.RectangleShimmer
|
||||
import com.tangem.core.ui.components.SpacerH12
|
||||
import com.tangem.core.ui.components.buttons.HorizontalActionChips
|
||||
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
|
|
@ -86,13 +87,16 @@ internal fun TangemPayDetailsScreen(
|
|||
bottom = TangemTheme.dimens.spacing16 + bottomBarHeight,
|
||||
),
|
||||
) {
|
||||
item(TangemPayCardDetailsUM::class.java) {
|
||||
cardDetailsBlockComponent.CardDetailsBlockContent(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.padding(top = 8.dp),
|
||||
state = cardDetailsState,
|
||||
)
|
||||
if (state.accountDeactivatedNotificationConfig == null) {
|
||||
item(TangemPayCardDetailsUM::class.java) {
|
||||
cardDetailsBlockComponent.CardDetailsBlockContent(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.padding(top = 8.dp),
|
||||
state = cardDetailsState,
|
||||
)
|
||||
SpacerH12()
|
||||
}
|
||||
}
|
||||
when (state.cardFrozenState) {
|
||||
is CardFrozenState.Frozen -> item(CardFrozenState.Frozen::class.java) {
|
||||
|
|
@ -100,11 +104,11 @@ internal fun TangemPayDetailsScreen(
|
|||
modifier = Modifier
|
||||
.animateItem()
|
||||
.padding(horizontal = 16.dp)
|
||||
.padding(top = 12.dp)
|
||||
.fillMaxWidth(),
|
||||
text = stringResourceSafe(R.string.tangempay_card_details_unfreeze_card),
|
||||
onClick = state.cardFrozenState.onUnfreeze,
|
||||
)
|
||||
SpacerH12()
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
|
|
@ -115,9 +119,9 @@ internal fun TangemPayDetailsScreen(
|
|||
TangemPayAddToWalletBlock(
|
||||
state = state.addToWalletBlockState,
|
||||
modifier = Modifier
|
||||
.padding(top = TangemTheme.dimens.spacing12)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
)
|
||||
SpacerH12()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -127,34 +131,52 @@ internal fun TangemPayDetailsScreen(
|
|||
TangemPayDetailsBalanceBlock(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.padding(top = 12.dp)
|
||||
.fillMaxWidth(),
|
||||
state = state.balanceBlockState,
|
||||
isBalanceHidden = state.isBalanceHidden,
|
||||
)
|
||||
SpacerH12()
|
||||
},
|
||||
)
|
||||
item(
|
||||
key = "TANGEM_PAY_IS_IN_BETA",
|
||||
content = {
|
||||
TangemPayBetaBlock(
|
||||
modifier = modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.padding(top = 12.dp)
|
||||
.fillMaxWidth(),
|
||||
config = state.betaNotificationConfig,
|
||||
)
|
||||
},
|
||||
)
|
||||
with(expressTransactionsComponent) {
|
||||
expressTransactionsContent(
|
||||
state = expressState.transactionsToDisplay,
|
||||
modifier = modifier
|
||||
.padding(start = 16.dp, end = 16.dp, top = 12.dp)
|
||||
.fillMaxWidth(),
|
||||
if (state.accountDeactivatedNotificationConfig != null) {
|
||||
item(
|
||||
key = "DEACTIVATION_MESSAGE",
|
||||
content = {
|
||||
Notification(
|
||||
modifier = modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.fillMaxWidth(),
|
||||
config = state.accountDeactivatedNotificationConfig,
|
||||
)
|
||||
SpacerH12()
|
||||
},
|
||||
)
|
||||
}
|
||||
with(txHistoryComponent) { txHistoryContent(listState = listState, state = txHistoryState) }
|
||||
if (state.betaNotificationConfig != null) {
|
||||
item(
|
||||
key = "TANGEM_PAY_IS_IN_BETA",
|
||||
content = {
|
||||
TangemPayBetaBlock(
|
||||
modifier = modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.fillMaxWidth(),
|
||||
config = state.betaNotificationConfig,
|
||||
)
|
||||
SpacerH12()
|
||||
},
|
||||
)
|
||||
}
|
||||
if (state.accountDeactivatedNotificationConfig == null) {
|
||||
with(expressTransactionsComponent) {
|
||||
expressTransactionsContent(
|
||||
state = expressState.transactionsToDisplay,
|
||||
modifier = modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
with(txHistoryComponent) { txHistoryContent(listState = listState, state = txHistoryState) }
|
||||
}
|
||||
}
|
||||
}
|
||||
expressTransactionsBottomSheetState?.content()
|
||||
|
|
@ -349,6 +371,7 @@ private class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider<Ta
|
|||
),
|
||||
iconSize = 36.dp,
|
||||
),
|
||||
accountDeactivatedNotificationConfig = null,
|
||||
),
|
||||
TangemPayDetailsUM(
|
||||
topBarConfig = TangemPayDetailsTopBarConfig(onBackClick = {}, onOpenMenu = {}, items = null),
|
||||
|
|
@ -368,6 +391,7 @@ private class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider<Ta
|
|||
),
|
||||
iconSize = 36.dp,
|
||||
),
|
||||
accountDeactivatedNotificationConfig = null,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -211,6 +211,7 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
|
|||
is PaymentAccountStatusValue.Locked,
|
||||
is PaymentAccountStatusValue.UnderReview,
|
||||
is PaymentAccountStatusValue.Empty,
|
||||
is PaymentAccountStatusValue.Deactivated,
|
||||
-> null
|
||||
}
|
||||
notification?.let(::add)
|
||||
|
|
|
|||
|
|
@ -240,6 +240,7 @@ internal class GetWalletNotificationsFactory @Inject constructor(
|
|||
is PaymentAccountStatusValue.Locked,
|
||||
is PaymentAccountStatusValue.UnderReview,
|
||||
is PaymentAccountStatusValue.Empty,
|
||||
is PaymentAccountStatusValue.Deactivated,
|
||||
-> null
|
||||
}
|
||||
notification?.let(::add)
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ internal class TangemPayUpdateInfoStateTransformer(
|
|||
cardFrozenState = cardFrozenState,
|
||||
cardNumberEnd = cardInfo.lastFourDigits,
|
||||
chainId = POLYGON_CHAIN_ID,
|
||||
isTangemPayDeactivated = false,
|
||||
),
|
||||
)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -56,6 +56,31 @@ internal class TangemPayMainBlockConverter(
|
|||
is PaymentAccountStatusValue.Empty -> TangemPayMainUM.Empty
|
||||
is PaymentAccountStatusValue.NotCreated -> TangemPayMainUM.Empty
|
||||
is PaymentAccountStatusValue.Loading -> TangemPayMainUM.Loading
|
||||
is PaymentAccountStatusValue.Deactivated -> TangemPayMainUM.Content(
|
||||
subtitle = TextReference.Res(R.string.tangempay_status_deactivated),
|
||||
isBalanceFlickering = statusValue.source == StatusSource.CACHE,
|
||||
balance = getBalanceText(
|
||||
currencyCode = statusValue.fiatBalance.currency,
|
||||
balance = statusValue.fiatBalance.availableBalance,
|
||||
),
|
||||
balanceSubtitle = stringReference("USDC"), // TODO hardcode for now
|
||||
shouldShowOnlyCacheWarning = statusValue.source == StatusSource.ONLY_CACHE,
|
||||
onClick = {
|
||||
// Dummy config for deactivated account just to open details screen
|
||||
tangemPayClickIntents.openDetails(
|
||||
userWalletId = value.account.userWalletId,
|
||||
config = TangemPayDetailsConfig(
|
||||
customerId = "",
|
||||
cardId = "",
|
||||
isPinSet = false,
|
||||
cardFrozenState = TangemPayCardFrozenState.Unfrozen,
|
||||
cardNumberEnd = "",
|
||||
chainId = POLYGON_CHAIN_ID,
|
||||
isTangemPayDeactivated = true,
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
is PaymentAccountStatusValue.Locked -> TangemPayMainUM.Content(
|
||||
subtitle = stringReference("*${statusValue.lastFourDigits}"),
|
||||
isBalanceFlickering = statusValue.source == StatusSource.CACHE,
|
||||
|
|
@ -75,6 +100,7 @@ internal class TangemPayMainBlockConverter(
|
|||
cardFrozenState = TangemPayCardFrozenState.Frozen,
|
||||
cardNumberEnd = statusValue.lastFourDigits,
|
||||
chainId = POLYGON_CHAIN_ID,
|
||||
isTangemPayDeactivated = false,
|
||||
),
|
||||
)
|
||||
},
|
||||
|
|
@ -98,6 +124,7 @@ internal class TangemPayMainBlockConverter(
|
|||
cardFrozenState = TangemPayCardFrozenState.Unfrozen,
|
||||
cardNumberEnd = statusValue.lastFourDigits,
|
||||
chainId = POLYGON_CHAIN_ID,
|
||||
isTangemPayDeactivated = false,
|
||||
),
|
||||
)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -65,11 +65,6 @@ internal class TangemPayMainSubscriber @AssistedInject constructor(
|
|||
TangemPayCustomerInfoError.ExposedDeviceError -> {
|
||||
stateController.update(TangemPayExposedDeviceTransformer(userWalletId))
|
||||
}
|
||||
TangemPayCustomerInfoError.DeactivatedError -> {
|
||||
stateController.update(
|
||||
transformer = TangemPayHiddenStateTransformer(userWalletId),
|
||||
)
|
||||
}
|
||||
TangemPayCustomerInfoError.UnknownError -> {
|
||||
// hide TangemPay block
|
||||
TangemLogger.e("Failed when loading main screen TangemPay info: $tangemPayError")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue