Updated on 2026-08-14

This commit is contained in:
Tangem 2026-07-17 13:35:59 +05:00
parent 7afc6735c1
commit c1e1458f3f
17 changed files with 193 additions and 24 deletions

View file

@ -114,6 +114,7 @@ internal class TangemPayCardPageScreenComponent(
paymentAccountAddress = navigation.paymentAccountAddress,
onDismiss = model.bottomSheetNavigation::dismiss,
onShowDetails = model::onShowVirtualAccountRequisites,
onShowBankingDetailsError = model::showVaBankingDetailsError,
onOrderCreated = model::onVirtualAccountOrderCreated,
),
)

View file

@ -143,6 +143,7 @@ internal class TangemPayDetailsComponent(
paymentAccountAddress = navigation.paymentAccountAddress,
onDismiss = model.bottomSheetNavigation::dismiss,
onShowDetails = model::onShowVirtualAccountRequisites,
onShowBankingDetailsError = model::showVaBankingDetailsError,
onOrderCreated = model::onVirtualAccountOrderCreated,
),
)

View file

@ -38,6 +38,7 @@ internal class TangemPayVirtualAccountDepositComponent(
val paymentAccountAddress: String,
val onDismiss: () -> Unit,
val onShowDetails: (VirtualAccountOnramp.Available) -> Unit,
val onShowBankingDetailsError: () -> Unit,
val onOrderCreated: () -> Unit,
)
}

View file

@ -71,7 +71,7 @@ import kotlinx.coroutines.launch
import javax.inject.Inject
import com.tangem.core.ui.R as CoreUiR
@Suppress("LongParameterList", "LargeClass")
@Suppress("LongParameterList", "LargeClass", "TooManyFunctions")
@Stable
@ModelScoped
internal class TangemPayCardPageModel @Inject constructor(
@ -495,10 +495,12 @@ internal class TangemPayCardPageModel @Inject constructor(
val loaded = currentStatus.value.ifLoadedOrNull { it } ?: return
when (val onramp = loaded.virtualAccount) {
null -> return
is VirtualAccountOnramp.BankCredentialsError -> showVaBankingDetailsError()
VirtualAccountOnramp.Processing -> showVaPreparing()
// BankCredentialsError opens the deposit intro first; the retryable error sheet is shown from
// its "Show details" action (see onShowDetailsClick).
is VirtualAccountOnramp.Available,
VirtualAccountOnramp.Eligible,
is VirtualAccountOnramp.BankCredentialsError,
-> openVirtualAccountDeposit(onramp, loaded)
}
}
@ -515,7 +517,7 @@ internal class TangemPayCardPageModel @Inject constructor(
)
}
private fun showVaBankingDetailsError() {
fun showVaBankingDetailsError() {
bottomSheetNavigation.dismiss()
bottomSheetNavigation.activate(
TangemPayCardNavigation.VaBankingDetailsError(userWalletId = userWalletId),

View file

@ -315,10 +315,12 @@ internal class TangemPayDetailsModel @Inject constructor(
val loaded = currentStatus.value.ifLoadedOrNull { it } ?: return
when (val onramp = loaded.virtualAccount) {
null -> return
is VirtualAccountOnramp.BankCredentialsError -> showVaBankingDetailsError()
VirtualAccountOnramp.Processing -> showVaPreparing()
// BankCredentialsError opens the deposit intro first; the retryable error sheet is shown from
// its "Show details" action (see onShowDetailsClick).
is VirtualAccountOnramp.Available,
VirtualAccountOnramp.Eligible,
is VirtualAccountOnramp.BankCredentialsError,
-> openVirtualAccountDeposit(onramp, loaded)
}
}
@ -335,7 +337,7 @@ internal class TangemPayDetailsModel @Inject constructor(
)
}
private fun showVaBankingDetailsError() {
fun showVaBankingDetailsError() {
bottomSheetNavigation.dismiss()
bottomSheetNavigation.activate(
TangemPayDetailsNavigation.VaBankingDetailsError(userWalletId = userWalletId),

View file

@ -81,11 +81,9 @@ internal class TangemPayVirtualAccountDepositModel @Inject constructor(
analytics.send(TangemPayAnalyticsEvents.VaShowDetailsFirstTimeClicked())
createVirtualAccountOrder()
}
// Processing/Error onramps never reach this sheet (a message/error sheet is shown instead);
// these branches only keep the `when` exhaustive.
VirtualAccountOnramp.Processing,
VirtualAccountOnramp.BankCredentialsError,
-> onDismiss()
VirtualAccountOnramp.BankCredentialsError -> params.onShowBankingDetailsError()
// Processing never reaches this sheet (the Preparing message is shown instead); defensive.
VirtualAccountOnramp.Processing -> onDismiss()
}
}

View file

@ -40,12 +40,20 @@ internal class TangemPayVirtualAccountDepositModelTest {
private val uiMessageSender: UiMessageSender = mockk(relaxed = true)
private val createVirtualAccountOrderUseCase: CreateVirtualAccountOrderUseCase = mockk()
private val onShowDetails: (VirtualAccountOnramp.Available) -> Unit = mockk(relaxed = true)
private val onShowBankingDetailsError: () -> Unit = mockk(relaxed = true)
private val onOrderCreated: () -> Unit = mockk(relaxed = true)
private val analytics: AnalyticsEventHandler = mockk(relaxed = true)
@BeforeEach
fun resetMocks() {
clearMocks(createVirtualAccountOrderUseCase, onShowDetails, onOrderCreated, uiMessageSender, analytics)
clearMocks(
createVirtualAccountOrderUseCase,
onShowDetails,
onShowBankingDetailsError,
onOrderCreated,
uiMessageSender,
analytics,
)
}
@Test
@ -65,6 +73,21 @@ internal class TangemPayVirtualAccountDepositModelTest {
verify(exactly = 1) { analytics.send(ofType<TangemPayAnalyticsEvents.VaShowDetailsClicked>()) }
}
@Test
fun `GIVEN bank credentials error WHEN show details THEN shows banking details error sheet`() = runTest {
// Arrange
val model = createModel(VirtualAccountOnramp.BankCredentialsError)
// Act
model.uiState.value.onShowDetailsClick()
advanceUntilIdle()
// Assert
verify(exactly = 1) { onShowBankingDetailsError() }
verify(exactly = 0) { onShowDetails(any()) }
coVerify(exactly = 0) { createVirtualAccountOrderUseCase(any(), any()) }
}
@Test
fun `GIVEN eligible and create succeeds WHEN show details THEN order created and loading reset`() = runTest {
// Arrange
@ -130,6 +153,7 @@ internal class TangemPayVirtualAccountDepositModelTest {
paymentAccountAddress = paymentAccountAddress,
onDismiss = {},
onShowDetails = onShowDetails,
onShowBankingDetailsError = onShowBankingDetailsError,
onOrderCreated = onOrderCreated,
),
),