diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index ba4fcb4c42..57b95dc184 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -377,6 +377,7 @@ month More + Network Network fee Amount sent will be reduced by %1$s (%2$s) to cover the selected fee level @@ -479,6 +480,7 @@ Unstake Due to %1$s limitations only %2$d UTXOs can fit in a single transaction. This means you can only send %3$s or less. You need to reduce the amount. Value copied + View all Voting Wallets Warning @@ -1636,6 +1638,8 @@ Web 3.0 Compatible An incoming transaction of at least %1$s is required to proceed Insufficient funds + Open chat + Open mail By approving, you allow the smart contract to use your tokens in future transactions. Detailed mode Fixed Rate @@ -1726,6 +1730,7 @@ Other PIN-code Purchase + Rename card Unable to use on rooted devices Completed Declined @@ -1736,7 +1741,7 @@ The bank rejected this transaction request. Category MCC - A fee is charged in accordance with the service tariffs + A fee is charged due to the service tariffs The transaction was partially or fully reversed by the merchant Keep using your money. You can freeze anytime. Unfreeze your card? @@ -1817,6 +1822,24 @@ Come back to the app if you forget it. Set a limit from %s to %s Set limits + insufficient funds + card spending limit exceeded + СVV2 match fail + wrong expiry date + incorrect PIN + prohibited transaction + more than 25 online-transactions within a 2-day period + suspected BIN-attack from a merchant + technical error, try again + more than 2 transactions within a 3-day period at automatic fuel dispensers + high-risk merchant category + transaction from restricted country + high-risk e-commerce merchant + purchase over $150 at automated fuel dispensers + blocked mcc + blocked merchant + card locked + Reason Digital card I understand that I will completely lose access to my Tangem Pay Card and all funds on it without the possibility of recovery Failed to issue card @@ -2437,7 +2460,8 @@ Check transaction history for details Yield mode bonus paid out %1$s days left to unlock your bonus - You are eligible for 30 days APY boost, T&C apply, learn more + You are eligible for 30 days APY boost + Terms and Conditions apply Activate Yield Mode for the first time and get up to 3x yield for your first 30 days First month APR bonus You get market yield + Bonus. Bonus is paid once in USDT or USDC within 14 days after the 30-day period ends. Available while promo budget lasts. Terms and conditions apply diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayDeclinedReasonMapper.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayDeclinedReasonMapper.kt new file mode 100644 index 0000000000..7ef610c30b --- /dev/null +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayDeclinedReasonMapper.kt @@ -0,0 +1,45 @@ +package com.tangem.features.tangempay.model.transformers + +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.stringReference +import com.tangem.features.tangempay.details.impl.R + +/** + * Maps a raw decline reason coming from the transaction metadata to a localized [TextReference]. + */ +internal object TangemPayDeclinedReasonMapper { + + private val reasonToResId: Map = mapOf( + "account credit limit exceeded" to R.string.tangempay_declined_reason_1, + "automatic fuel dispenser velocity limit reached, more than 2 transactions were attempted within a 3-day " + + "period" to R.string.tangempay_declined_reason_2, + "block transaction from high-risk merchant category codes" to R.string.tangempay_declined_reason_3, + "block transaction from restricted countries [v3-correlation]" to R.string.tangempay_declined_reason_4, + "block transaction from specified high-risk e-commerce merchants" to R.string.tangempay_declined_reason_5, + "block transactions from specified high-risk e-commerce merchants" to R.string.tangempay_declined_reason_5, + "block transactions from specified high ecom merchant" to R.string.tangempay_declined_reason_5, + "block transactions over 150 usd at automated fuel dispensers" to R.string.tangempay_declined_reason_6, + "blocked mcc" to R.string.tangempay_declined_reason_7, + "blocked merchant" to R.string.tangempay_declined_reason_8, + "card locked" to R.string.tangempay_declined_reason_9, + "card spending limit exceeded" to R.string.tangempay_declined_reason_10, + "cvv2 match fail" to R.string.tangempay_declined_reason_11, + "expiry in de14 not matching database stored expiry for this card" to R.string.tangempay_declined_reason_12, + "incorrect pin" to R.string.tangempay_declined_reason_13, + "transaction not permitted to cardholder" to R.string.tangempay_declined_reason_14, + "transaction velocity limit reached, more than 25 transactions were attempted within a 2-day period" to + R.string.tangempay_declined_reason_15, + "triggers if there is a suspected bin attack from a merchant" to R.string.tangempay_declined_reason_16, + "webhook declined" to R.string.tangempay_declined_reason_17, + ) + + fun map(declinedReason: String): TextReference { + val resId = reasonToResId[declinedReason.trim().lowercase()] + return if (resId != null) { + resourceReference(resId) + } else { + stringReference(declinedReason) + } + } +} \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayTxHistoryDetailsConverter.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayTxHistoryDetailsConverter.kt index 16115c40e6..29c444b3cc 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayTxHistoryDetailsConverter.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayTxHistoryDetailsConverter.kt @@ -238,13 +238,15 @@ internal object TangemPayTxHistoryDetailsConverter : is TangemPayTxHistoryItem.Spend -> when (this.status) { TangemPayTxHistoryItem.Status.DECLINED -> TangemPayTxHistoryDetailsUM.NotificationState( config = NotificationConfig( - title = if (declinedReason.isNullOrEmpty()) { - resourceReference(R.string.tangem_pay_transaction_declined_notification_text) - } else { - resourceReference( - id = R.string.tangem_pay_history_item_spend_mc_declined_reason, - formatArgs = wrappedList(requireNotNull(declinedReason)), - ) + title = declinedReason.let { reason -> + if (reason.isNullOrEmpty()) { + resourceReference(R.string.tangem_pay_transaction_declined_notification_text) + } else { + resourceReference( + id = R.string.tangem_pay_history_item_spend_mc_declined_reason, + formatArgs = wrappedList(TangemPayDeclinedReasonMapper.map(reason)), + ) + } }, subtitle = TextReference.EMPTY, iconResId = R.drawable.ic_token_info_24, diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayTxHistoryDetailsConverterV2.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayTxHistoryDetailsConverterV2.kt index 7ce966bf8b..a46ad42459 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayTxHistoryDetailsConverterV2.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayTxHistoryDetailsConverterV2.kt @@ -295,12 +295,13 @@ internal object TangemPayTxHistoryDetailsConverterV2 : } private fun TangemPayTxHistoryItem.Spend.extractDeclinedSubtitle(): TextReference { - return if (declinedReason.isNullOrEmpty()) { + val reason = declinedReason + return if (reason.isNullOrEmpty()) { resourceReference(R.string.tangem_pay_transaction_declined_notification_text) } else { resourceReference( id = R.string.tangem_pay_history_item_spend_mc_declined_reason, - formatArgs = wrappedList(requireNotNull(declinedReason)), + formatArgs = wrappedList(TangemPayDeclinedReasonMapper.map(reason)), ) } }