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)),
)
}
}