diff --git a/app/src/androidTest/kotlin/com/tangem/screens/DetailsPageObject.kt b/app/src/androidTest/kotlin/com/tangem/screens/DetailsPageObject.kt
index 62b73d6c4b..863e387a71 100644
--- a/app/src/androidTest/kotlin/com/tangem/screens/DetailsPageObject.kt
+++ b/app/src/androidTest/kotlin/com/tangem/screens/DetailsPageObject.kt
@@ -44,7 +44,7 @@ class DetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
}
val contactSupportButton: KNode = child {
hasTestTag(DetailsScreenTestTags.SCREEN_ITEM)
- hasText(getResourceString(R.string.details_row_title_contact_to_support))
+ hasText(getResourceString(R.string.common_contact_support))
}
val toSButton: KNode = child {
hasTestTag(DetailsScreenTestTags.SCREEN_ITEM)
diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml
index deea678229..7f0604d2d7 100644
--- a/core/res/src/main/res/values/strings.xml
+++ b/core/res/src/main/res/values/strings.xml
@@ -244,6 +244,7 @@
Coming soon
Confirm
Connecting
+ Contact support
Contact Tangem Support
Contact Visa Support
Continue
@@ -1382,6 +1383,8 @@
You receive
Choose token
not available
+ We would be happy to receive your feedback
+ Tangem Pay is now in beta
Card frozen
Card payment
Deposit
diff --git a/core/ui/src/main/res/drawable/img_visa_label_26_16.xml b/core/ui/src/main/res/drawable/img_visa_label_26_16.xml
deleted file mode 100644
index c5859a2fda..0000000000
--- a/core/ui/src/main/res/drawable/img_visa_label_26_16.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
diff --git a/core/ui/src/main/res/drawable/img_visa_notification.webp b/core/ui/src/main/res/drawable/img_visa_notification.webp
new file mode 100644
index 0000000000..b0b4afb8b6
Binary files /dev/null and b/core/ui/src/main/res/drawable/img_visa_notification.webp differ
diff --git a/domain/feedback/models/src/main/kotlin/com/tangem/domain/feedback/models/FeedbackEmailType.kt b/domain/feedback/models/src/main/kotlin/com/tangem/domain/feedback/models/FeedbackEmailType.kt
index 5786ee9dac..78848710c5 100644
--- a/domain/feedback/models/src/main/kotlin/com/tangem/domain/feedback/models/FeedbackEmailType.kt
+++ b/domain/feedback/models/src/main/kotlin/com/tangem/domain/feedback/models/FeedbackEmailType.kt
@@ -78,5 +78,7 @@ sealed interface FeedbackEmailType {
val providerName: String,
val txId: String,
) : Visa()
+
+ data class FeatureIsBeta(override val walletMetaInfo: WalletMetaInfo) : Visa()
}
}
\ No newline at end of file
diff --git a/domain/feedback/src/main/java/com/tangem/domain/feedback/FeedbackDataBuilder.kt b/domain/feedback/src/main/java/com/tangem/domain/feedback/FeedbackDataBuilder.kt
index fac64d171a..9a3a7de9b6 100644
--- a/domain/feedback/src/main/java/com/tangem/domain/feedback/FeedbackDataBuilder.kt
+++ b/domain/feedback/src/main/java/com/tangem/domain/feedback/FeedbackDataBuilder.kt
@@ -49,6 +49,10 @@ internal class FeedbackDataBuilder {
builder.appendKeyValue("Total saved wallets", userWalletsInfo.totalUserWallets.toString())
}
+ fun addUserWalletId(userWalletId: String) {
+ builder.appendKeyValue("User Wallet ID", userWalletId)
+ }
+
fun addUserWalletMetaInfo(walletMetaInfo: WalletMetaInfo) {
builder.appendKeyValue("Mobile Wallet is backed up", walletMetaInfo.hotWalletIsBackedUp?.toString())
builder.appendKeyValue("Card ID", walletMetaInfo.cardId)
diff --git a/domain/feedback/src/main/java/com/tangem/domain/feedback/SendFeedbackEmailUseCase.kt b/domain/feedback/src/main/java/com/tangem/domain/feedback/SendFeedbackEmailUseCase.kt
index 04e4d5db8f..adc8353252 100644
--- a/domain/feedback/src/main/java/com/tangem/domain/feedback/SendFeedbackEmailUseCase.kt
+++ b/domain/feedback/src/main/java/com/tangem/domain/feedback/SendFeedbackEmailUseCase.kt
@@ -65,6 +65,7 @@ class SendFeedbackEmailUseCase(
is FeedbackEmailType.CardAttestationFailed,
is FeedbackEmailType.Visa.Dispute,
is FeedbackEmailType.Visa.DisputeV2,
+ is FeedbackEmailType.Visa.FeatureIsBeta,
-> this
is FeedbackEmailType.DirectUserRequest,
is FeedbackEmailType.RateCanBeBetter,
diff --git a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageBodyResolver.kt b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageBodyResolver.kt
index 12bd80d66a..c8a13a4ef7 100644
--- a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageBodyResolver.kt
+++ b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageBodyResolver.kt
@@ -38,6 +38,7 @@ internal class EmailMessageBodyResolver(
is FeedbackEmailType.Visa.Dispute -> addVisaRequestBody(type.walletMetaInfo, type.visaTxDetails)
is FeedbackEmailType.Visa.DisputeV2 -> addTangemPayRequestBody(type.walletMetaInfo, type.item)
is FeedbackEmailType.Visa.Withdrawal -> addTangemPayWithdrawalRequestBody(type)
+ is FeedbackEmailType.Visa.FeatureIsBeta -> addTangemPayBetaRequestBody(type.walletMetaInfo)
}
return build()
@@ -52,6 +53,15 @@ internal class EmailMessageBodyResolver(
addTangemPayTxInfo(item)
}
+ private fun FeedbackDataBuilder.addTangemPayBetaRequestBody(walletMetaInfo: WalletMetaInfo) {
+ addPhoneInfoBody()
+ addDelimiter()
+ walletMetaInfo.userWalletId?.let { userWalletId ->
+ addUserWalletId(userWalletId = userWalletId.stringValue)
+ addDelimiter()
+ }
+ }
+
private suspend fun FeedbackDataBuilder.addTangemPayWithdrawalRequestBody(
type: FeedbackEmailType.Visa.Withdrawal,
) {
diff --git a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageTitleResolver.kt b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageTitleResolver.kt
index 7d42928a99..36940c948e 100644
--- a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageTitleResolver.kt
+++ b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageTitleResolver.kt
@@ -26,6 +26,8 @@ internal class EmailMessageTitleResolver(private val resources: Resources) {
is FeedbackEmailType.Visa.DisputeV2,
is FeedbackEmailType.Visa.FailedIssueCard,
is FeedbackEmailType.Visa.Withdrawal,
+ is FeedbackEmailType.Visa.FeatureIsBeta,
+ is FeedbackEmailType.PreActivatedWallet,
-> R.string.feedback_preface_support
is FeedbackEmailType.RateCanBeBetter -> R.string.feedback_preface_rate_negative
is FeedbackEmailType.ScanningProblem -> R.string.feedback_preface_scan_failed
@@ -33,7 +35,6 @@ internal class EmailMessageTitleResolver(private val resources: Resources) {
is FeedbackEmailType.StakingProblem,
is FeedbackEmailType.SwapProblem,
-> R.string.feedback_preface_tx_failed
- is FeedbackEmailType.PreActivatedWallet -> R.string.feedback_preface_support
}
return resources.getStringSafe(resId)
diff --git a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailSubjectResolver.kt b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailSubjectResolver.kt
index 6e01c9989f..4b1e4f9799 100644
--- a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailSubjectResolver.kt
+++ b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailSubjectResolver.kt
@@ -15,6 +15,7 @@ import com.tangem.domain.feedback.models.FeedbackEmailType
internal class EmailSubjectResolver(private val resources: Resources) {
/** Resolve email message body by [type] */
+ @Suppress("CyclomaticComplexMethod")
fun resolve(type: FeedbackEmailType): String {
return when (type) {
is FeedbackEmailType.DirectUserRequest -> {
@@ -43,8 +44,8 @@ internal class EmailSubjectResolver(private val resources: Resources) {
is FeedbackEmailType.Visa.Dispute,
is FeedbackEmailType.Visa.DisputeV2,
-> "[Visa] [DISPUTE] {auto-filled subject}"
- is FeedbackEmailType.Visa.Withdrawal,
- -> "[Visa] [WITHDRAWAL] {auto-filled subject}"
+ is FeedbackEmailType.Visa.Withdrawal -> "[Visa] [WITHDRAWAL] {auto-filled subject}"
+ is FeedbackEmailType.Visa.FeatureIsBeta -> "[VISA] [FEEDBACK]"
}
}
}
\ No newline at end of file
diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt
index ebabf476c2..617de52a47 100644
--- a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt
+++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt
@@ -87,7 +87,7 @@ internal class ItemsBuilder @Inject constructor(private val router: Router) {
DetailsItemUM.Basic.Item(
id = "support_email",
block = BlockUM(
- text = resourceReference(R.string.details_row_title_contact_to_support),
+ text = resourceReference(R.string.common_contact_support),
iconRes = R.drawable.ic_comment_24,
onClick = onSupportEmailClick,
),
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsStateFactory.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsStateFactory.kt
index 0036f7c5ba..9853165dad 100644
--- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsStateFactory.kt
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsStateFactory.kt
@@ -1,8 +1,10 @@
package com.tangem.features.tangempay.entity
+import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
import com.tangem.core.ui.components.dropdownmenu.TangemDropdownMenuItem
+import com.tangem.core.ui.components.notifications.NotificationConfig
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.themedColor
import com.tangem.core.ui.res.TangemTheme
@@ -21,6 +23,7 @@ internal class TangemPayDetailsStateFactory(
private val converter: TangemPayCardFrozenStateConverter,
) {
+ @Suppress("LongMethod")
fun getInitialState(): TangemPayDetailsUM {
val cardFrozenStateItem = when (cardFrozenState) {
is TangemPayCardFrozenState.Pending -> null
@@ -88,6 +91,16 @@ internal class TangemPayDetailsStateFactory(
isBalanceHidden = false,
addFundsEnabled = true,
cardFrozenState = converter.convert(cardFrozenState),
+ betaNotificationConfig = NotificationConfig(
+ title = resourceReference(R.string.tangem_pay_beta_notification_title),
+ subtitle = resourceReference(R.string.tangem_pay_beta_notification_subtitle),
+ iconResId = R.drawable.img_visa_notification,
+ buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
+ text = resourceReference(R.string.common_contact_support),
+ onClick = intents::onContactSupportClicked,
+ ),
+ iconSize = 36.dp,
+ ),
)
}
}
\ No newline at end of file
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsUM.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsUM.kt
index 6faa4a89ea..a8b31086f1 100644
--- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsUM.kt
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsUM.kt
@@ -2,6 +2,7 @@ package com.tangem.features.tangempay.entity
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
+import com.tangem.core.ui.components.notifications.NotificationConfig
import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.visa.model.TangemPayCardFrozenState
import kotlinx.collections.immutable.ImmutableList
@@ -14,6 +15,7 @@ internal data class TangemPayDetailsUM(
val isBalanceHidden: Boolean,
val addFundsEnabled: Boolean,
val cardFrozenState: CardFrozenState,
+ val betaNotificationConfig: NotificationConfig,
)
internal data class TangemPayCardDetailsUM(
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt
index 3a08e43adf..78c4c843c6 100644
--- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt
@@ -17,10 +17,13 @@ import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfi
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.message.SnackbarMessage
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
+import com.tangem.domain.feedback.SendFeedbackEmailUseCase
+import com.tangem.domain.feedback.models.FeedbackEmailType
+import com.tangem.domain.feedback.models.WalletMetaInfo
import com.tangem.domain.models.TokenReceiveConfig
import com.tangem.domain.pay.TangemPayCryptoCurrencyFactory
-import com.tangem.domain.pay.model.TangemPayTopUpData
import com.tangem.domain.pay.model.TangemPayCardBalance
+import com.tangem.domain.pay.model.TangemPayTopUpData
import com.tangem.domain.pay.repository.CustomerOrderRepository
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
import com.tangem.domain.tangempay.TangemPayAnalyticsEvents
@@ -73,6 +76,7 @@ internal class TangemPayDetailsModel @Inject constructor(
private val tangemPayCryptoCurrencyFactory: TangemPayCryptoCurrencyFactory,
private val orderRepository: CustomerOrderRepository,
private val getUserWalletUseCase: GetUserWalletUseCase,
+ private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
) : Model(), TangemPayTxHistoryUiActions, TangemPayDetailIntents, AddFundsListener {
private val params: TangemPayDetailsContainerComponent.Params = paramsContainer.require()
@@ -306,6 +310,16 @@ internal class TangemPayDetailsModel @Inject constructor(
}.saveIn(addToWalletBannerJobHolder)
}
+ override fun onContactSupportClicked() {
+ modelScope.launch {
+ sendFeedbackEmailUseCase.invoke(
+ type = FeedbackEmailType.Visa.FeatureIsBeta(
+ walletMetaInfo = WalletMetaInfo(userWalletId = params.userWalletId),
+ ),
+ )
+ }
+ }
+
override fun onRefreshSwipe(refreshState: ShowRefreshState) {
modelScope.launch {
uiState.update(TangemPayDetailsRefreshTransformer(isRefreshing = refreshState.value))
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayDetailsScreen.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayDetailsScreen.kt
index 6c0a7fdf77..6addbcf3d6 100644
--- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayDetailsScreen.kt
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayDetailsScreen.kt
@@ -31,11 +31,10 @@ import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfi
import com.tangem.core.ui.components.containers.pullToRefresh.TangemPullToRefreshContainer
import com.tangem.core.ui.components.dropdownmenu.TangemDropdownItem
import com.tangem.core.ui.components.dropdownmenu.TangemDropdownMenu
+import com.tangem.core.ui.components.notifications.Notification
+import com.tangem.core.ui.components.notifications.NotificationConfig
import com.tangem.core.ui.components.text.applyBladeBrush
-import com.tangem.core.ui.extensions.TextReference
-import com.tangem.core.ui.extensions.orMaskWithStars
-import com.tangem.core.ui.extensions.resourceReference
-import com.tangem.core.ui.extensions.stringResourceSafe
+import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.test.TokenDetailsTopBarTestTags
@@ -81,7 +80,9 @@ internal fun TangemPayDetailsScreen(
) {
item(TangemPayCardDetailsUM::class.java) {
cardDetailsBlockComponent.CardDetailsBlockContent(
- modifier = Modifier.padding(horizontal = 16.dp).padding(top = 8.dp),
+ modifier = Modifier
+ .padding(horizontal = 16.dp)
+ .padding(top = 8.dp),
state = cardDetailsState,
)
}
@@ -116,7 +117,7 @@ internal fun TangemPayDetailsScreen(
key = TangemPayDetailsBalanceBlockState::class.java,
content = {
TangemPayDetailsBalanceBlock(
- modifier = modifier
+ modifier = Modifier
.padding(horizontal = TangemTheme.dimens.spacing16)
.padding(top = 12.dp)
.fillMaxWidth(),
@@ -125,15 +126,32 @@ internal fun TangemPayDetailsScreen(
)
},
)
+ item(
+ key = "TANGEM_PAY_IS_IN_BETA",
+ content = {
+ TangemPayBetaBlock(
+ modifier = modifier
+ .padding(horizontal = TangemTheme.dimens.spacing16)
+ .padding(top = 12.dp)
+ .fillMaxWidth(),
+ config = state.betaNotificationConfig,
+ )
+ },
+ )
with(txHistoryComponent) { txHistoryContent(listState = listState, state = txHistoryState) }
}
}
}
}
+@Composable
+private fun TangemPayBetaBlock(config: NotificationConfig, modifier: Modifier = Modifier) {
+ Notification(modifier = modifier, config = config)
+}
+
// region Balance block
@Composable
-internal fun TangemPayDetailsBalanceBlock(
+private fun TangemPayDetailsBalanceBlock(
state: TangemPayDetailsBalanceBlockState,
isBalanceHidden: Boolean,
modifier: Modifier = Modifier,
@@ -335,6 +353,16 @@ private class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider