From 6a4f779a41ec922d1d9fc65665751b567be865f1 Mon Sep 17 00:00:00 2001 From: mtgriego Date: Mon, 10 Jun 2024 14:36:13 -0700 Subject: [PATCH] add trigger for 3ds flow for post campaign payments (#2054) --- .../ui/activities/ProjectPageActivity.kt | 11 ++-- .../LatePledgeCheckoutViewModel.kt | 50 ++++++++++++++++++- .../activities/compose/LoginToutScreenTest.kt | 1 + 3 files changed, 54 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/kickstarter/ui/activities/ProjectPageActivity.kt b/app/src/main/java/com/kickstarter/ui/activities/ProjectPageActivity.kt index b43c9de042..e665a6a39c 100644 --- a/app/src/main/java/com/kickstarter/ui/activities/ProjectPageActivity.kt +++ b/app/src/main/java/com/kickstarter/ui/activities/ProjectPageActivity.kt @@ -562,12 +562,6 @@ class ProjectPageActivity : val userEmail = latePledgeCheckoutUIState.userEmail val checkoutLoading = latePledgeCheckoutUIState.isLoading - LaunchedEffect(Unit) { - latePledgeCheckoutViewModel.paymentRequiresAction.collect { - stripeNextAction(it) - } - } - latePledgeCheckoutViewModel.provideErrorAction { message -> showToastError(message) } @@ -1219,6 +1213,7 @@ class ProjectPageActivity : binding.pledgeContainerCompose, getString(R.string.general_error_oops) ) + latePledgeCheckoutViewModel.onNewCardFailed() } is PaymentSheetResult.Failed -> { @@ -1228,6 +1223,7 @@ class ProjectPageActivity : binding.pledgeContainerCompose, errorMessage ) + latePledgeCheckoutViewModel.onNewCardFailed() } is PaymentSheetResult.Completed -> { @@ -1279,11 +1275,12 @@ class ProjectPageActivity : object : ApiResultCallback { override fun onSuccess(result: PaymentIntentResult) { if (result.outcome == StripeIntentResult.Outcome.SUCCEEDED) { - // Go to thanks page + latePledgeCheckoutViewModel.completeOnSessionCheckoutFor3DS() } else showToastError() } override fun onError(e: Exception) { + latePledgeCheckoutViewModel.clear3DSValues() showToastError() } } diff --git a/app/src/main/java/com/kickstarter/viewmodels/projectpage/LatePledgeCheckoutViewModel.kt b/app/src/main/java/com/kickstarter/viewmodels/projectpage/LatePledgeCheckoutViewModel.kt index c4ac9e38b7..cacc9cfa81 100644 --- a/app/src/main/java/com/kickstarter/viewmodels/projectpage/LatePledgeCheckoutViewModel.kt +++ b/app/src/main/java/com/kickstarter/viewmodels/projectpage/LatePledgeCheckoutViewModel.kt @@ -57,6 +57,9 @@ class LatePledgeCheckoutViewModel(val environment: Environment) : ViewModel() { private var newStoredCard: StoredCard? = null private var errorAction: (message: String?) -> Unit = {} + private var clientSecretFor3DSVerification: String = "" + private var selectedCardFor3DSVerification: StoredCard? = null + private var selectedReward: Reward? = null private var mutableLatePledgeCheckoutUIState = MutableStateFlow(LatePledgeCheckoutUIState()) @@ -149,6 +152,12 @@ class LatePledgeCheckoutViewModel(val environment: Environment) : ViewModel() { } } + fun onNewCardFailed() { + viewModelScope.launch { + emitCurrentState() + } + } + private suspend fun refreshUserCards() { apolloClient.getStoredCards() .asFlow().onStart { @@ -241,7 +250,12 @@ class LatePledgeCheckoutViewModel(val environment: Environment) : ViewModel() { val withSDK = intentParams.withShouldUseStripeSdk(shouldUseStripeSdk = true) val paymentIntent = stripe.confirmPaymentIntent(withSDK) - if (paymentIntent.lastPaymentError.isNotNull()) { + if (paymentIntent.requiresAction()) { + clientSecretFor3DSVerification = clientSecret + selectedCardFor3DSVerification = selectedCard + mutablePaymentRequiresAction.emit(clientSecret) + emitCurrentState() + } else if (paymentIntent.lastPaymentError.isNotNull()) { // Display error with lastPaymentError.message emitCurrentState() errorAction.invoke(paymentIntent.lastPaymentError?.message) @@ -270,6 +284,40 @@ class LatePledgeCheckoutViewModel(val environment: Environment) : ViewModel() { }.collect() } + fun completeOnSessionCheckoutFor3DS() { + viewModelScope.launch { + if (clientSecretFor3DSVerification.isNotEmpty() && selectedCardFor3DSVerification.isNotNull()) { + apolloClient.completeOnSessionCheckout( + checkoutId = checkoutId ?: "", + paymentIntentClientSecret = clientSecretFor3DSVerification, + paymentSourceId = if (selectedCardFor3DSVerification == newStoredCard) null else selectedCardFor3DSVerification?.id() ?: "", + paymentSourceReusable = true + ).asFlow().map { iDRequiresActionPair -> + if (iDRequiresActionPair.second) { + mutablePaymentRequiresAction.emit(clientSecretFor3DSVerification) + } else { + mutableOnPledgeSuccessAction.emit(true) + } + }.onStart { + emitCurrentState(isLoading = true) + }.onCompletion { + emitCurrentState() + }.catch { + errorAction.invoke(null) + clear3DSValues() + }.collect() + } else { + errorAction.invoke(null) + clear3DSValues() + } + } + } + + fun clear3DSValues() { + clientSecretFor3DSVerification = "" + selectedCardFor3DSVerification = null + } + private fun createCheckoutData(shippingAmount: Double, total: Double, bonusAmount: Double?, checkout: Checkout? = null): CheckoutData { return CheckoutData.builder() .amount(total) diff --git a/app/src/test/java/com/kickstarter/ui/activities/compose/LoginToutScreenTest.kt b/app/src/test/java/com/kickstarter/ui/activities/compose/LoginToutScreenTest.kt index f3f44fd15f..ec80c547a0 100644 --- a/app/src/test/java/com/kickstarter/ui/activities/compose/LoginToutScreenTest.kt +++ b/app/src/test/java/com/kickstarter/ui/activities/compose/LoginToutScreenTest.kt @@ -89,6 +89,7 @@ class LoginToutScreenTest : KSRobolectricTestCase() { touPpCookieDisclaimer.assertIsDisplayed() } + @Test fun testComponentsVisible_featureFlag_On() { composeTestRule.setContent { KSTheme {