Updated on 2026-08-14
This commit is contained in:
parent
33c331f529
commit
b2b0b3cc72
14 changed files with 144 additions and 79 deletions
|
|
@ -44,7 +44,12 @@ class NetworkLogsSaveInterceptor(
|
|||
throw e
|
||||
}
|
||||
|
||||
if (restrictedForLogURLs.contains(request.url.host + request.url.encodedPath)) {
|
||||
val host = request.url.host
|
||||
val path = request.url.encodedPath
|
||||
val isRestrictedUrl = restrictedForLogURLs.contains(host + path)
|
||||
val isRestrictedHost = restrictedForLogHosts.any { host.contains(it) }
|
||||
|
||||
if (isRestrictedUrl || isRestrictedHost) {
|
||||
logResponseWithEmptyMessage(response, startNs)
|
||||
} else {
|
||||
logResponseMessage(response, startNs)
|
||||
|
|
@ -222,5 +227,8 @@ class NetworkLogsSaveInterceptor(
|
|||
val restrictedForLogURLs = listOf(
|
||||
"api.stakek.it/v1/yields/enabled",
|
||||
)
|
||||
val restrictedForLogHosts = listOf(
|
||||
"us.paera.com",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1453,6 +1453,7 @@
|
|||
<string name="tangempay_failed_to_issue_card">Failed to issue card</string>
|
||||
<string name="tangempay_failed_to_issue_card_retry_description">A technical error has occurred, please try again by clicking the button below.</string>
|
||||
<string name="tangempay_failed_to_issue_card_support_description">A technical error has occurred, please contact support.</string>
|
||||
<string name="tangempay_go_to_support">Go to Support</string>
|
||||
<string name="tangempay_issue_card_notification_description">It usually takes up to 15 minutes</string>
|
||||
<string name="tangempay_issue_card_notification_title">Setting up your Tangem Card</string>
|
||||
<string name="tangempay_issuing_your_card">Issuing your card</string>
|
||||
|
|
|
|||
|
|
@ -2,14 +2,12 @@ package com.tangem.data.pay
|
|||
|
||||
import arrow.core.Either
|
||||
import arrow.core.Either.Companion.catch
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.blockchain.blockchains.ethereum.Chain
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.core.error.UniversalError
|
||||
import com.tangem.data.common.currency.CryptoCurrencyFactory
|
||||
import com.tangem.data.common.network.NetworkFactory
|
||||
import com.tangem.data.pay.util.TangemPayErrorConverter
|
||||
import com.tangem.datasource.di.NetworkMoshi
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.pay.TangemPayCryptoCurrencyFactory
|
||||
|
|
@ -26,8 +24,8 @@ private const val TOKEN_CONTRACT_ADDRESS = "0x3c499c542cef5e3811e1192ce70d8cc03d
|
|||
private const val TOKEN_DECIMALS = 6
|
||||
|
||||
internal class DefaultTangemPayCryptoCurrencyFactory @Inject constructor(
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
private val errorConverter: TangemPayErrorConverter,
|
||||
) : TangemPayCryptoCurrencyFactory {
|
||||
|
||||
private val cryptoCurrencyFactory by lazy(mode = LazyThreadSafetyMode.NONE) {
|
||||
|
|
@ -37,8 +35,6 @@ internal class DefaultTangemPayCryptoCurrencyFactory @Inject constructor(
|
|||
NetworkFactory(excludedBlockchains)
|
||||
}
|
||||
|
||||
private val errorConverter by lazy(mode = LazyThreadSafetyMode.NONE) { TangemPayErrorConverter(moshi) }
|
||||
|
||||
override fun create(userWallet: UserWallet, chainId: Int): Either<UniversalError, CryptoCurrency> {
|
||||
return catch {
|
||||
val chain = requireNotNull(Chain.entries.find { it.id == chainId }) { "Can not find chain with $chainId" }
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
package com.tangem.data.pay.repository
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.left
|
||||
import arrow.core.raise.catch
|
||||
import arrow.core.right
|
||||
import com.tangem.core.error.UniversalError
|
||||
import com.tangem.data.pay.util.RainCryptoUtil
|
||||
import com.tangem.data.pay.util.TangemPayErrorConverter
|
||||
import com.tangem.data.visa.config.VisaLibLoader
|
||||
import com.tangem.datasource.api.common.config.ApiConfig
|
||||
import com.tangem.datasource.api.common.config.ApiEnvironment
|
||||
|
|
@ -40,6 +44,7 @@ internal class DefaultTangemPayCardDetailsRepository @Inject constructor(
|
|||
private val rainCryptoUtil: RainCryptoUtil,
|
||||
private val storage: TangemPayStorage,
|
||||
private val cardFrozenStateStore: TangemPayCardFrozenStateStore,
|
||||
private val errorConverter: TangemPayErrorConverter,
|
||||
) : TangemPayCardDetailsRepository {
|
||||
|
||||
private val pollingScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
|
|
@ -64,37 +69,39 @@ internal class DefaultTangemPayCardDetailsRepository @Inject constructor(
|
|||
}
|
||||
|
||||
override suspend fun revealCardDetails(userWalletId: UserWalletId): Either<UniversalError, TangemPayCardDetails> {
|
||||
return requestHelper.runWithErrorLogs(TAG) {
|
||||
val publicKeyBase64 = getPublicKeyBase64()
|
||||
val (secretKeyBytes, sessionId) = rainCryptoUtil.generateSecretKeyAndSessionId(publicKeyBase64)
|
||||
return catch(
|
||||
block = {
|
||||
val publicKeyBase64 = getPublicKeyBase64()
|
||||
val (secretKeyBytes, sessionId) = rainCryptoUtil.generateSecretKeyAndSessionId(publicKeyBase64)
|
||||
val result = requestHelper.performRequest(userWalletId = userWalletId) { authHeader ->
|
||||
tangemPayApi.revealCardDetails(
|
||||
authHeader = authHeader,
|
||||
body = CardDetailsRequest(sessionId = sessionId),
|
||||
)
|
||||
}.getOrNull()?.result ?: error("Cannot reveal card details")
|
||||
|
||||
val result = requestHelper.request(userWalletId) { authHeader ->
|
||||
tangemPayApi.revealCardDetails(
|
||||
authHeader = authHeader,
|
||||
body = CardDetailsRequest(sessionId = sessionId),
|
||||
val pan = rainCryptoUtil.decryptSecret(
|
||||
base64Secret = result.pan.secret,
|
||||
base64Iv = result.pan.iv,
|
||||
secretKeyBytes = secretKeyBytes,
|
||||
)
|
||||
}.result ?: error("Cannot reveal card details")
|
||||
|
||||
val pan = rainCryptoUtil.decryptSecret(
|
||||
base64Secret = result.pan.secret,
|
||||
base64Iv = result.pan.iv,
|
||||
secretKeyBytes = secretKeyBytes,
|
||||
)
|
||||
val cvv = rainCryptoUtil.decryptSecret(
|
||||
base64Secret = result.cvv.secret,
|
||||
base64Iv = result.cvv.iv,
|
||||
secretKeyBytes = secretKeyBytes,
|
||||
)
|
||||
secretKeyBytes.fill(0)
|
||||
|
||||
val cvv = rainCryptoUtil.decryptSecret(
|
||||
base64Secret = result.cvv.secret,
|
||||
base64Iv = result.cvv.iv,
|
||||
secretKeyBytes = secretKeyBytes,
|
||||
)
|
||||
secretKeyBytes.fill(0)
|
||||
|
||||
TangemPayCardDetails(
|
||||
pan = pan,
|
||||
cvv = cvv,
|
||||
expirationYear = result.expirationYear,
|
||||
expirationMonth = result.expirationMonth,
|
||||
)
|
||||
}
|
||||
TangemPayCardDetails(
|
||||
pan = pan,
|
||||
cvv = cvv,
|
||||
expirationYear = result.expirationYear,
|
||||
expirationMonth = result.expirationMonth,
|
||||
).right()
|
||||
},
|
||||
catch = { errorConverter.convert(it).left() },
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun setPin(userWalletId: UserWalletId, pin: String): Either<UniversalError, SetPinResult> {
|
||||
|
|
|
|||
|
|
@ -5,14 +5,12 @@ import arrow.core.getOrElse
|
|||
import arrow.core.left
|
||||
import arrow.core.raise.catch
|
||||
import arrow.core.right
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.wire.Instant
|
||||
import com.tangem.data.pay.util.TangemPayErrorConverter
|
||||
import com.tangem.datasource.api.common.response.ApiResponse
|
||||
import com.tangem.datasource.api.pay.TangemPayAuthApi
|
||||
import com.tangem.datasource.api.pay.models.request.RefreshCustomerWalletAccessTokenRequest
|
||||
import com.tangem.datasource.api.pay.models.response.TangemPayGetTokensResponse
|
||||
import com.tangem.datasource.di.NetworkMoshi
|
||||
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
|
||||
import com.tangem.datasource.local.visa.TangemPayStorage
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
|
@ -33,7 +31,7 @@ private const val TAG = "TangemPayRequestPerformer"
|
|||
|
||||
@Singleton
|
||||
internal class TangemPayRequestPerformer @Inject constructor(
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
private val errorConverter: TangemPayErrorConverter,
|
||||
private val environmentConfigStorage: EnvironmentConfigStorage,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val tangemPayAuthApi: TangemPayAuthApi,
|
||||
|
|
@ -42,7 +40,6 @@ internal class TangemPayRequestPerformer @Inject constructor(
|
|||
|
||||
private val customerWalletAddresses = ConcurrentHashMap<UserWalletId, String>()
|
||||
private val tokensMutex = Mutex()
|
||||
private val errorConverter = TangemPayErrorConverter(moshi)
|
||||
|
||||
@Deprecated("Do not use this method")
|
||||
suspend fun <T : Any> runWithErrorLogs(tag: String, requestBlock: suspend () -> T): Either<VisaApiError, T> {
|
||||
|
|
|
|||
|
|
@ -3,10 +3,16 @@ package com.tangem.data.pay.util
|
|||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.datasource.api.common.response.ApiResponseError
|
||||
import com.tangem.datasource.api.pay.models.response.VisaErrorResponse
|
||||
import com.tangem.datasource.di.NetworkMoshi
|
||||
import com.tangem.domain.visa.error.VisaApiError
|
||||
import com.tangem.utils.converter.Converter
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
class TangemPayErrorConverter(moshi: Moshi) : Converter<Throwable, VisaApiError> {
|
||||
@Singleton
|
||||
internal class TangemPayErrorConverter @Inject constructor(
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
) : Converter<Throwable, VisaApiError> {
|
||||
|
||||
private val visaErrorAdapter by lazy { moshi.adapter(VisaErrorResponse::class.java) }
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ sealed interface FeedbackEmailType {
|
|||
}
|
||||
|
||||
sealed class Visa : FeedbackEmailType {
|
||||
data class FailedIssueCard(override val walletMetaInfo: WalletMetaInfo) : Visa()
|
||||
|
||||
data class DirectUserRequest(override val walletMetaInfo: WalletMetaInfo) : Visa()
|
||||
|
||||
|
|
@ -68,6 +67,8 @@ sealed interface FeedbackEmailType {
|
|||
override val walletMetaInfo: WalletMetaInfo,
|
||||
) : Visa()
|
||||
|
||||
data class FailedIssueCard(override val walletMetaInfo: WalletMetaInfo) : Visa()
|
||||
|
||||
data class DisputeV2(
|
||||
val item: TangemPayTxHistoryItem,
|
||||
override val walletMetaInfo: WalletMetaInfo,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ internal class FeedbackDataBuilder {
|
|||
|
||||
fun addTangemPayTxInfo(item: TangemPayTxHistoryItem) {
|
||||
builder.append(item.jsonRepresentation)
|
||||
builder.breakLine()
|
||||
}
|
||||
|
||||
fun addVisaTxInfo(txDetails: VisaTxDetails) {
|
||||
|
|
@ -108,6 +109,26 @@ internal class FeedbackDataBuilder {
|
|||
builder.appendKeyValue("App version", phoneInfo.appVersion)
|
||||
}
|
||||
|
||||
fun addTangemPayIssueType(type: FeedbackEmailType.Visa) {
|
||||
val issueType = when (type) {
|
||||
is FeedbackEmailType.Visa.Activation,
|
||||
is FeedbackEmailType.Visa.DirectUserRequest,
|
||||
is FeedbackEmailType.Visa.Dispute,
|
||||
is FeedbackEmailType.Visa.FeatureIsBeta,
|
||||
is FeedbackEmailType.Visa.Withdrawal,
|
||||
-> return
|
||||
is FeedbackEmailType.Visa.DisputeV2 -> when (type.item) {
|
||||
is TangemPayTxHistoryItem.Collateral -> "Receive/Withdraw"
|
||||
is TangemPayTxHistoryItem.Fee,
|
||||
is TangemPayTxHistoryItem.Spend,
|
||||
is TangemPayTxHistoryItem.Payment,
|
||||
-> "Transaction"
|
||||
}
|
||||
is FeedbackEmailType.Visa.FailedIssueCard -> "Card issuing"
|
||||
}
|
||||
builder.appendKeyValue("Issue type", issueType)
|
||||
}
|
||||
|
||||
fun addBlockchainError(info: BlockchainInfo, error: BlockchainErrorInfo) {
|
||||
builder.appendKeyValue("Blockchain", info.blockchain)
|
||||
builder.appendAddresses(
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ import com.tangem.domain.feedback.models.FeedbackEmail
|
|||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||
import com.tangem.domain.feedback.repository.FeedbackRepository
|
||||
import com.tangem.domain.feedback.utils.*
|
||||
import java.io.File
|
||||
|
||||
private const val BINDER_MAX_SIZE_BYTES = 500_000 // Safe limit under Android's 1MB Binder limit
|
||||
|
||||
/**
|
||||
* Get email with feedback for support
|
||||
|
|
@ -29,22 +32,30 @@ class SendFeedbackEmailUseCase(
|
|||
address = getAddress(type),
|
||||
subject = emailSubjectResolver.resolve(type),
|
||||
message = createMessage(type),
|
||||
file = feedbackRepository.getZipLogFile(),
|
||||
file = getFile(type),
|
||||
)
|
||||
|
||||
feedbackRepository.sendEmail(email)
|
||||
}
|
||||
|
||||
private suspend fun getFile(type: FeedbackEmailType): File? {
|
||||
return if (type.isVisaEmail()) {
|
||||
null
|
||||
} else {
|
||||
feedbackRepository.getZipLogFile()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAddress(type: FeedbackEmailType): String {
|
||||
return when {
|
||||
type is FeedbackEmailType.Visa || type.walletMetaInfo?.isVisa == true -> TANGEM_VISA_SUPPORT_EMAIL
|
||||
type.isVisaEmail() -> TANGEM_VISA_SUPPORT_EMAIL
|
||||
type.walletMetaInfo?.isStart2Coin == true -> START2COIN_SUPPORT_EMAIL
|
||||
else -> TANGEM_SUPPORT_EMAIL
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun createMessage(type: FeedbackEmailType): String {
|
||||
return StringBuilder().apply {
|
||||
val fullMessage = buildString {
|
||||
val title = emailMessageTitleResolver.resolve(type)
|
||||
append(title)
|
||||
|
||||
|
|
@ -54,7 +65,25 @@ class SendFeedbackEmailUseCase(
|
|||
|
||||
val body = emailMessageBodyResolver.resolve(type)
|
||||
append(body)
|
||||
}.toString()
|
||||
}
|
||||
|
||||
return truncateMessageIfNeeded(fullMessage)
|
||||
}
|
||||
|
||||
private fun truncateMessageIfNeeded(message: String): String {
|
||||
val messageBytes = message.toByteArray(Charsets.UTF_8)
|
||||
|
||||
return if (messageBytes.size > BINDER_MAX_SIZE_BYTES) {
|
||||
// Find a safe truncation point (avoid cutting in middle of UTF-8 chars)
|
||||
val truncatedBytes = messageBytes.sliceArray(0 until BINDER_MAX_SIZE_BYTES)
|
||||
String(truncatedBytes, Charsets.UTF_8)
|
||||
} else {
|
||||
message
|
||||
}
|
||||
}
|
||||
|
||||
private fun FeedbackEmailType.isVisaEmail(): Boolean {
|
||||
return this is FeedbackEmailType.Visa || this.walletMetaInfo?.isVisa == true
|
||||
}
|
||||
|
||||
private fun StringBuilder.appendDisclaimerIfNeeded(type: FeedbackEmailType): StringBuilder {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import com.tangem.domain.feedback.FeedbackDataBuilder
|
|||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||
import com.tangem.domain.feedback.models.WalletMetaInfo
|
||||
import com.tangem.domain.feedback.repository.FeedbackRepository
|
||||
import com.tangem.domain.visa.model.TangemPayTxHistoryItem
|
||||
import com.tangem.domain.visa.model.VisaTxDetails
|
||||
|
||||
/**
|
||||
|
|
@ -34,31 +33,39 @@ internal class EmailMessageBodyResolver(
|
|||
-> addPhoneInfoBody()
|
||||
is FeedbackEmailType.Visa.Activation -> addUserRequestBody(type.walletMetaInfo)
|
||||
is FeedbackEmailType.Visa.DirectUserRequest -> addUserRequestBody(type.walletMetaInfo)
|
||||
is FeedbackEmailType.Visa.FailedIssueCard -> addUserRequestBody(type.walletMetaInfo)
|
||||
is FeedbackEmailType.Visa.Dispute -> addVisaRequestBody(type.walletMetaInfo, type.visaTxDetails)
|
||||
is FeedbackEmailType.Visa.DisputeV2 -> addTangemPayRequestBody(type.walletMetaInfo, type.item)
|
||||
is FeedbackEmailType.Visa.FailedIssueCard -> addTangemPayFailedIssuingCardBody(type)
|
||||
is FeedbackEmailType.Visa.DisputeV2 -> addTangemPayDisputeRequestBody(type)
|
||||
is FeedbackEmailType.Visa.Withdrawal -> addTangemPayWithdrawalRequestBody(type)
|
||||
is FeedbackEmailType.Visa.FeatureIsBeta -> addTangemPayBetaRequestBody(type.walletMetaInfo)
|
||||
is FeedbackEmailType.Visa.FeatureIsBeta -> addTangemPayBetaRequestBody(type)
|
||||
}
|
||||
|
||||
return build()
|
||||
}
|
||||
|
||||
private suspend fun FeedbackDataBuilder.addTangemPayRequestBody(
|
||||
walletMetaInfo: WalletMetaInfo,
|
||||
item: TangemPayTxHistoryItem,
|
||||
) {
|
||||
addUserRequestBody(walletMetaInfo)
|
||||
private fun FeedbackDataBuilder.addTangemPayFailedIssuingCardBody(type: FeedbackEmailType.Visa.FailedIssueCard) {
|
||||
addTangemPayPhoneInfoBody(type)
|
||||
addDelimiter()
|
||||
addTangemPayTxInfo(item)
|
||||
type.walletMetaInfo.userWalletId?.let { userWalletId ->
|
||||
addUserWalletId(userWalletId = userWalletId.stringValue)
|
||||
}
|
||||
}
|
||||
|
||||
private fun FeedbackDataBuilder.addTangemPayBetaRequestBody(walletMetaInfo: WalletMetaInfo) {
|
||||
addPhoneInfoBody()
|
||||
private fun FeedbackDataBuilder.addTangemPayDisputeRequestBody(type: FeedbackEmailType.Visa.DisputeV2) {
|
||||
addTangemPayPhoneInfoBody(type = type)
|
||||
addDelimiter()
|
||||
walletMetaInfo.userWalletId?.let { userWalletId ->
|
||||
addTangemPayTxInfo(type.item)
|
||||
addDelimiter()
|
||||
type.walletMetaInfo.userWalletId?.let { userWalletId ->
|
||||
addUserWalletId(userWalletId = userWalletId.stringValue)
|
||||
}
|
||||
}
|
||||
|
||||
private fun FeedbackDataBuilder.addTangemPayBetaRequestBody(type: FeedbackEmailType.Visa) {
|
||||
addTangemPayPhoneInfoBody(type)
|
||||
addDelimiter()
|
||||
type.walletMetaInfo?.userWalletId?.let { userWalletId ->
|
||||
addUserWalletId(userWalletId = userWalletId.stringValue)
|
||||
addDelimiter()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -122,6 +129,11 @@ internal class EmailMessageBodyResolver(
|
|||
addPhoneInfo(phoneInfo = feedbackRepository.getPhoneInfo())
|
||||
}
|
||||
|
||||
private fun FeedbackDataBuilder.addTangemPayPhoneInfoBody(type: FeedbackEmailType.Visa) {
|
||||
addPhoneInfo(phoneInfo = feedbackRepository.getPhoneInfo())
|
||||
addTangemPayIssueType(type)
|
||||
}
|
||||
|
||||
private suspend fun FeedbackDataBuilder.addTransactionSendingProblemBody(walletMetaInfo: WalletMetaInfo) {
|
||||
addUserWalletMetaInfo(walletMetaInfo)
|
||||
addDelimiter()
|
||||
|
|
|
|||
|
|
@ -1647,8 +1647,7 @@ internal class SwapModel @Inject constructor(
|
|||
|
||||
private fun onTangemPaySupportClick(txId: String?) {
|
||||
modelScope.launch {
|
||||
val metaInfo = getWalletMetaInfoUseCase(userWallet.walletId)
|
||||
.getOrElse { error("CardInfo must be not null") }
|
||||
val metaInfo = getWalletMetaInfoUseCase(userWallet.walletId).getOrNull() ?: return@launch
|
||||
val email = FeedbackEmailType.Visa.Withdrawal(
|
||||
walletMetaInfo = metaInfo,
|
||||
providerName = dataState.selectedProvider?.name.orEmpty(),
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@ import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
|||
import com.tangem.domain.feedback.GetWalletMetaInfoUseCase
|
||||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||
import com.tangem.domain.models.wallet.requireColdWallet
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import com.tangem.features.tangempay.components.txHistory.TangemPayTxHistoryDetailsComponent
|
||||
import com.tangem.features.tangempay.entity.TangemPayTxHistoryDetailsUM
|
||||
import com.tangem.features.tangempay.model.transformers.TangemPayTxHistoryDetailsConverter
|
||||
|
|
@ -21,10 +19,8 @@ import javax.inject.Inject
|
|||
|
||||
@Stable
|
||||
@ModelScoped
|
||||
@Suppress("LongParameterList")
|
||||
internal class TangemPayTxHistoryDetailsModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val getUserWalletsUseCase: GetWalletsUseCase,
|
||||
private val getWalletMetaInfoUseCase: GetWalletMetaInfoUseCase,
|
||||
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
||||
private val urlOpener: UrlOpener,
|
||||
|
|
@ -66,12 +62,7 @@ internal class TangemPayTxHistoryDetailsModel @Inject constructor(
|
|||
|
||||
private fun dispute() {
|
||||
modelScope.launch {
|
||||
val userWalletId = params.userWalletId
|
||||
val userWallet = getUserWalletsUseCase.invokeSync()
|
||||
.firstOrNull { it.walletId == userWalletId } ?: return@launch
|
||||
val walletMetaInfo = getWalletMetaInfoUseCase.invoke(
|
||||
userWallet.requireColdWallet().scanResponse,
|
||||
).getOrNull() ?: return@launch
|
||||
val walletMetaInfo = getWalletMetaInfoUseCase.invoke(params.userWalletId).getOrNull() ?: return@launch
|
||||
|
||||
sendFeedbackEmailUseCase.invoke(
|
||||
FeedbackEmailType.Visa.DisputeV2(
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import androidx.compose.material3.Text
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Devices
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
|
|
@ -74,6 +75,7 @@ internal fun TangemPayTxHistoryDetailsContent(state: TangemPayTxHistoryDetailsUM
|
|||
text = state.transactionSubtitle.resolveReference(),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(top = 8.dp),
|
||||
|
|
@ -84,7 +86,7 @@ internal fun TangemPayTxHistoryDetailsContent(state: TangemPayTxHistoryDetailsUM
|
|||
state.localTransactionText?.let { localTransaction ->
|
||||
Text(
|
||||
modifier = Modifier.padding(top = 4.dp),
|
||||
text = localTransaction,
|
||||
text = localTransaction.orMaskWithStars(state.isBalanceHidden),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
|
|
@ -207,11 +209,11 @@ private class TangemPayTxHistoryDetailsUMProvider : CollectionPreviewParameterPr
|
|||
dismiss = {},
|
||||
),
|
||||
TangemPayTxHistoryDetailsUM(
|
||||
isBalanceHidden = false,
|
||||
isBalanceHidden = true,
|
||||
title = stringReference("12 June • 12:40"),
|
||||
iconState = ImageReference.Res(R.drawable.ic_category_24),
|
||||
transactionTitle = stringReference("Starbucks"),
|
||||
transactionSubtitle = stringReference("Food and drinks"),
|
||||
transactionSubtitle = stringReference("Food and drinks Food and drinks Food and drinks Food and drinks"),
|
||||
transactionAmount = "-$5.86",
|
||||
transactionAmountColor = themedColor { TangemTheme.colors.text.primary1 },
|
||||
localTransactionText = "€ 5.36",
|
||||
|
|
|
|||
|
|
@ -10,11 +10,9 @@ import com.tangem.domain.feedback.GetWalletMetaInfoUseCase
|
|||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.models.wallet.requireColdWallet
|
||||
import com.tangem.domain.pay.repository.OnboardingRepository
|
||||
import com.tangem.domain.pay.usecase.ProduceTangemPayInitialDataUseCase
|
||||
import com.tangem.domain.pay.usecase.TangemPayMainScreenCustomerInfoUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
||||
import com.tangem.features.tangempay.TangemPayFeatureToggles
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -41,7 +39,6 @@ internal class TangemPayClickIntentsImplementor @Inject constructor(
|
|||
private val onboardingRepository: OnboardingRepository,
|
||||
private val produceInitialDataTangemPay: ProduceTangemPayInitialDataUseCase,
|
||||
private val getWalletMetainfoUseCase: GetWalletMetaInfoUseCase,
|
||||
private val getUserWalletUseCase: GetUserWalletUseCase,
|
||||
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
||||
private val tangemPayMainScreenCustomerInfoUseCase: TangemPayMainScreenCustomerInfoUseCase,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
|
|
@ -93,7 +90,7 @@ internal class TangemPayClickIntentsImplementor @Inject constructor(
|
|||
body = resourceReference(R.string.tangempay_failed_to_issue_card_support_description)
|
||||
}
|
||||
secondaryButton {
|
||||
text = resourceReference(R.string.common_contact_support)
|
||||
text = resourceReference(R.string.tangempay_go_to_support)
|
||||
onClick {
|
||||
onPaySupportClick()
|
||||
closeBs()
|
||||
|
|
@ -106,10 +103,8 @@ internal class TangemPayClickIntentsImplementor @Inject constructor(
|
|||
|
||||
override fun onPaySupportClick() {
|
||||
modelScope.launch {
|
||||
val userWalletId = stateHolder.getSelectedWalletId()
|
||||
val userWallet = getUserWalletUseCase.invoke(userWalletId).getOrNull() ?: return@launch
|
||||
val cardInfo = getWalletMetainfoUseCase.invoke(
|
||||
userWallet.requireColdWallet().scanResponse,
|
||||
userWalletId = stateHolder.getSelectedWalletId(),
|
||||
).getOrNull() ?: return@launch
|
||||
|
||||
sendFeedbackEmailUseCase(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue