Updated on 2026-08-14
This commit is contained in:
commit
495602deae
8 changed files with 106 additions and 4 deletions
|
|
@ -86,6 +86,12 @@ internal class FeedbackDataBuilder {
|
|||
builder.appendKeyValue("Fee", error.fee ?: "Unable to receive")
|
||||
}
|
||||
|
||||
fun addStakingInfo(validatorName: String?, transactionType: String?, unsignedTransaction: String?) {
|
||||
builder.appendKeyValue("Validator", validatorName ?: "unknown")
|
||||
builder.appendKeyValue("Action", transactionType ?: "unknown")
|
||||
builder.appendKeyValue("Unsigned transaction", unsignedTransaction ?: "unknown")
|
||||
}
|
||||
|
||||
fun addDelimiter(): StringBuilder = builder.appendDelimiter()
|
||||
|
||||
fun build(): String = builder.trimEnd().toString()
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class SaveBlockchainErrorUseCase(
|
|||
private val feedbackRepository: FeedbackRepository,
|
||||
) {
|
||||
|
||||
fun invoke(error: BlockchainErrorInfo) {
|
||||
operator fun invoke(error: BlockchainErrorInfo) {
|
||||
feedbackRepository.saveBlockchainErrorInfo(error = error)
|
||||
}
|
||||
}
|
||||
|
|
@ -22,4 +22,12 @@ sealed interface FeedbackEmailType {
|
|||
|
||||
/** User has problem with sending transaction */
|
||||
data class TransactionSendingProblem(override val cardInfo: CardInfo) : FeedbackEmailType
|
||||
|
||||
/** User has problem with staking */
|
||||
data class StakingProblem(
|
||||
override val cardInfo: CardInfo,
|
||||
val validatorName: String?,
|
||||
val transactionType: String?,
|
||||
val unsignedTransaction: String?,
|
||||
) : FeedbackEmailType
|
||||
}
|
||||
|
|
@ -23,6 +23,12 @@ internal class EmailMessageBodyResolver(
|
|||
is FeedbackEmailType.RateCanBeBetter -> addCardAndPhoneInfo(type.cardInfo)
|
||||
is FeedbackEmailType.ScanningProblem -> addScanningProblemBody()
|
||||
is FeedbackEmailType.TransactionSendingProblem -> addTransactionSendingProblemBody(type.cardInfo)
|
||||
is FeedbackEmailType.StakingProblem -> addStakingProblemBody(
|
||||
type.cardInfo,
|
||||
type.validatorName,
|
||||
type.transactionType,
|
||||
type.unsignedTransaction,
|
||||
)
|
||||
}
|
||||
|
||||
return build()
|
||||
|
|
@ -72,6 +78,36 @@ internal class EmailMessageBodyResolver(
|
|||
addPhoneInfo(phoneInfo = feedbackRepository.getPhoneInfo())
|
||||
}
|
||||
|
||||
private suspend fun FeedbackDataBuilder.addStakingProblemBody(
|
||||
cardInfo: CardInfo,
|
||||
validatorName: String?,
|
||||
transactionType: String?,
|
||||
unsignedTransaction: String?,
|
||||
) {
|
||||
addCardInfo(cardInfo)
|
||||
addDelimiter()
|
||||
|
||||
val userWalletId = requireNotNull(cardInfo.userWalletId) { "UserWalletId must be not null" }
|
||||
val blockchainError = feedbackRepository.getBlockchainErrorInfo(userWalletId = userWalletId)
|
||||
val blockchainInfo = blockchainError?.let {
|
||||
feedbackRepository.getBlockchainInfo(
|
||||
userWalletId = userWalletId,
|
||||
blockchainId = blockchainError.blockchainId,
|
||||
derivationPath = blockchainError.derivationPath,
|
||||
)
|
||||
}
|
||||
|
||||
if (blockchainInfo != null) {
|
||||
addBlockchainError(blockchainInfo, blockchainError)
|
||||
addDelimiter()
|
||||
}
|
||||
|
||||
addStakingInfo(validatorName, transactionType, unsignedTransaction)
|
||||
addDelimiter()
|
||||
|
||||
addPhoneInfo(phoneInfo = feedbackRepository.getPhoneInfo())
|
||||
}
|
||||
|
||||
private fun FeedbackDataBuilder.addCardAndPhoneInfo(cardInfo: CardInfo) {
|
||||
addCardInfo(cardInfo)
|
||||
addDelimiter()
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@ internal class EmailMessageTitleResolver(private val resources: Resources) {
|
|||
is FeedbackEmailType.DirectUserRequest -> R.string.feedback_preface_support
|
||||
is FeedbackEmailType.RateCanBeBetter -> R.string.feedback_preface_rate_negative
|
||||
is FeedbackEmailType.ScanningProblem -> R.string.feedback_preface_scan_failed
|
||||
is FeedbackEmailType.TransactionSendingProblem -> R.string.feedback_preface_tx_failed
|
||||
is FeedbackEmailType.TransactionSendingProblem,
|
||||
is FeedbackEmailType.StakingProblem,
|
||||
-> R.string.feedback_preface_tx_failed
|
||||
}
|
||||
.let(resources::getString)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ internal class EmailSubjectResolver(private val resources: Resources) {
|
|||
is FeedbackEmailType.RateCanBeBetter -> R.string.feedback_subject_rate_negative
|
||||
is FeedbackEmailType.ScanningProblem -> R.string.feedback_subject_scan_failed
|
||||
is FeedbackEmailType.TransactionSendingProblem -> R.string.feedback_subject_tx_failed
|
||||
is FeedbackEmailType.StakingProblem -> R.string.feedback_subject_tx_failed
|
||||
}
|
||||
.let(resources::getString)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ dependencies {
|
|||
implementation(projects.domain.transaction)
|
||||
implementation(projects.domain.transaction.models)
|
||||
implementation(projects.domain.txhistory)
|
||||
implementation(projects.domain.feedback)
|
||||
|
||||
/** Common */
|
||||
implementation(projects.common.ui)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,11 @@ import com.tangem.core.ui.haptic.VibratorHapticManager
|
|||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.feedback.FeedbackManager
|
||||
import com.tangem.domain.feedback.GetCardInfoUseCase
|
||||
import com.tangem.domain.feedback.SaveBlockchainErrorUseCase
|
||||
import com.tangem.domain.feedback.models.BlockchainErrorInfo
|
||||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||
import com.tangem.domain.staking.*
|
||||
import com.tangem.domain.staking.model.StakingApproval
|
||||
import com.tangem.domain.staking.model.stakekit.PendingAction
|
||||
|
|
@ -24,6 +29,7 @@ import com.tangem.domain.staking.model.stakekit.Yield
|
|||
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
|
||||
import com.tangem.domain.staking.model.stakekit.transaction.ActionParams
|
||||
import com.tangem.domain.staking.model.stakekit.transaction.StakingGasEstimate
|
||||
import com.tangem.domain.staking.model.stakekit.transaction.StakingTransaction
|
||||
import com.tangem.domain.staking.model.stakekit.transaction.StakingTransactionType
|
||||
import com.tangem.domain.tokens.FetchPendingTransactionsUseCase
|
||||
import com.tangem.domain.tokens.GetCryptoCurrencyStatusSyncUseCase
|
||||
|
|
@ -95,6 +101,9 @@ internal class StakingViewModel @Inject constructor(
|
|||
private val isApproveNeededUseCase: IsApproveNeededUseCase,
|
||||
private val clipboardManager: ClipboardManager,
|
||||
private val vibratorHapticManager: VibratorHapticManager,
|
||||
private val feedbackManager: FeedbackManager,
|
||||
private val getCardInfoUseCase: GetCardInfoUseCase,
|
||||
private val saveBlockchainErrorUseCase: SaveBlockchainErrorUseCase,
|
||||
@DelayedWork private val coroutineScope: CoroutineScope,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : ViewModel(), DefaultLifecycleObserver, StakingClickIntents {
|
||||
|
|
@ -134,6 +143,8 @@ internal class StakingViewModel @Inject constructor(
|
|||
private var stakingApproval: StakingApproval = StakingApproval.Empty
|
||||
private val allowanceTaskScheduler = SingleTaskScheduler<BigDecimal>()
|
||||
|
||||
private var transactionInProgress: StakingTransaction? = null
|
||||
|
||||
private var approvalJobHolder: JobHolder = JobHolder()
|
||||
|
||||
init {
|
||||
|
|
@ -207,9 +218,13 @@ internal class StakingViewModel @Inject constructor(
|
|||
stakingEventFactory.createStakingErrorAlert(it)
|
||||
return@launch
|
||||
}
|
||||
val gasEstimate = constructedTransaction.gasEstimate
|
||||
?: return@launch stakingEventFactory.createGenericErrorAlert("Gas estimate is null")
|
||||
|
||||
transactionInProgress = constructedTransaction
|
||||
sendStakingTransaction(
|
||||
transactionId = constructedTransaction.id,
|
||||
gasEstimate = constructedTransaction.gasEstimate ?: error("No gas estimate available"),
|
||||
gasEstimate = gasEstimate,
|
||||
txData = transactionData,
|
||||
pendingActionList = confirmationState.pendingActions,
|
||||
)
|
||||
|
|
@ -504,7 +519,39 @@ internal class StakingViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onFailedTxEmailClick(errorMessage: String) {
|
||||
// TODO staking sending feedback email [REDACTED_TASK_KEY]
|
||||
viewModelScope.launch {
|
||||
val network = cryptoCurrencyStatus.currency.network
|
||||
|
||||
val cardInfo = getCardInfoUseCase(userWallet.scanResponse).getOrElse { error("CardInfo must be not null") }
|
||||
val amountState = uiState.value.amountState as? AmountState.Data
|
||||
val confirmationState = uiState.value.confirmationState as? StakingStates.ConfirmationState.Data
|
||||
val validatorState = confirmationState?.validatorState as? ValidatorState.Content
|
||||
val feeState = confirmationState?.feeState as? FeeState.Content
|
||||
|
||||
val validator = validatorState?.chosenValidator
|
||||
val feeAmount = feeState?.fee?.amount
|
||||
val amount = amountState?.amountTextField?.cryptoAmount
|
||||
saveBlockchainErrorUseCase(
|
||||
error = BlockchainErrorInfo(
|
||||
errorMessage = errorMessage,
|
||||
blockchainId = network.id.value,
|
||||
derivationPath = network.derivationPath.value,
|
||||
destinationAddress = validator?.address.orEmpty(),
|
||||
tokenSymbol = (cryptoCurrencyStatus.currency as? CryptoCurrency.Token)?.symbol,
|
||||
amount = amount?.run { value?.toPlainString() + currencySymbol }.orEmpty(),
|
||||
fee = feeAmount?.run { value?.toPlainString() + currencySymbol }.orEmpty(),
|
||||
),
|
||||
)
|
||||
|
||||
val email = FeedbackEmailType.StakingProblem(
|
||||
cardInfo = cardInfo,
|
||||
validatorName = validator?.name,
|
||||
transactionType = transactionInProgress?.type?.name,
|
||||
unsignedTransaction = transactionInProgress?.unsignedTransaction,
|
||||
)
|
||||
|
||||
feedbackManager.sendEmail(email)
|
||||
}
|
||||
}
|
||||
|
||||
fun setRouter(router: InnerStakingRouter, stateRouter: StakingStateRouter) {
|
||||
|
|
@ -602,6 +649,7 @@ internal class StakingViewModel @Inject constructor(
|
|||
stakingEventFactory.createSendTransactionErrorAlert(error)
|
||||
},
|
||||
ifRight = { txHash ->
|
||||
transactionInProgress = null
|
||||
submitHash(transactionId, txHash)
|
||||
scheduleUpdates()
|
||||
val txUrl = getExplorerTransactionUrlUseCase(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue