Updated on 2026-08-14

This commit is contained in:
Tangem 2025-11-14 18:54:33 +05:00
parent 4c25513253
commit 5e854cd424
9 changed files with 55 additions and 27 deletions

View file

@ -31,7 +31,7 @@ internal class TangemPay(
private fun createDevEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig(
environment = ApiEnvironment.DEV,
baseUrl = "[REDACTED_ENV_URL]",
baseUrl = "https://api.dev.us.paera.com/bff/",
headers = createHeaders(),
)

View file

@ -241,7 +241,7 @@ internal class ProdApiConfigsManagerTest {
id = ApiConfig.ID.TangemPay,
expected = ApiEnvironmentConfig(
environment = ApiEnvironment.DEV,
baseUrl = "[REDACTED_ENV_URL]",
baseUrl = "https://api.dev.us.paera.com/bff/",
headers = mapOf(
"version" to ProviderSuspend { VERSION_NAME },
"platform" to ProviderSuspend { "Android" },

View file

@ -1380,6 +1380,7 @@
<string name="tangem_pay_status_declined">Declined</string>
<string name="tangem_pay_status_pending">Pending</string>
<string name="tangem_pay_terms_fees_limits">Terms, Fees &amp; Limits</string>
<string name="tangem_pay_terms_limits">Terms and Limits</string>
<string name="tangem_pay_transaction_declined_notification_text">The bank rejected this transaction request.</string>
<string name="tangem_pay_transaction_fee_notification_text">This fee goes to cover the cost of handling your transfer.</string>
<string name="tangem_pay_unfreeze_card_alert_body">Keep using your money. You can freeze anytime.</string>
@ -1433,7 +1434,7 @@
<string name="tangempay_onboarding_purchases_title">Pay exactly what you see</string>
<string name="tangempay_onboarding_security_description">A separate payment account will be created without disclosing your addresses and assets</string>
<string name="tangempay_onboarding_security_title">Unrivaled privacy</string>
<string name="tangempay_onboarding_title">Get your free Crypto Card\nin minutes</string>
<string name="tangempay_onboarding_title">Get your free Tangem Pay Card in minutes</string>
<string name="tangempay_service_unavailable_description">Were fixing a technical issue. Please try again later.</string>
<string name="tangempay_service_unavailable_title">Service temporarily unavailable</string>
<string name="tangempay_title">Tangem Pay</string>

View file

@ -0,0 +1,5 @@
package com.tangem.features.tangempay
object TangemPayConstants {
const val TERMS_AND_LIMITS_LINK = "https://tangem.com/docs/en/tangem-visa-tariffs.pdf"
}

View file

@ -2,23 +2,19 @@ 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.containers.pullToRefresh.PullToRefreshConfig.ShowRefreshState
import com.tangem.core.ui.components.dropdownmenu.TangemDropdownMenuItem
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.themedColor
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.tangempay.details.impl.R
import com.tangem.features.tangempay.utils.TangemPayDetailIntents
import kotlinx.collections.immutable.persistentListOf
@Suppress("LongParameterList")
internal class TangemPayDetailsStateFactory(
private val onBack: () -> Unit,
private val onRefresh: (ShowRefreshState) -> Unit,
private val onAddFunds: () -> Unit,
private val onClickChangePin: () -> Unit,
private val intents: TangemPayDetailIntents,
private val isCardFrozen: Boolean,
private val onClickFreezeCard: () -> Unit,
private val onClickUnfreezeCard: () -> Unit,
) {
fun getInitialState(): TangemPayDetailsUM {
@ -28,7 +24,7 @@ internal class TangemPayDetailsStateFactory(
dropdownItem = TangemDropdownMenuItem(
title = resourceReference(R.string.tangempay_card_details_unfreeze_card),
textColor = themedColor { TangemTheme.colors.text.primary1 },
onClick = onClickUnfreezeCard,
onClick = intents::onClickUnfreezeCard,
),
)
} else {
@ -37,7 +33,7 @@ internal class TangemPayDetailsStateFactory(
dropdownItem = TangemDropdownMenuItem(
title = resourceReference(R.string.tangempay_card_details_freeze_card),
textColor = themedColor { TangemTheme.colors.text.primary1 },
onClick = onClickFreezeCard,
onClick = intents::onClickFreezeCard,
),
)
}
@ -51,7 +47,15 @@ internal class TangemPayDetailsStateFactory(
dropdownItem = TangemDropdownMenuItem(
title = resourceReference(R.string.tangempay_card_details_change_pin),
textColor = themedColor { TangemTheme.colors.text.primary1 },
onClick = onClickChangePin,
onClick = intents::onClickChangePin,
),
),
TangemPayDetailsTopBarMenuItem(
type = TangemPayDetailsTopBarMenuItemType.TermsAndLimits,
dropdownItem = TangemDropdownMenuItem(
title = resourceReference(R.string.tangem_pay_terms_limits),
textColor = themedColor { TangemTheme.colors.text.primary1 },
onClick = intents::onClickTermsAndLimits,
),
),
cardFrozenStateItem,
@ -59,18 +63,18 @@ internal class TangemPayDetailsStateFactory(
),
pullToRefreshConfig = PullToRefreshConfig(
isRefreshing = false,
onRefresh = onRefresh,
onRefresh = intents::onRefreshSwipe,
),
balanceBlockState = TangemPayDetailsBalanceBlockState.Loading(
actionButtons = persistentListOf(
ActionButtonConfig(
text = resourceReference(id = R.string.tangempay_card_details_add_funds),
iconResId = R.drawable.ic_arrow_down_24,
onClick = onAddFunds,
onClick = intents::onClickAddFunds,
),
),
frozenState = if (isCardFrozen) {
CardFrozenState.Frozen(onClickUnfreezeCard)
CardFrozenState.Frozen(intents::onClickUnfreezeCard)
} else {
CardFrozenState.Unfrozen
},

View file

@ -15,6 +15,7 @@ internal data class TangemPayDetailsTopBarMenuItem(
internal enum class TangemPayDetailsTopBarMenuItemType {
ChangePin,
TermsAndLimits,
FreezeCard,
UnfreezeCard,
}

View file

@ -11,6 +11,7 @@ import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.decompose.navigation.Router
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig.ShowRefreshState
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.message.SnackbarMessage
@ -19,6 +20,7 @@ import com.tangem.domain.pay.TangemPayTopUpData
import com.tangem.domain.pay.model.TangemPayCardBalance
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
import com.tangem.domain.visa.model.TangemPayTxHistoryItem
import com.tangem.features.tangempay.TangemPayConstants
import com.tangem.features.tangempay.components.AddFundsListener
import com.tangem.features.tangempay.components.TangemPayDetailsContainerComponent
import com.tangem.features.tangempay.details.impl.R
@ -30,6 +32,7 @@ import com.tangem.features.tangempay.model.listener.CardDetailsEvent
import com.tangem.features.tangempay.model.listener.CardDetailsEventListener
import com.tangem.features.tangempay.model.transformers.*
import com.tangem.features.tangempay.navigation.TangemPayDetailsInnerRoute
import com.tangem.features.tangempay.utils.TangemPayDetailIntents
import com.tangem.features.tangempay.utils.TangemPayMessagesFactory
import com.tangem.features.tangempay.utils.TangemPayTxHistoryUiActions
import com.tangem.features.tangempay.utils.TangemPayTxHistoryUpdateListener
@ -50,22 +53,19 @@ internal class TangemPayDetailsModel @Inject constructor(
paramsContainer: ParamsContainer,
override val dispatchers: CoroutineDispatcherProvider,
private val router: Router,
private val urlOpener: UrlOpener,
private val cardDetailsRepository: TangemPayCardDetailsRepository,
private val uiMessageSender: UiMessageSender,
private val cardDetailsEventListener: CardDetailsEventListener,
private val txHistoryUpdateListener: TangemPayTxHistoryUpdateListener,
) : Model(), TangemPayTxHistoryUiActions, AddFundsListener {
) : Model(), TangemPayTxHistoryUiActions, TangemPayDetailIntents, AddFundsListener {
private val params: TangemPayDetailsContainerComponent.Params = paramsContainer.require()
private val stateFactory = TangemPayDetailsStateFactory(
onBack = router::pop,
onRefresh = ::onRefreshSwipe,
onAddFunds = ::onClickAddFunds,
onClickChangePin = ::onClickChangePin,
intents = this,
isCardFrozen = params.config.isCardFrozen,
onClickFreezeCard = ::onClickFreezeCard,
onClickUnfreezeCard = ::onClickUnfreezeCard,
)
val uiState: StateFlow<TangemPayDetailsUM>
@ -84,15 +84,15 @@ internal class TangemPayDetailsModel @Inject constructor(
fetchBalance()
}
private fun onClickChangePin() {
override fun onClickChangePin() {
router.push(TangemPayDetailsInnerRoute.ChangePIN)
}
private fun onClickFreezeCard() {
override fun onClickFreezeCard() {
uiMessageSender.send(TangemPayMessagesFactory.createFreezeCardMessage(onFreezeClicked = ::freezeCard))
}
private fun onClickUnfreezeCard() {
override fun onClickUnfreezeCard() {
uiMessageSender.send(TangemPayMessagesFactory.createUnfreezeCardMessage(onUnfreezeClicked = ::unfreezeCard))
}
@ -150,7 +150,7 @@ internal class TangemPayDetailsModel @Inject constructor(
}
}
private fun onClickAddFunds() {
override fun onClickAddFunds() {
if (params.config.depositAddress == null || balance == null) {
showBottomSheetError(TangemPayDetailsErrorType.Receive)
} else {
@ -187,7 +187,7 @@ internal class TangemPayDetailsModel @Inject constructor(
}.saveIn(addToWalletBannerJobHolder)
}
private fun onRefreshSwipe(refreshState: ShowRefreshState) {
override fun onRefreshSwipe(refreshState: ShowRefreshState) {
modelScope.launch {
uiState.update(TangemPayDetailsRefreshTransformer(isRefreshing = refreshState.value))
cardDetailsEventListener.send(CardDetailsEvent.Hide)
@ -251,6 +251,10 @@ internal class TangemPayDetailsModel @Inject constructor(
bottomSheetNavigation.activate(TangemPayDetailsNavigation.TransactionDetails(item))
}
override fun onClickTermsAndLimits() {
urlOpener.openUrl(TangemPayConstants.TERMS_AND_LIMITS_LINK)
}
private fun showBottomSheetError(type: TangemPayDetailsErrorType) {
uiMessageSender.send(message = TangemPayMessagesFactory.createErrorMessage(type = type))
}

View file

@ -0,0 +1,12 @@
package com.tangem.features.tangempay.utils
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig.ShowRefreshState
internal interface TangemPayDetailIntents {
fun onRefreshSwipe(refreshState: ShowRefreshState)
fun onClickAddFunds()
fun onClickChangePin()
fun onClickFreezeCard()
fun onClickUnfreezeCard()
fun onClickTermsAndLimits()
}

View file

@ -6,6 +6,7 @@ import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.decompose.navigation.Router
import com.tangem.features.tangempay.TangemPayConstants
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.domain.pay.repository.OnboardingRepository
import com.tangem.domain.pay.usecase.ProduceTangemPayInitialDataUseCase
@ -81,7 +82,7 @@ internal class TangemPayOnboardingModel @Inject constructor(
}
private fun onTermsClick() {
urlOpener.openUrl("https://tangem.com/docs/en/tangem-visa-tariffs.pdf")
urlOpener.openUrl(TangemPayConstants.TERMS_AND_LIMITS_LINK)
}
private fun onGetCardClick() {