Updated on 2026-08-14
This commit is contained in:
parent
269a6d1d57
commit
161477c16a
11 changed files with 125 additions and 72 deletions
|
|
@ -67,7 +67,11 @@ internal class DefaultTangemPayStorage @Inject constructor(
|
|||
secureStorage.get(createOrderIdKey(customerWalletAddress))?.decodeToString(throwOnInvalidSequence = true)
|
||||
}
|
||||
|
||||
override suspend fun clear(customerWalletAddress: String) = withContext(dispatcherProvider.io) {
|
||||
override suspend fun clearOrderId(customerWalletAddress: String) = withContext(dispatcherProvider.io) {
|
||||
secureStorage.delete(createOrderIdKey(customerWalletAddress))
|
||||
}
|
||||
|
||||
override suspend fun clearAll(customerWalletAddress: String) = withContext(dispatcherProvider.io) {
|
||||
secureStorage.delete(createKey(customerWalletAddress))
|
||||
secureStorage.delete(createOrderIdKey(customerWalletAddress))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,5 +12,7 @@ interface TangemPayStorage {
|
|||
|
||||
suspend fun getOrderId(customerWalletAddress: String): String?
|
||||
|
||||
suspend fun clear(customerWalletAddress: String)
|
||||
suspend fun clearOrderId(customerWalletAddress: String)
|
||||
|
||||
suspend fun clearAll(customerWalletAddress: String)
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@ import kotlinx.coroutines.withContext
|
|||
import javax.inject.Inject
|
||||
|
||||
private const val VALID_STATUS = "valid"
|
||||
private const val APPROVED_KYC_STATUS = "APPROVED"
|
||||
private const val TAG = "TangemPay: OnboardingRepository"
|
||||
|
||||
internal class DefaultOnboardingRepository @Inject constructor(
|
||||
|
|
@ -47,13 +48,36 @@ internal class DefaultOnboardingRepository @Inject constructor(
|
|||
|
||||
override suspend fun getMainScreenCustomerInfo(): Either<UniversalError, MainScreenCustomerInfo> {
|
||||
return requestHelper.runWithErrorLogs(TAG) {
|
||||
val result = requestHelper.requestWithPersistedToken { authHeader ->
|
||||
tangemPayApi.getCustomerMe(authHeader)
|
||||
}.result
|
||||
val customerWalletAddress = requestHelper.getCustomerWalletAddress()
|
||||
|
||||
val orderStatus = getOrderStatus().getOrNull() ?: error("Order status is null")
|
||||
when (val orderId = tangemPayStorage.getOrderId(customerWalletAddress)) {
|
||||
// If order id wasn't saved -> get customer info
|
||||
null -> {
|
||||
MainScreenCustomerInfo(
|
||||
info = getCustomerInfoWithPersistedToken(),
|
||||
orderStatus = OrderStatus.UNKNOWN,
|
||||
)
|
||||
}
|
||||
// If order id was saved -> check its status
|
||||
else -> {
|
||||
val orderStatus = getOrderStatus(orderId)
|
||||
val customerInfo = when (orderStatus) {
|
||||
// Kyc is passed and user waits for order creation -> no need to get customer info
|
||||
OrderStatus.NEW,
|
||||
OrderStatus.PROCESSING,
|
||||
-> CustomerInfo(productInstance = null, isKycApproved = true, cardInfo = null)
|
||||
|
||||
MainScreenCustomerInfo(info = getCustomerInfo(result), orderStatus = orderStatus)
|
||||
// Order was created/cancelled -> clear order id and get customer info
|
||||
OrderStatus.UNKNOWN,
|
||||
OrderStatus.COMPLETED,
|
||||
OrderStatus.CANCELED,
|
||||
-> getCustomerInfoWithPersistedToken().also {
|
||||
tangemPayStorage.clearOrderId(customerWalletAddress)
|
||||
}
|
||||
}
|
||||
MainScreenCustomerInfo(info = customerInfo, orderStatus = orderStatus)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -84,27 +108,28 @@ internal class DefaultOnboardingRepository @Inject constructor(
|
|||
}
|
||||
return CustomerInfo(
|
||||
productInstance = response?.productInstance?.let { ProductInstance(id = it.id, status = it.status) },
|
||||
kycStatus = response?.kyc?.status,
|
||||
isKycApproved = response?.kyc?.status == APPROVED_KYC_STATUS,
|
||||
cardInfo = cardInfo,
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun getOrderStatus(): Either<UniversalError, OrderStatus> {
|
||||
return requestHelper.runWithErrorLogs(TAG) {
|
||||
val walletAddress = requestHelper.getCustomerWalletAddress()
|
||||
val orderId: String = tangemPayStorage.getOrderId(walletAddress)
|
||||
?: return@runWithErrorLogs OrderStatus.NOT_ISSUED
|
||||
private suspend fun getOrderStatus(orderId: String): OrderStatus {
|
||||
val result = requestHelper.request { authHeader ->
|
||||
tangemPayApi.getOrder(authHeader, orderId)
|
||||
}.result ?: error("Order result is null")
|
||||
|
||||
val result = requestHelper.request { authHeader ->
|
||||
tangemPayApi.getOrder(authHeader, orderId)
|
||||
}.result ?: error("Order result is null")
|
||||
|
||||
when (result.status) {
|
||||
OrderStatus.NEW.apiName -> OrderStatus.NEW
|
||||
OrderStatus.PROCESSING.apiName -> OrderStatus.PROCESSING
|
||||
OrderStatus.COMPLETED.apiName -> OrderStatus.COMPLETED
|
||||
else -> OrderStatus.CANCELED
|
||||
}
|
||||
return when (result.status) {
|
||||
OrderStatus.NEW.apiName -> OrderStatus.NEW
|
||||
OrderStatus.PROCESSING.apiName -> OrderStatus.PROCESSING
|
||||
OrderStatus.COMPLETED.apiName -> OrderStatus.COMPLETED
|
||||
else -> OrderStatus.CANCELED
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getCustomerInfoWithPersistedToken(): CustomerInfo {
|
||||
val result = requestHelper.requestWithPersistedToken { authHeader ->
|
||||
tangemPayApi.getCustomerMe(authHeader)
|
||||
}.result
|
||||
return getCustomerInfo(result)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,8 +2,6 @@ package com.tangem.domain.pay.model
|
|||
|
||||
import java.math.BigDecimal
|
||||
|
||||
private const val APPROVED_KYC_STATUS = "APPROVED"
|
||||
|
||||
data class MainScreenCustomerInfo(
|
||||
val info: CustomerInfo,
|
||||
val orderStatus: OrderStatus,
|
||||
|
|
@ -11,7 +9,7 @@ data class MainScreenCustomerInfo(
|
|||
|
||||
data class CustomerInfo(
|
||||
val productInstance: ProductInstance?,
|
||||
val kycStatus: String?,
|
||||
val isKycApproved: Boolean,
|
||||
val cardInfo: CardInfo?,
|
||||
) {
|
||||
|
||||
|
|
@ -26,6 +24,4 @@ data class CustomerInfo(
|
|||
val currencyCode: String,
|
||||
val customerWalletAddress: String,
|
||||
)
|
||||
|
||||
fun isKycApproved() = kycStatus == APPROVED_KYC_STATUS
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.domain.pay.model
|
||||
|
||||
enum class OrderStatus(val apiName: String) {
|
||||
NOT_ISSUED(""),
|
||||
UNKNOWN(""),
|
||||
NEW("NEW"),
|
||||
PROCESSING("PROCESSING"),
|
||||
COMPLETED("COMPLETED"),
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ internal class TangemPayOnboardingModel @Inject constructor(
|
|||
repository.getCustomerInfo()
|
||||
.onRight { customerInfo ->
|
||||
when {
|
||||
!customerInfo.isKycApproved() -> {
|
||||
!customerInfo.isKycApproved -> {
|
||||
when (params) {
|
||||
is TangemPayOnboardingComponent.Params.Deeplink ->
|
||||
screenState.value = screenState.value.copy(fullScreenLoading = false)
|
||||
|
|
|
|||
|
|
@ -359,10 +359,10 @@ internal class WalletModel @Inject constructor(
|
|||
val info = tangemPayMainScreenCustomerInfoUseCase()
|
||||
if (info != null) {
|
||||
stateHolder.update(
|
||||
transformer = TangemPayStateTransformer(
|
||||
transformer = TangemPayInitialStateTransformer(
|
||||
value = info,
|
||||
onIssueOrderClick = ::issueOrder,
|
||||
onContinueKycClick = innerWalletRouter::openTangemPayOnboarding,
|
||||
onClickIssue = ::issueOrder,
|
||||
onClickKyc = innerWalletRouter::openTangemPayOnboarding,
|
||||
openDetails = innerWalletRouter::openTangemPayDetails,
|
||||
),
|
||||
)
|
||||
|
|
@ -371,9 +371,9 @@ internal class WalletModel @Inject constructor(
|
|||
|
||||
private fun issueOrder() {
|
||||
modelScope.launch {
|
||||
stateHolder.update(TangemPayStateTransformer(issueProgressState = true))
|
||||
stateHolder.update(TangemPayIssueProgressStateTransformer())
|
||||
tangemPayIssueOrderUseCase().onLeft {
|
||||
stateHolder.update(TangemPayStateTransformer(issueState = true, onIssueOrderClick = ::issueOrder))
|
||||
stateHolder.update(TangemPayIssueAvailableStateTransformer(onClickIssue = ::issueOrder))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,33 +1,28 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.transformers
|
||||
|
||||
import com.tangem.common.ui.R
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.domain.pay.model.CustomerInfo.CardInfo
|
||||
import com.tangem.domain.pay.model.MainScreenCustomerInfo
|
||||
import com.tangem.domain.pay.model.OrderStatus.CANCELED
|
||||
import com.tangem.domain.pay.model.OrderStatus.NOT_ISSUED
|
||||
import com.tangem.domain.pay.model.OrderStatus.UNKNOWN
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState.Progress
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletScreenState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.util.TangemPayStateCreator.createIssueAvailableState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.util.TangemPayStateCreator.createIssueProgressState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.util.TangemPayStateCreator.createKycInProgressState
|
||||
import java.util.Currency
|
||||
|
||||
internal class TangemPayStateTransformer(
|
||||
internal class TangemPayInitialStateTransformer(
|
||||
private val value: MainScreenCustomerInfo? = null,
|
||||
private val onIssueOrderClick: () -> Unit = {},
|
||||
private val onContinueKycClick: () -> Unit = {},
|
||||
private val onClickIssue: () -> Unit = {},
|
||||
private val onClickKyc: () -> Unit = {},
|
||||
private val openDetails: (customerWalletAddress: String, cardNumberEnd: String) -> Unit = { _, _ -> },
|
||||
private val issueProgressState: Boolean = false,
|
||||
private val issueState: Boolean = false,
|
||||
) : WalletScreenStateTransformer {
|
||||
|
||||
override fun transform(prevState: WalletScreenState): WalletScreenState {
|
||||
val tangemPayState = when {
|
||||
issueProgressState -> createIssueProgressState()
|
||||
issueState -> createIssueState()
|
||||
else -> createInitialState()
|
||||
}
|
||||
val tangemPayState = createInitialState()
|
||||
return prevState.copy(tangemPayState = tangemPayState)
|
||||
}
|
||||
|
||||
|
|
@ -35,35 +30,13 @@ internal class TangemPayStateTransformer(
|
|||
val cardInfo = value?.info?.cardInfo
|
||||
return when {
|
||||
value == null -> TangemPayState.Empty
|
||||
!value.info.isKycApproved() -> createKycInProgressState(onContinueKycClick)
|
||||
!value.info.isKycApproved -> createKycInProgressState(onClickKyc)
|
||||
cardInfo != null -> getCardInfoState(cardInfo)
|
||||
value.orderStatus == NOT_ISSUED || value.orderStatus == CANCELED -> createIssueState()
|
||||
value.orderStatus == UNKNOWN || value.orderStatus == CANCELED -> createIssueAvailableState(onClickIssue)
|
||||
else -> createIssueProgressState()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createIssueProgressState(): TangemPayState = Progress(
|
||||
title = TextReference.Res(R.string.tangempay_issue_card_notification_title),
|
||||
buttonText = TextReference.EMPTY,
|
||||
iconRes = R.drawable.ic_tangem_pay_promo_card_36,
|
||||
onButtonClick = {},
|
||||
showProgress = true,
|
||||
)
|
||||
|
||||
private fun createIssueState() = Progress(
|
||||
title = TextReference.Res(R.string.tangempay_issue_card_notification_title),
|
||||
buttonText = TextReference.Res(R.string.common_continue),
|
||||
iconRes = R.drawable.ic_tangem_pay_promo_card_36,
|
||||
onButtonClick = onIssueOrderClick,
|
||||
)
|
||||
|
||||
private fun createKycInProgressState(onContinueKycClick: () -> Unit): TangemPayState = Progress(
|
||||
title = TextReference.Res(R.string.tangempay_kyc_in_progress_notification_title),
|
||||
buttonText = TextReference.Res(R.string.tangempay_kyc_in_progress_notification_button),
|
||||
iconRes = R.drawable.ic_promo_kyc_36,
|
||||
onButtonClick = onContinueKycClick,
|
||||
)
|
||||
|
||||
private fun getCardInfoState(cardInfo: CardInfo): TangemPayState = TangemPayState.Card(
|
||||
lastFourDigits = TextReference.Str("*${cardInfo.lastFourDigits}"),
|
||||
balanceText = TextReference.Str(getBalanceText(cardInfo)),
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.transformers
|
||||
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletScreenState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.util.TangemPayStateCreator.createIssueAvailableState
|
||||
|
||||
internal class TangemPayIssueAvailableStateTransformer(
|
||||
private val onClickIssue: () -> Unit = {},
|
||||
) : WalletScreenStateTransformer {
|
||||
|
||||
override fun transform(prevState: WalletScreenState): WalletScreenState =
|
||||
prevState.copy(tangemPayState = createIssueAvailableState(onClickIssue))
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.transformers
|
||||
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletScreenState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.util.TangemPayStateCreator.createIssueProgressState
|
||||
|
||||
internal class TangemPayIssueProgressStateTransformer : WalletScreenStateTransformer {
|
||||
|
||||
override fun transform(prevState: WalletScreenState): WalletScreenState =
|
||||
prevState.copy(tangemPayState = createIssueProgressState())
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.util
|
||||
|
||||
import com.tangem.common.ui.R
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState.Progress
|
||||
|
||||
internal object TangemPayStateCreator {
|
||||
|
||||
fun createKycInProgressState(onClickKyc: () -> Unit): TangemPayState = Progress(
|
||||
title = TextReference.Res(R.string.tangempay_kyc_in_progress_notification_title),
|
||||
buttonText = TextReference.Res(R.string.tangempay_kyc_in_progress_notification_button),
|
||||
iconRes = R.drawable.ic_promo_kyc_36,
|
||||
onButtonClick = onClickKyc,
|
||||
)
|
||||
|
||||
fun createIssueAvailableState(onClickIssue: () -> Unit) = Progress(
|
||||
title = TextReference.Res(R.string.tangempay_issue_card_notification_title),
|
||||
buttonText = TextReference.Res(R.string.common_continue),
|
||||
iconRes = R.drawable.ic_tangem_pay_promo_card_36,
|
||||
onButtonClick = onClickIssue,
|
||||
)
|
||||
|
||||
fun createIssueProgressState(): TangemPayState = Progress(
|
||||
title = TextReference.Res(R.string.tangempay_issue_card_notification_title),
|
||||
buttonText = TextReference.EMPTY,
|
||||
iconRes = R.drawable.ic_tangem_pay_promo_card_36,
|
||||
onButtonClick = {},
|
||||
showProgress = true,
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue