From 53b02cfb1014660ee78bbc7b1693e5006c3722fa Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 23 Apr 2026 03:02:00 -0700 Subject: [PATCH] Updated on 2026-08-14 --- .../com/tangem/datasource/di/MoshiModule.kt | 2 +- .../visa/DefaultTangemPayReissueCardStore.kt | 2 +- .../local/visa/TangemPayReissueCardStore.kt | 2 +- .../entity/PaymentAccountStatusValueDM.kt | 22 ++- .../utils/MoshiDataStoreSerializer.kt | 7 +- .../pay/DefaultTangemPayEligibilityManager.kt | 2 +- .../PaymentAccountStatusValueDMConverter.kt | 91 ++++++----- .../tangem/data/pay/di/TangemPayDataModule.kt | 2 + .../DefaultPaymentAccountStatusFetcher.kt | 52 +++---- .../repository/DefaultOnboardingRepository.kt | 6 +- .../DefaultReissueCardRepository.kt | 2 +- .../pay/store/PaymentAccountStatusesStore.kt | 2 + .../IsAccountsModeEnabledUseCaseTest.kt | 24 --- .../account/PaymentAccountStatusValue.kt | 61 +------- .../tangem/domain/models/pay/TangemPayCard.kt | 25 +++ .../domain/models/pay/TangemPayCardLimit.kt | 49 ++++++ .../models/pay/TangemPayCardLimitData.kt | 10 ++ .../{ => pay}/TangemPayEligibilityType.kt | 2 +- .../{ => pay}/TangemPayReissueCardFee.kt | 2 +- .../tangem/domain/pay/model/CustomerInfo.kt | 1 + .../domain/pay/model/TangemPayCardLimit.kt | 32 ---- .../pay/repository/OnboardingRepository.kt | 2 +- .../TangemPayReissueCardRepository.kt | 2 +- ...ymentAccountCryptoCurrencyStatusUseCase.kt | 1 - .../destination/model/SendDestinationModel.kt | 1 - .../feature/swap/domain/SwapInteractorImpl.kt | 1 - .../converter/ChooseTokenListItemConverter.kt | 1 - .../tangempay/model/TangemPayCardPageModel.kt | 145 ++++++++---------- .../domain/GetMultiWalletWarningsFactory.kt | 1 - .../domain/GetWalletNotificationsFactory.kt | 1 - .../converter/TangemPayMainBlockConverter.kt | 79 ++++------ 31 files changed, 286 insertions(+), 346 deletions(-) create mode 100644 domain/models/src/main/kotlin/com/tangem/domain/models/pay/TangemPayCard.kt create mode 100644 domain/models/src/main/kotlin/com/tangem/domain/models/pay/TangemPayCardLimit.kt create mode 100644 domain/models/src/main/kotlin/com/tangem/domain/models/pay/TangemPayCardLimitData.kt rename domain/models/src/main/kotlin/com/tangem/domain/models/{ => pay}/TangemPayEligibilityType.kt (89%) rename domain/models/src/main/kotlin/com/tangem/domain/models/{ => pay}/TangemPayReissueCardFee.kt (77%) delete mode 100644 domain/visa/src/main/kotlin/com/tangem/domain/pay/model/TangemPayCardLimit.kt diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/MoshiModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/MoshiModule.kt index effeecade9..d4a7ccf033 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/di/MoshiModule.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/di/MoshiModule.kt @@ -51,7 +51,7 @@ class MoshiModule { .withSubtype(PaymentAccountStatusValueDM.NotCreated::class.java, "not_created") .withSubtype(PaymentAccountStatusValueDM.UnderReview::class.java, "kyc_status") .withSubtype(PaymentAccountStatusValueDM.IssuingCard::class.java, "issuing_card") - .withSubtype(PaymentAccountStatusValueDM.ActiveCard::class.java, "active_card") + .withSubtype(PaymentAccountStatusValueDM.ActiveAccount::class.java, "active_account") .withSubtype(PaymentAccountStatusValueDM.CardIssueFailed::class.java, "card_issue_failed"), ) .add( diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/visa/DefaultTangemPayReissueCardStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/visa/DefaultTangemPayReissueCardStore.kt index d179f07eb3..666b4e790c 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/visa/DefaultTangemPayReissueCardStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/visa/DefaultTangemPayReissueCardStore.kt @@ -1,7 +1,7 @@ package com.tangem.datasource.local.visa import com.tangem.datasource.local.datastore.RuntimeDataStore -import com.tangem.domain.models.TangemPayReissueCardFee +import com.tangem.domain.models.pay.TangemPayReissueCardFee import com.tangem.domain.models.wallet.UserWalletId internal class DefaultTangemPayReissueCardStore( diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/visa/TangemPayReissueCardStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/visa/TangemPayReissueCardStore.kt index bc7825051f..0925c1ea31 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/visa/TangemPayReissueCardStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/visa/TangemPayReissueCardStore.kt @@ -1,6 +1,6 @@ package com.tangem.datasource.local.visa -import com.tangem.domain.models.TangemPayReissueCardFee +import com.tangem.domain.models.pay.TangemPayReissueCardFee import com.tangem.domain.models.wallet.UserWalletId interface TangemPayReissueCardStore { diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/visa/entity/PaymentAccountStatusValueDM.kt b/core/datasource/src/main/java/com/tangem/datasource/local/visa/entity/PaymentAccountStatusValueDM.kt index 98bfec8c62..31f6c44adf 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/visa/entity/PaymentAccountStatusValueDM.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/visa/entity/PaymentAccountStatusValueDM.kt @@ -4,6 +4,7 @@ package com.tangem.datasource.local.visa.entity import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import com.tangem.domain.models.kyc.KycStatus +import com.tangem.domain.models.serialization.SerializedBigDecimal import dev.onenowy.moshipolymorphicadapter.PolymorphicAdapterType import dev.onenowy.moshipolymorphicadapter.annotations.NameLabel import java.math.BigDecimal @@ -32,18 +33,14 @@ sealed interface PaymentAccountStatusValueDM { @Json(name = "issuing_card") val marker: Boolean = true, ) : PaymentAccountStatusValueDM - @NameLabel("active_card") - data class ActiveCard( - @Json(name = "active_card") val isLocked: Boolean, + @NameLabel("active_account") + data class ActiveAccount( @Json(name = "customer_id") val customerId: String, - @Json(name = "card_id") val cardId: String, - @Json(name = "last_four_digits") val lastFourDigits: String, @Json(name = "currency_code") val currencyCode: String, @Json(name = "deposit_address") val depositAddress: String?, - @Json(name = "is_pin_set") val isPinSet: Boolean, @Json(name = "fiat_balance") val fiatBalance: FiatBalanceDM, @Json(name = "crypto_balance") val cryptoBalance: CryptoBalanceDM, - @Json(name = "display_name") val displayName: String?, + @Json(name = "cards") val cards: List, ) : PaymentAccountStatusValueDM @NameLabel("card_issue_failed") @@ -66,4 +63,15 @@ sealed interface PaymentAccountStatusValueDM { @Json(name = "token_contract_address") val tokenContractAddress: String, @Json(name = "balance") val balance: BigDecimal, ) + + @JsonClass(generateAdapter = true) + data class TangemPayCard( + @Json(name = "id") val id: String, + @Json(name = "has_pin_code") val hasPinCode: Boolean, + @Json(name = "display_name") val displayName: String?, + @Json(name = "actual_daily_limit") val actualDailyLimit: SerializedBigDecimal?, + @Json(name = "admin_daily_limit") val adminDailyLimit: SerializedBigDecimal?, + @Json(name = "is_frozen") val isFrozen: Boolean, + @Json(name = "last_digits") val lastDigits: String, + ) } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/utils/MoshiDataStoreSerializer.kt b/core/datasource/src/main/java/com/tangem/datasource/utils/MoshiDataStoreSerializer.kt index c76773424f..7dae75ccfe 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/utils/MoshiDataStoreSerializer.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/utils/MoshiDataStoreSerializer.kt @@ -1,5 +1,6 @@ package com.tangem.datasource.utils +import androidx.datastore.core.CorruptionException import androidx.datastore.core.Serializer import com.squareup.moshi.JsonAdapter import com.squareup.moshi.Moshi @@ -34,7 +35,11 @@ class MoshiDataStoreSerializer( override suspend fun readFrom(input: InputStream): T { return input.bufferedReader().use { reader -> - adapter.fromJson(reader.readText()) ?: defaultValue + try { + adapter.fromJson(reader.readText()) ?: defaultValue + } catch (e: Exception) { + throw CorruptionException("Failed to deserialize data", e) + } } } diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/DefaultTangemPayEligibilityManager.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/DefaultTangemPayEligibilityManager.kt index fb9bd81fda..029791dec1 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/DefaultTangemPayEligibilityManager.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/DefaultTangemPayEligibilityManager.kt @@ -2,7 +2,7 @@ package com.tangem.data.pay import com.tangem.common.card.FirmwareVersion import com.tangem.domain.common.wallets.UserWalletsListRepository -import com.tangem.domain.models.TangemPayEligibilityType +import com.tangem.domain.models.pay.TangemPayEligibilityType import com.tangem.utils.coroutines.AppCoroutineScope import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWalletId diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/converter/PaymentAccountStatusValueDMConverter.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/converter/PaymentAccountStatusValueDMConverter.kt index cfa7822955..8fbc87cb6f 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/converter/PaymentAccountStatusValueDMConverter.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/converter/PaymentAccountStatusValueDMConverter.kt @@ -1,11 +1,15 @@ package com.tangem.data.pay.converter -import com.tangem.data.pay.entity.TangemPayCurrencyFactory import arrow.core.getOrElse +import com.tangem.data.pay.entity.TangemPayCurrencyFactory import com.tangem.datasource.local.visa.entity.PaymentAccountStatusValueDM import com.tangem.domain.models.StatusSource import com.tangem.domain.models.account.CardDisplayName import com.tangem.domain.models.account.PaymentAccountStatusValue +import com.tangem.domain.models.pay.TangemPayCard +import com.tangem.domain.models.pay.TangemPayCardLimit +import com.tangem.domain.models.pay.TangemPayCardLimitData +import com.tangem.domain.models.pay.TangemPayCardLimitPeriod import com.tangem.domain.models.wallet.UserWalletId import javax.inject.Inject import javax.inject.Singleton @@ -31,29 +35,23 @@ internal class PaymentAccountStatusValueDMConverter @Inject constructor( customerId = value.customerId, ) is PaymentAccountStatusValue.IssuingCard -> PaymentAccountStatusValueDM.IssuingCard() - is PaymentAccountStatusValue.Locked -> PaymentAccountStatusValueDM.ActiveCard( - isLocked = true, + is PaymentAccountStatusValue.Loaded -> PaymentAccountStatusValueDM.ActiveAccount( customerId = value.customerId, - cardId = value.cardId, - lastFourDigits = value.lastFourDigits, currencyCode = value.currencyCode, depositAddress = value.depositAddress, - isPinSet = value.isPinSet, fiatBalance = value.fiatBalance.toDM(), cryptoBalance = value.cryptoBalance.toDM(), - displayName = value.displayName?.value, - ) - is PaymentAccountStatusValue.Loaded -> PaymentAccountStatusValueDM.ActiveCard( - isLocked = false, - customerId = value.customerId, - cardId = value.cardId, - lastFourDigits = value.lastFourDigits, - currencyCode = value.currencyCode, - depositAddress = value.depositAddress, - isPinSet = value.isPinSet, - fiatBalance = value.fiatBalance.toDM(), - cryptoBalance = value.cryptoBalance.toDM(), - displayName = value.displayName?.value, + cards = value.cards.map { card -> + PaymentAccountStatusValueDM.TangemPayCard( + id = card.id, + hasPinCode = card.hasPinCode, + displayName = card.displayName?.value, + actualDailyLimit = card.limit?.actualCardLimit?.amount, + adminDailyLimit = card.limit?.adminCardLimit?.amount, + isFrozen = card.isFrozen, + lastDigits = card.lastDigits, + ) + }, ) is PaymentAccountStatusValue.Error.CardIssueFailed -> PaymentAccountStatusValueDM.CardIssueFailed( customerId = value.customerId, @@ -76,35 +74,32 @@ internal class PaymentAccountStatusValueDMConverter @Inject constructor( is PaymentAccountStatusValueDM.IssuingCard -> PaymentAccountStatusValue.IssuingCard( source = StatusSource.CACHE, ) - is PaymentAccountStatusValueDM.ActiveCard -> if (value.isLocked) { - PaymentAccountStatusValue.Locked( - source = StatusSource.CACHE, - customerId = value.customerId, - cardId = value.cardId, - lastFourDigits = value.lastFourDigits, - currencyCode = value.currencyCode, - depositAddress = value.depositAddress, - isPinSet = value.isPinSet, - fiatBalance = value.fiatBalance.toDomain(), - cryptoBalance = value.cryptoBalance.toDomain(), - cryptoCurrency = tangemPayCurrencyFactory.create(userWalletId), - displayName = value.displayName?.let { CardDisplayName(it).getOrElse { null } }, - ) - } else { - PaymentAccountStatusValue.Loaded( - source = StatusSource.CACHE, - customerId = value.customerId, - cardId = value.cardId, - lastFourDigits = value.lastFourDigits, - currencyCode = value.currencyCode, - depositAddress = value.depositAddress, - isPinSet = value.isPinSet, - fiatBalance = value.fiatBalance.toDomain(), - cryptoBalance = value.cryptoBalance.toDomain(), - cryptoCurrency = tangemPayCurrencyFactory.create(userWalletId), - displayName = value.displayName?.let { CardDisplayName(it).getOrElse { null } }, - ) - } + is PaymentAccountStatusValueDM.ActiveAccount -> PaymentAccountStatusValue.Loaded( + source = StatusSource.CACHE, + customerId = value.customerId, + currencyCode = value.currencyCode, + depositAddress = value.depositAddress, + fiatBalance = value.fiatBalance.toDomain(), + cryptoBalance = value.cryptoBalance.toDomain(), + cryptoCurrency = tangemPayCurrencyFactory.create(userWalletId), + cards = value.cards.map { card -> + TangemPayCard( + id = card.id, + hasPinCode = card.hasPinCode, + displayName = card.displayName?.let { CardDisplayName(it).getOrElse { null } }, + limit = TangemPayCardLimitData( + actualCardLimit = card.actualDailyLimit?.let { limit -> + TangemPayCardLimit(limit, TangemPayCardLimitPeriod.DAY) + }, + adminCardLimit = card.adminDailyLimit?.let { limit -> + TangemPayCardLimit(limit, TangemPayCardLimitPeriod.DAY) + }, + ), + isFrozen = card.isFrozen, + lastDigits = card.lastDigits, + ) + }, + ) is PaymentAccountStatusValueDM.UnderReview -> PaymentAccountStatusValue.UnderReview( source = StatusSource.CACHE, kycStatus = value.kycStatus, diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/di/TangemPayDataModule.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/di/TangemPayDataModule.kt index 7d55c0625d..2c3e46bd19 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/di/TangemPayDataModule.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/di/TangemPayDataModule.kt @@ -2,6 +2,7 @@ package com.tangem.data.pay.di import android.content.Context import androidx.datastore.core.DataStoreFactory +import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler import androidx.datastore.dataStoreFile import com.squareup.moshi.Moshi import com.tangem.data.pay.DefaultTangemPayCryptoCurrencyFactory @@ -129,6 +130,7 @@ internal interface TangemPayDataModule { types = mapWithStringKeyTypes(), defaultValue = emptyMap(), ), + corruptionHandler = ReplaceFileCorruptionHandler { emptyMap() }, produceFile = { context.dataStoreFile(fileName = "payment_account_statuses") }, scope = scope, ), diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/flow/DefaultPaymentAccountStatusFetcher.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/flow/DefaultPaymentAccountStatusFetcher.kt index 1cb938336b..220bdc93a1 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/flow/DefaultPaymentAccountStatusFetcher.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/flow/DefaultPaymentAccountStatusFetcher.kt @@ -9,6 +9,8 @@ import com.tangem.domain.models.account.Account import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.PaymentAccountStatusValue import com.tangem.domain.models.kyc.KycStatus +import com.tangem.domain.models.pay.TangemPayCard +import com.tangem.domain.models.pay.TangemPayCardLimitData import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.pay.flow.PaymentAccountStatusFetcher import com.tangem.domain.pay.model.CustomerInfo @@ -277,34 +279,28 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor( customerId: String, ): PaymentAccountStatusValue { val cryptoCurrency = tangemPayCurrencyFactory.create(userWalletId) - return when (productInstance.frozenState) { - TangemPayCardFrozenState.Frozen -> PaymentAccountStatusValue.Locked( - source = StatusSource.ACTUAL, - customerId = customerId, - cardId = productInstance.cardId, - lastFourDigits = cardInfo.lastFourDigits, - currencyCode = cardInfo.currencyCode, - depositAddress = cardInfo.depositAddress, - isPinSet = cardInfo.isPinSet, - fiatBalance = cardInfo.fiatBalance, - cryptoBalance = cardInfo.cryptoBalance, - cryptoCurrency = cryptoCurrency, - displayName = productInstance.displayName, - ) - else -> PaymentAccountStatusValue.Loaded( - source = StatusSource.ACTUAL, - customerId = customerId, - cardId = productInstance.cardId, - lastFourDigits = cardInfo.lastFourDigits, - currencyCode = cardInfo.currencyCode, - depositAddress = cardInfo.depositAddress, - isPinSet = cardInfo.isPinSet, - fiatBalance = cardInfo.fiatBalance, - cryptoBalance = cardInfo.cryptoBalance, - cryptoCurrency = cryptoCurrency, - displayName = productInstance.displayName, - ) - } + return PaymentAccountStatusValue.Loaded( + source = StatusSource.ACTUAL, + customerId = customerId, + currencyCode = cardInfo.currencyCode, + depositAddress = cardInfo.depositAddress, + fiatBalance = cardInfo.fiatBalance, + cryptoBalance = cardInfo.cryptoBalance, + cryptoCurrency = cryptoCurrency, + cards = listOf( + TangemPayCard( + id = productInstance.cardId, + hasPinCode = cardInfo.isPinSet, + displayName = productInstance.displayName, + limit = TangemPayCardLimitData( + actualCardLimit = productInstance.actualCardLimit, + adminCardLimit = productInstance.adminCardLimit, + ), + isFrozen = productInstance.frozenState is TangemPayCardFrozenState.Frozen, + lastDigits = cardInfo.lastFourDigits, + ), + ), + ) } private fun VisaApiError.mapToPaymentAccountStatus(): PaymentAccountStatusValue { diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt index aa7f791149..9b3188f36b 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt @@ -15,7 +15,7 @@ import com.tangem.datasource.api.pay.models.response.OrderResponse import com.tangem.datasource.local.visa.TangemPayCardFrozenStateStore import com.tangem.datasource.local.visa.TangemPayStorage import com.tangem.domain.common.wallets.UserWalletsListRepository -import com.tangem.domain.models.TangemPayEligibilityType +import com.tangem.domain.models.pay.TangemPayEligibilityType import com.tangem.domain.models.account.CardDisplayName import com.tangem.domain.models.account.PaymentAccountStatusValue import com.tangem.domain.models.kyc.KycStatus @@ -25,8 +25,8 @@ import com.tangem.domain.pay.datasource.TangemPayAuthDataSource import com.tangem.domain.pay.model.CustomerInfo import com.tangem.domain.pay.model.CustomerInfo.CardInfo import com.tangem.domain.pay.model.CustomerInfo.ProductInstance -import com.tangem.domain.pay.model.TangemPayCardLimit -import com.tangem.domain.pay.model.TangemPayCardLimitPeriod +import com.tangem.domain.models.pay.TangemPayCardLimit +import com.tangem.domain.models.pay.TangemPayCardLimitPeriod import com.tangem.domain.pay.repository.OnboardingRepository import com.tangem.domain.tangempay.TangemPayAnalyticsEvents import com.tangem.domain.visa.error.VisaApiError diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultReissueCardRepository.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultReissueCardRepository.kt index abffaa87fc..b6ee3b4b76 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultReissueCardRepository.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultReissueCardRepository.kt @@ -8,7 +8,7 @@ import com.tangem.datasource.api.pay.TangemPayApi import com.tangem.datasource.api.pay.models.request.ReissueCardRequest import com.tangem.datasource.api.pay.models.response.OrderResponse import com.tangem.datasource.local.visa.TangemPayReissueCardStore -import com.tangem.domain.models.TangemPayReissueCardFee +import com.tangem.domain.models.pay.TangemPayReissueCardFee import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.pay.model.OrderStatus import com.tangem.domain.pay.model.TangemPayReissueOrderInfo diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/store/PaymentAccountStatusesStore.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/store/PaymentAccountStatusesStore.kt index 62accbccf7..c39190f6d8 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/store/PaymentAccountStatusesStore.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/store/PaymentAccountStatusesStore.kt @@ -10,6 +10,7 @@ import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.PaymentAccountStatusValue import com.tangem.domain.models.wallet.UserWalletId import com.tangem.utils.coroutines.AppCoroutineScope +import com.tangem.utils.coroutines.runSuspendCatching import com.tangem.utils.logging.TangemLogger import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.Flow @@ -45,6 +46,7 @@ internal class PaymentAccountStatusesStore( }, ) } catch (e: Exception) { + runSuspendCatching { persistenceDataStore.updateData { emptyMap() } } TangemLogger.e("Error while loading cached payment account statuses", e) } } diff --git a/domain/account/status/src/test/kotlin/com/tangem/domain/account/status/usecase/IsAccountsModeEnabledUseCaseTest.kt b/domain/account/status/src/test/kotlin/com/tangem/domain/account/status/usecase/IsAccountsModeEnabledUseCaseTest.kt index 49a4a0bd50..df60423785 100644 --- a/domain/account/status/src/test/kotlin/com/tangem/domain/account/status/usecase/IsAccountsModeEnabledUseCaseTest.kt +++ b/domain/account/status/src/test/kotlin/com/tangem/domain/account/status/usecase/IsAccountsModeEnabledUseCaseTest.kt @@ -78,18 +78,6 @@ class IsAccountsModeEnabledUseCaseTest { Truth.assertThat(actual).isTrue() } - @Test - fun `returns true when payment account is Locked`() = runTest { - val statusList = createAccountStatusList( - statuses = listOf(mockCryptoPortfolio(), mockPayment(mockk())), - ) - every { multiAccountStatusListSupplier.invoke() } returns flowOf(listOf(statusList)) - - val actual = useCase.invoke().first() - - Truth.assertThat(actual).isTrue() - } - @Test fun `returns false when payment account is NotCreated`() = runTest { val statusList = createAccountStatusList( @@ -210,18 +198,6 @@ class IsAccountsModeEnabledUseCaseTest { Truth.assertThat(actual).isTrue() } - @Test - fun `returns true when payment account is Locked`() = runTest { - val statusList = createAccountStatusList( - statuses = listOf(mockCryptoPortfolio(), mockPayment(mockk())), - ) - coEvery { multiAccountStatusListSupplier.getSyncOrNull(Unit, any()) } returns listOf(statusList) - - val actual = useCase.invokeSync() - - Truth.assertThat(actual).isTrue() - } - @Test fun `returns false when payment account is NotCreated`() = runTest { val statusList = createAccountStatusList( diff --git a/domain/models/src/main/kotlin/com/tangem/domain/models/account/PaymentAccountStatusValue.kt b/domain/models/src/main/kotlin/com/tangem/domain/models/account/PaymentAccountStatusValue.kt index 8e74069ff6..6187861ae1 100644 --- a/domain/models/src/main/kotlin/com/tangem/domain/models/account/PaymentAccountStatusValue.kt +++ b/domain/models/src/main/kotlin/com/tangem/domain/models/account/PaymentAccountStatusValue.kt @@ -6,6 +6,7 @@ import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.kyc.KycStatus import com.tangem.domain.models.network.NetworkAddress +import com.tangem.domain.models.pay.TangemPayCard import com.tangem.domain.models.serialization.SerializedBigDecimal import kotlinx.serialization.Serializable import java.math.BigDecimal @@ -28,7 +29,6 @@ sealed class PaymentAccountStatusValue { is UnderReview, -> TotalFiatBalance.Loaded(amount = SerializedBigDecimal.ZERO, source = source) is Loading -> TotalFiatBalance.Loading - is Locked -> TotalFiatBalance.Loaded(amount = fiatBalance.availableBalance, source = source) is Loaded -> TotalFiatBalance.Loaded(amount = fiatBalance.availableBalance, source = source) } @@ -41,7 +41,6 @@ sealed class PaymentAccountStatusValue { return when (this) { is IssuingCard -> copy(source = source) is Loaded -> copy(source = source) - is Locked -> copy(source = source) is UnderReview -> copy(source = source) is Loading, is NotCreated, @@ -84,81 +83,27 @@ sealed class PaymentAccountStatusValue { @Serializable data class IssuingCard(override val source: StatusSource) : PaymentAccountStatusValue() - /** - * Represents a state where the payment account is locked. - * - * @property source The source of the status information. - * @property customerId The unique identifier of the customer. - * @property cardId The unique identifier of the card. - * @property lastFourDigits The last four digits of the card number. - * @property currencyCode The code of the currency. - * @property depositAddress The address for deposits, if available. - * @property isPinSet Indicates if the PIN is set for the card. - * @property fiatBalance The fiat balance details. - * @property cryptoBalance The crypto balance details. - */ - @Serializable - data class Locked( - override val source: StatusSource, - val customerId: String, - val cardId: String, - val lastFourDigits: String, - val currencyCode: String, - val depositAddress: String?, - val isPinSet: Boolean, - val fiatBalance: FiatBalance, - val cryptoBalance: CryptoBalance, - val cryptoCurrency: CryptoCurrency.Token, - val displayName: CardDisplayName?, - ) : PaymentAccountStatusValue() { - val cryptoCurrencyStatus: CryptoCurrencyStatus = CryptoCurrencyStatus( - currency = cryptoCurrency, - value = CryptoCurrencyStatus.Loaded( - amount = cryptoBalance.balance, - fiatAmount = fiatBalance.availableBalance, - fiatRate = BigDecimal.ONE, - priceChange = BigDecimal.ZERO, - networkAddress = NetworkAddress.Single( - defaultAddress = NetworkAddress.Address( - type = NetworkAddress.Address.Type.Primary, - value = cryptoBalance.depositAddress, - ), - ), - sources = CryptoCurrencyStatus.Sources(), - pendingTransactions = emptySet(), - stakingBalance = null, - yieldSupplyStatus = null, - hasCurrentNetworkTransactions = false, - ), - ) - } - /** * Represents a state where the payment account is successfully loaded with complete information. * * @property source The source of the status information. * @property customerId The unique identifier of the customer. - * @property cardId The unique identifier of the card. - * @property lastFourDigits The last four digits of the card number. * @property currencyCode The code of the currency. * @property depositAddress The address for deposits, if available. - * @property isPinSet Indicates if the PIN is set for the card. * @property fiatBalance The fiat balance details. * @property cryptoBalance The crypto balance details. + * @property cards The list of user's cards. */ @Serializable data class Loaded( override val source: StatusSource, val customerId: String, - val cardId: String, - val lastFourDigits: String, val currencyCode: String, val depositAddress: String?, - val isPinSet: Boolean, val fiatBalance: FiatBalance, val cryptoBalance: CryptoBalance, val cryptoCurrency: CryptoCurrency.Token, - val displayName: CardDisplayName?, + val cards: List, ) : PaymentAccountStatusValue() { val cryptoCurrencyStatus: CryptoCurrencyStatus = CryptoCurrencyStatus( currency = cryptoCurrency, diff --git a/domain/models/src/main/kotlin/com/tangem/domain/models/pay/TangemPayCard.kt b/domain/models/src/main/kotlin/com/tangem/domain/models/pay/TangemPayCard.kt new file mode 100644 index 0000000000..115e387985 --- /dev/null +++ b/domain/models/src/main/kotlin/com/tangem/domain/models/pay/TangemPayCard.kt @@ -0,0 +1,25 @@ +package com.tangem.domain.models.pay + +import com.tangem.domain.models.account.CardDisplayName +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +/** + * Represents a Tangem Pay card linked to a payment account. + * + * @property id unique card identifier assigned by the backend. + * @property hasPinCode whether the card has a PIN code set. + * @property displayName optional human-readable name assigned to the card; `null` if not set. + * @property limit spending limit configuration for the card; `null` if not configured or not yet loaded. + * @property isFrozen whether the card is currently frozen (blocked for payments). + * @property lastDigits The last four digits of the card number. + */ +@Serializable +data class TangemPayCard( + @SerialName("id") val id: String, + @SerialName("has_pin_code") val hasPinCode: Boolean, + @SerialName("display_name") val displayName: CardDisplayName?, + @SerialName("limit") val limit: TangemPayCardLimitData?, + @SerialName("is_frozen") val isFrozen: Boolean, + @SerialName("last_digits") val lastDigits: String, +) \ No newline at end of file diff --git a/domain/models/src/main/kotlin/com/tangem/domain/models/pay/TangemPayCardLimit.kt b/domain/models/src/main/kotlin/com/tangem/domain/models/pay/TangemPayCardLimit.kt new file mode 100644 index 0000000000..01df4b7f89 --- /dev/null +++ b/domain/models/src/main/kotlin/com/tangem/domain/models/pay/TangemPayCardLimit.kt @@ -0,0 +1,49 @@ +package com.tangem.domain.models.pay + +import com.tangem.domain.models.serialization.SerializedBigDecimal +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import java.util.Locale + +@Serializable +data class TangemPayCardLimit( + @SerialName("amount") val amount: SerializedBigDecimal, + @SerialName("period") val period: TangemPayCardLimitPeriod, +) + +@Serializable +enum class TangemPayCardLimitPeriod { + @SerialName("DAY") + DAY, + + @SerialName("WEEK") + WEEK, + + @SerialName("MONTH") + MONTH, + + @SerialName("YEAR") + YEAR, + + @SerialName("ALL_TIME") + ALL_TIME, + + @SerialName("AUTHORIZATION") + AUTHORIZATION, + + @SerialName("UNKNOWN") + UNKNOWN, + ; + + companion object { + fun fromString(value: String) = when (value.uppercase(Locale.US)) { + "DAY" -> DAY + "WEEK" -> WEEK + "MONTH" -> MONTH + "YEAR" -> YEAR + "ALL_TIME" -> ALL_TIME + "AUTHORIZATION" -> AUTHORIZATION + else -> UNKNOWN + } + } +} \ No newline at end of file diff --git a/domain/models/src/main/kotlin/com/tangem/domain/models/pay/TangemPayCardLimitData.kt b/domain/models/src/main/kotlin/com/tangem/domain/models/pay/TangemPayCardLimitData.kt new file mode 100644 index 0000000000..bffc3a671a --- /dev/null +++ b/domain/models/src/main/kotlin/com/tangem/domain/models/pay/TangemPayCardLimitData.kt @@ -0,0 +1,10 @@ +package com.tangem.domain.models.pay + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class TangemPayCardLimitData( + @SerialName("actual_card_limit") val actualCardLimit: TangemPayCardLimit?, + @SerialName("admin_card_limit") val adminCardLimit: TangemPayCardLimit?, +) \ No newline at end of file diff --git a/domain/models/src/main/kotlin/com/tangem/domain/models/TangemPayEligibilityType.kt b/domain/models/src/main/kotlin/com/tangem/domain/models/pay/TangemPayEligibilityType.kt similarity index 89% rename from domain/models/src/main/kotlin/com/tangem/domain/models/TangemPayEligibilityType.kt rename to domain/models/src/main/kotlin/com/tangem/domain/models/pay/TangemPayEligibilityType.kt index 7f449b1bcd..2431867555 100644 --- a/domain/models/src/main/kotlin/com/tangem/domain/models/TangemPayEligibilityType.kt +++ b/domain/models/src/main/kotlin/com/tangem/domain/models/pay/TangemPayEligibilityType.kt @@ -1,4 +1,4 @@ -package com.tangem.domain.models +package com.tangem.domain.models.pay enum class TangemPayEligibilityType { diff --git a/domain/models/src/main/kotlin/com/tangem/domain/models/TangemPayReissueCardFee.kt b/domain/models/src/main/kotlin/com/tangem/domain/models/pay/TangemPayReissueCardFee.kt similarity index 77% rename from domain/models/src/main/kotlin/com/tangem/domain/models/TangemPayReissueCardFee.kt rename to domain/models/src/main/kotlin/com/tangem/domain/models/pay/TangemPayReissueCardFee.kt index 515857f8a7..26cde00590 100644 --- a/domain/models/src/main/kotlin/com/tangem/domain/models/TangemPayReissueCardFee.kt +++ b/domain/models/src/main/kotlin/com/tangem/domain/models/pay/TangemPayReissueCardFee.kt @@ -1,4 +1,4 @@ -package com.tangem.domain.models +package com.tangem.domain.models.pay import java.math.BigDecimal diff --git a/domain/visa/src/main/kotlin/com/tangem/domain/pay/model/CustomerInfo.kt b/domain/visa/src/main/kotlin/com/tangem/domain/pay/model/CustomerInfo.kt index 4f04e19fa0..c0bc32185f 100644 --- a/domain/visa/src/main/kotlin/com/tangem/domain/pay/model/CustomerInfo.kt +++ b/domain/visa/src/main/kotlin/com/tangem/domain/pay/model/CustomerInfo.kt @@ -1,5 +1,6 @@ package com.tangem.domain.pay.model +import com.tangem.domain.models.pay.TangemPayCardLimit import com.tangem.domain.models.account.CardDisplayName import com.tangem.domain.models.account.PaymentAccountStatusValue import com.tangem.domain.models.kyc.KycStatus diff --git a/domain/visa/src/main/kotlin/com/tangem/domain/pay/model/TangemPayCardLimit.kt b/domain/visa/src/main/kotlin/com/tangem/domain/pay/model/TangemPayCardLimit.kt deleted file mode 100644 index 63ba23859b..0000000000 --- a/domain/visa/src/main/kotlin/com/tangem/domain/pay/model/TangemPayCardLimit.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.tangem.domain.pay.model - -import java.math.BigDecimal -import java.util.Locale - -data class TangemPayCardLimit( - val amount: BigDecimal, - val period: TangemPayCardLimitPeriod, -) - -enum class TangemPayCardLimitPeriod { - DAY, - WEEK, - MONTH, - YEAR, - ALL_TIME, - AUTHORIZATION, - UNKNOWN, - ; - - companion object { - fun fromString(value: String) = when (value.uppercase(Locale.US)) { - "DAY" -> DAY - "WEEK" -> WEEK - "MONTH" -> MONTH - "YEAR" -> YEAR - "ALL_TIME" -> ALL_TIME - "AUTHORIZATION" -> AUTHORIZATION - else -> UNKNOWN - } - } -} \ No newline at end of file diff --git a/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/OnboardingRepository.kt b/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/OnboardingRepository.kt index 8fcab526ee..bce59b45c7 100644 --- a/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/OnboardingRepository.kt +++ b/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/OnboardingRepository.kt @@ -2,7 +2,7 @@ package com.tangem.domain.pay.repository import arrow.core.Either import com.tangem.core.error.UniversalError -import com.tangem.domain.models.TangemPayEligibilityType +import com.tangem.domain.models.pay.TangemPayEligibilityType import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.pay.model.CustomerInfo import com.tangem.domain.visa.error.VisaApiError diff --git a/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/TangemPayReissueCardRepository.kt b/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/TangemPayReissueCardRepository.kt index 2342faff2c..3f756df4ee 100644 --- a/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/TangemPayReissueCardRepository.kt +++ b/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/TangemPayReissueCardRepository.kt @@ -3,7 +3,7 @@ package com.tangem.domain.pay.repository import arrow.core.Either import com.tangem.core.error.UniversalError import com.tangem.domain.models.wallet.UserWalletId -import com.tangem.domain.models.TangemPayReissueCardFee +import com.tangem.domain.models.pay.TangemPayReissueCardFee import com.tangem.domain.pay.model.TangemPayReissueOrderInfo import com.tangem.domain.visa.error.VisaApiError diff --git a/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/GetPaymentAccountCryptoCurrencyStatusUseCase.kt b/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/GetPaymentAccountCryptoCurrencyStatusUseCase.kt index fe66dc36f7..4200d87d77 100644 --- a/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/GetPaymentAccountCryptoCurrencyStatusUseCase.kt +++ b/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/GetPaymentAccountCryptoCurrencyStatusUseCase.kt @@ -22,7 +22,6 @@ class GetPaymentAccountCryptoCurrencyStatusUseCase( val accountStatus = paymentAccountStatusSupplier.invoke(userWalletId).firstOrNull() ?: return none() val cryptoCurrencyStatus = when (val statusValue = accountStatus.value) { is PaymentAccountStatusValue.Loaded -> statusValue.cryptoCurrencyStatus - is PaymentAccountStatusValue.Locked -> statusValue.cryptoCurrencyStatus else -> return none() } return if (cryptoCurrencyStatus.currency == cryptoCurrency) { diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/model/SendDestinationModel.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/model/SendDestinationModel.kt index 2daa88480b..e2cc71268c 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/model/SendDestinationModel.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/model/SendDestinationModel.kt @@ -262,7 +262,6 @@ internal class SendDestinationModel @Inject constructor( val contractAddress = (cryptoCurrency as? CryptoCurrency.Token)?.contractAddress ?: return null val (paymentAccountAddress, currency) = when (val status = this.value) { is PaymentAccountStatusValue.Loaded -> status.cryptoBalance.depositAddress to status.cryptoCurrency - is PaymentAccountStatusValue.Locked -> status.cryptoBalance.depositAddress to status.cryptoCurrency else -> return null } diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt index 5b2b9b002e..2a5a8f55ea 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt @@ -187,7 +187,6 @@ internal class SwapInteractorImpl @AssistedInject constructor( private fun getPaymentAccountCurrencies(accountStatus: AccountStatus.Payment): List { val currencyStatus = when (val statusValue = accountStatus.value) { is PaymentAccountStatusValue.Loaded -> statusValue.cryptoCurrencyStatus - is PaymentAccountStatusValue.Locked -> statusValue.cryptoCurrencyStatus else -> return emptyList() } diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/choosetoken/impl/converter/ChooseTokenListItemConverter.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/choosetoken/impl/converter/ChooseTokenListItemConverter.kt index 296375932e..3ad65aa9dd 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/choosetoken/impl/converter/ChooseTokenListItemConverter.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/choosetoken/impl/converter/ChooseTokenListItemConverter.kt @@ -188,7 +188,6 @@ internal class ChooseTokenListItemConverter( PaymentAccountStatusValue.Loading, -> return null is PaymentAccountStatusValue.Loaded -> status.cryptoCurrencyStatus - is PaymentAccountStatusValue.Locked -> status.cryptoCurrencyStatus } val account = this.account val tokensCount = 1 diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardPageModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardPageModel.kt index 4371b252e4..dd917953d6 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardPageModel.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardPageModel.kt @@ -18,12 +18,15 @@ import com.tangem.core.ui.format.bigdecimal.fiat import com.tangem.core.ui.format.bigdecimal.format import com.tangem.core.ui.format.bigdecimal.getJavaCurrencyByCode import com.tangem.core.ui.message.SnackbarMessage +import com.tangem.domain.models.StatusSource import com.tangem.domain.models.TokenReceiveConfig +import com.tangem.domain.models.account.PaymentAccountStatusValue +import com.tangem.domain.models.pay.TangemPayCard +import com.tangem.domain.models.pay.TangemPayCardLimitPeriod +import com.tangem.domain.pay.flow.PaymentAccountStatusSupplier import com.tangem.domain.pay.model.OrderStatus -import com.tangem.domain.pay.model.TangemPayCardLimitPeriod import com.tangem.domain.pay.model.TangemPayReissueOrderInfo 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.TangemPayReissueCardRepository import com.tangem.domain.tangempay.TangemPayAnalyticsEvents @@ -33,22 +36,15 @@ import com.tangem.features.tangempay.components.ReissueCardListener import com.tangem.features.tangempay.components.TangemPayCardPageComponent import com.tangem.features.tangempay.components.ViewPinListener import com.tangem.features.tangempay.details.impl.R -import com.tangem.features.tangempay.entity.AddToWalletBlockState -import com.tangem.features.tangempay.entity.TangemPayCardPageSetting -import com.tangem.features.tangempay.entity.TangemPayCardPageUM -import com.tangem.features.tangempay.entity.TangemPayDetailsNavigation +import com.tangem.features.tangempay.entity.* import com.tangem.features.tangempay.navigation.TangemPayDetailsInnerRoute -import com.tangem.features.tangempay.entity.TangemPayDailyLimitBlockState import com.tangem.features.tangempay.utils.TangemPayMessagesFactory import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.JobHolder import com.tangem.utils.coroutines.saveIn +import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.flow.update +import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import javax.inject.Inject @@ -57,19 +53,17 @@ import javax.inject.Inject @ModelScoped internal class TangemPayCardPageModel @Inject constructor( paramsContainer: ParamsContainer, + paymentAccountStatusSupplier: PaymentAccountStatusSupplier, override val dispatchers: CoroutineDispatcherProvider, private val router: Router, private val analytics: AnalyticsEventHandler, private val cardDetailsRepository: TangemPayCardDetailsRepository, - private val onboardingRepository: OnboardingRepository, private val uiMessageSender: UiMessageSender, private val reissueCardRepository: TangemPayReissueCardRepository, ) : Model(), ViewPinListener, ReissueCardListener, AddFundsListener { private val params: TangemPayCardPageComponent.Params = paramsContainer.require() - private var currentFrozenState: TangemPayCardFrozenState = params.config.cardFrozenState - private val addToWalletBannerJobHolder = JobHolder() private val addFundsJobHolder = JobHolder() @@ -78,34 +72,63 @@ internal class TangemPayCardPageModel @Inject constructor( TangemPayCardPageUM( onBackClick = router::pop, dailyLimitState = TangemPayDailyLimitBlockState.Loading, - settings = persistentListOf( - TangemPayCardPageSetting( - title = TextReference.Res(R.string.tangempay_card_details_change_pin), - onSettingClick = ::onClickChangePIN, - ), - TangemPayCardPageSetting( - title = TextReference.Res(R.string.tangempay_card_details_freeze_card), - onSettingClick = ::onClickFreezeOrUnfreezeCard, - ), - TangemPayCardPageSetting( - title = TextReference.Res(R.string.tangempay_card_details_reissue_card), - onSettingClick = ::onClickReissueCard, - ), - ), + settings = persistentListOf(), ), ) val bottomSheetNavigation: SlotNavigation = SlotNavigation() + // TODO v_rodionov: #[REDACTED_TASK_KEY] check reissue order state before card details are showed init { - // TODO v_rodionov: #[REDACTED_TASK_KEY] check reissue order state before card details are showed fetchAddToWalletBanner() - fetchCardLimit() - subscribeToCardFrozenState() + + paymentAccountStatusSupplier.invoke(params.userWalletId) + .onEach { state -> + val status = state.value + if (status is PaymentAccountStatusValue.Loaded && + status.source == StatusSource.ACTUAL && + status.cards.isNotEmpty() + ) { + val card = status.cards.first() + val limit = card.limit?.actualCardLimit?.takeIf { it.period == TangemPayCardLimitPeriod.DAY } + val dailyLimitState = if (limit != null) { + TangemPayDailyLimitBlockState.Content( + limit = limit.amount.format { + val symbol = getJavaCurrencyByCode(status.currencyCode).symbol + fiat(status.currencyCode, symbol) + }, + onChangeClick = {}, // TODO v_rodionov: #[REDACTED_TASK_KEY] + ) + } else { + TangemPayDailyLimitBlockState.Error + } + uiState.update { it.copy(dailyLimitState = dailyLimitState, settings = buildSettings(card)) } + } else { + // TODO v_rodionov: #[REDACTED_TASK_KEY] show error state + } + } + .launchIn(modelScope) } - private fun onClickChangePIN() { - if (!params.config.isPinSet) { + private fun buildSettings(card: TangemPayCard): ImmutableList { + return persistentListOf( + TangemPayCardPageSetting( + title = TextReference.Res(R.string.tangempay_card_details_change_pin), + onSettingClick = { onClickChangePIN(card.hasPinCode) }, + ), + TangemPayCardPageSetting( + title = TextReference.Res(R.string.tangempay_card_details_freeze_card), + onSettingClick = { onClickFreezeOrUnfreezeCard(card.isFrozen) }, + ), + TangemPayCardPageSetting( + title = TextReference.Res(R.string.tangempay_card_details_reissue_card), + onSettingClick = ::onClickReissueCard, + ), + ) + } + + private fun onClickChangePIN(isPinSet: Boolean) { + if (!isPinSet) { router.push(TangemPayDetailsInnerRoute.ChangePIN) } else { bottomSheetNavigation.activate( @@ -117,15 +140,13 @@ internal class TangemPayCardPageModel @Inject constructor( } } - private fun onClickFreezeOrUnfreezeCard() { - when (currentFrozenState) { - TangemPayCardFrozenState.Frozen -> uiMessageSender.send( - TangemPayMessagesFactory.createUnfreezeCardMessage(onUnfreezeClicked = ::unfreezeCard), - ) - else -> uiMessageSender.send( - TangemPayMessagesFactory.createFreezeCardMessage(onFreezeClicked = ::freezeCard), - ) + private fun onClickFreezeOrUnfreezeCard(isFrozen: Boolean) { + val message = if (isFrozen) { + TangemPayMessagesFactory.createUnfreezeCardMessage(onUnfreezeClicked = ::unfreezeCard) + } else { + TangemPayMessagesFactory.createFreezeCardMessage(onFreezeClicked = ::freezeCard) } + uiMessageSender.send(message) } private fun onClickReissueCard() { @@ -242,13 +263,6 @@ internal class TangemPayCardPageModel @Inject constructor( } } - private fun subscribeToCardFrozenState() { - cardDetailsRepository - .cardFrozenState(params.config.cardId) - .onEach { state -> currentFrozenState = state } - .launchIn(modelScope) - } - private fun fetchAddToWalletBanner() { modelScope.launch { val isDone = cardDetailsRepository.isAddToWalletDone(params.userWalletId).getOrNull() == true @@ -265,39 +279,6 @@ internal class TangemPayCardPageModel @Inject constructor( }.saveIn(addToWalletBannerJobHolder) } - private fun fetchCardLimit() { - modelScope.launch { - onboardingRepository.getCustomerInfo(params.userWalletId) - .onRight { info -> - val productInstance = info.productInstance - val cardInfo = info.cardInfo - val actualCardLimit = productInstance?.actualCardLimit - val dailyLimitState = if ( - productInstance != null && - cardInfo != null && - actualCardLimit?.period == TangemPayCardLimitPeriod.DAY - ) { - val limit = actualCardLimit.amount.format { - val symbol = getJavaCurrencyByCode(cardInfo.currencyCode).symbol - fiat(cardInfo.currencyCode, symbol) - } - TangemPayDailyLimitBlockState.Content( - limit = limit, - onChangeClick = {}, // TODO v_rodionov: #[REDACTED_TASK_KEY] - ) - } else { - TangemPayDailyLimitBlockState.Error - } - uiState.update { it.copy(dailyLimitState = dailyLimitState) } - } - .onLeft { - uiState.update { state -> - state.copy(dailyLimitState = TangemPayDailyLimitBlockState.Error) - } - } - } - } - private fun onClickAddToWallet() { router.push(TangemPayDetailsInnerRoute.AddToWallet) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt index 4dc9493025..36bc62a6cc 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt @@ -213,7 +213,6 @@ internal class GetMultiWalletWarningsFactory @Inject constructor( is PaymentAccountStatusValue.IssuingCard, is PaymentAccountStatusValue.Loaded, is PaymentAccountStatusValue.Loading, - is PaymentAccountStatusValue.Locked, is PaymentAccountStatusValue.UnderReview, -> null } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetWalletNotificationsFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetWalletNotificationsFactory.kt index 8ce6b1a9c0..203004c0fc 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetWalletNotificationsFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetWalletNotificationsFactory.kt @@ -237,7 +237,6 @@ internal class GetWalletNotificationsFactory @Inject constructor( is PaymentAccountStatusValue.IssuingCard, is PaymentAccountStatusValue.Loaded, is PaymentAccountStatusValue.Loading, - is PaymentAccountStatusValue.Locked, is PaymentAccountStatusValue.UnderReview, -> null } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TangemPayMainBlockConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TangemPayMainBlockConverter.kt index a065f12000..77a4f8c17b 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TangemPayMainBlockConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TangemPayMainBlockConverter.kt @@ -55,54 +55,37 @@ internal class TangemPayMainBlockConverter( ) is PaymentAccountStatusValue.NotCreated -> TangemPayMainUM.Empty is PaymentAccountStatusValue.Loading -> TangemPayMainUM.Loading - is PaymentAccountStatusValue.Locked -> TangemPayMainUM.Content( - subtitle = stringReference("*${statusValue.lastFourDigits}"), - isBalanceFlickering = statusValue.source == StatusSource.CACHE, - balance = getBalanceText( - currencyCode = statusValue.currencyCode, - balance = statusValue.fiatBalance.availableBalance, - ), - balanceSubtitle = stringReference("USDC"), // TODO hardcode for now - shouldShowOnlyCacheWarning = statusValue.source == StatusSource.ONLY_CACHE, - onClick = { - tangemPayClickIntents.openDetails( - value.account.userWalletId, - TangemPayDetailsConfig( - customerId = statusValue.customerId, - cardId = statusValue.cardId, - isPinSet = statusValue.isPinSet, - cardFrozenState = TangemPayCardFrozenState.Frozen, - cardNumberEnd = statusValue.lastFourDigits, - chainId = POLYGON_CHAIN_ID, - displayName = statusValue.displayName, - ), - ) - }, - ) - is PaymentAccountStatusValue.Loaded -> TangemPayMainUM.Content( - subtitle = stringReference("*${statusValue.lastFourDigits}"), - isBalanceFlickering = statusValue.source == StatusSource.CACHE, - balance = getBalanceText( - currencyCode = statusValue.currencyCode, - balance = statusValue.fiatBalance.availableBalance, - ), - balanceSubtitle = stringReference("USDC"), // TODO hardcode for now - shouldShowOnlyCacheWarning = statusValue.source == StatusSource.ONLY_CACHE, - onClick = { - tangemPayClickIntents.openDetails( - value.account.userWalletId, - TangemPayDetailsConfig( - customerId = statusValue.customerId, - cardId = statusValue.cardId, - isPinSet = statusValue.isPinSet, - cardFrozenState = TangemPayCardFrozenState.Unfrozen, - cardNumberEnd = statusValue.lastFourDigits, - chainId = POLYGON_CHAIN_ID, - displayName = statusValue.displayName, - ), - ) - }, - ) + is PaymentAccountStatusValue.Loaded -> { + val card = statusValue.cards.firstOrNull() ?: return TangemPayMainUM.TemporaryUnavailable + TangemPayMainUM.Content( + subtitle = stringReference("*${card.lastDigits}"), + isBalanceFlickering = statusValue.source == StatusSource.CACHE, + balance = getBalanceText( + currencyCode = statusValue.currencyCode, + balance = statusValue.fiatBalance.availableBalance, + ), + balanceSubtitle = stringReference("USDC"), // TODO hardcode for now + shouldShowOnlyCacheWarning = statusValue.source == StatusSource.ONLY_CACHE, + onClick = { + tangemPayClickIntents.openDetails( + value.account.userWalletId, + TangemPayDetailsConfig( + customerId = statusValue.customerId, + cardId = card.id, + isPinSet = card.hasPinCode, + cardFrozenState = if (card.isFrozen) { + TangemPayCardFrozenState.Frozen + } else { + TangemPayCardFrozenState.Unfrozen + }, + cardNumberEnd = card.lastDigits, + chainId = POLYGON_CHAIN_ID, + displayName = card.displayName, + ), + ) + }, + ) + } } }