diff --git a/android/navi-payment/src/main/java/com/navi/payment/nativepayment/components/PaymentCheckoutFooter.kt b/android/navi-payment/src/main/java/com/navi/payment/nativepayment/components/PaymentCheckoutFooter.kt index 880101c380..b45f2baf56 100644 --- a/android/navi-payment/src/main/java/com/navi/payment/nativepayment/components/PaymentCheckoutFooter.kt +++ b/android/navi-payment/src/main/java/com/navi/payment/nativepayment/components/PaymentCheckoutFooter.kt @@ -7,9 +7,12 @@ package com.navi.payment.nativepayment.components +import android.content.Intent import androidx.activity.ComponentActivity import androidx.activity.compose.BackHandler +import androidx.activity.compose.ManagedActivityResultLauncher import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.ActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedContentTransitionScope @@ -89,10 +92,13 @@ import com.navi.payment.nativepayment.model.OneClickBottomSheetUiState import com.navi.payment.nativepayment.model.PaymentsMainCtaState import com.navi.payment.nativepayment.model.RewardsInfoV2 import com.navi.payment.nativepayment.presentation.reducer.OneClickCheckoutState +import com.navi.payment.nativepayment.presentation.reducer.OneClickScreenEffect import com.navi.payment.nativepayment.presentation.reducer.OneClickScreenEvent import com.navi.payment.nativepayment.screens.RedirectingBottomSheetContent import com.navi.payment.nativepayment.sharedviewmodel.NaviCheckoutViewModelV2 import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @@ -163,6 +169,24 @@ fun PaymentCheckoutFooter( ) } + val upiResultLauncher = + rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result + -> + naviCheckoutViewModel.onEvent( + OneClickScreenEvent.OnNaviUpiResultReceived( + result = result, + generateToken = generateToken, + ) + ) + } + + EffectsHandler( + activity = activity, + oneCliCkCheckoutScreenEffect = naviCheckoutViewModel.effect, + oneClickCheckoutViewModelV2 = naviCheckoutViewModel, + upiResultLauncher = upiResultLauncher, + ) + Column( modifier = modifier @@ -512,3 +536,25 @@ fun OneClickBankAccountItem( } } } + +@Composable +fun EffectsHandler( + oneCliCkCheckoutScreenEffect: SharedFlow, + oneClickCheckoutViewModelV2: NaviCheckoutViewModelV2, + activity: ComponentActivity, + upiResultLauncher: ManagedActivityResultLauncher, +) { + LaunchedEffect(Unit) { + oneCliCkCheckoutScreenEffect.collectLatest { effect -> + when (effect) { + is OneClickScreenEffect.StartNaviUpiMPinSetAction -> { + oneClickCheckoutViewModelV2.startAction( + activity = activity, + upiResultLauncher = upiResultLauncher, + data = effect.payload, + ) + } + } + } + } +} diff --git a/android/navi-payment/src/main/java/com/navi/payment/nativepayment/presentation/reducer/OneClickScreenContract.kt b/android/navi-payment/src/main/java/com/navi/payment/nativepayment/presentation/reducer/OneClickScreenContract.kt index b8e46c3484..65c93715d7 100644 --- a/android/navi-payment/src/main/java/com/navi/payment/nativepayment/presentation/reducer/OneClickScreenContract.kt +++ b/android/navi-payment/src/main/java/com/navi/payment/nativepayment/presentation/reducer/OneClickScreenContract.kt @@ -7,6 +7,7 @@ package com.navi.payment.nativepayment.presentation.reducer +import androidx.activity.result.ActivityResult import com.navi.pay.common.model.view.CheckBalanceState import com.navi.pay.management.common.sendmoney.model.view.BankAccountsState import com.navi.pay.management.common.sendmoney.model.view.EligibilityState @@ -14,6 +15,7 @@ import com.navi.pay.onboarding.account.detail.model.view.LinkedAccountEntity import com.navi.payment.model.paymentmethod.Amount import com.navi.payment.nativepayment.model.PaymentsMainCtaState import kotlinx.coroutines.flow.MutableStateFlow +import org.json.JSONObject interface OneClickScreenContract : NaviPaymentViewModelContract @@ -40,9 +42,14 @@ sealed interface OneClickScreenEvent { data object OnArcNudgeClicked : OneClickScreenEvent data object OnCheckBalanceClicked : OneClickScreenEvent + + data class OnNaviUpiResultReceived(val result: ActivityResult, val generateToken: () -> Unit) : + OneClickScreenEvent } -sealed interface OneClickScreenEffect {} +sealed interface OneClickScreenEffect { + data class StartNaviUpiMPinSetAction(val payload: JSONObject) : OneClickScreenEffect +} enum class CheckoutCtaAction { SEND_MONEY_NAVIGATION, diff --git a/android/navi-payment/src/main/java/com/navi/payment/nativepayment/sharedviewmodel/NaviCheckoutViewModelV2.kt b/android/navi-payment/src/main/java/com/navi/payment/nativepayment/sharedviewmodel/NaviCheckoutViewModelV2.kt index 448fa24c1e..1346784c58 100644 --- a/android/navi-payment/src/main/java/com/navi/payment/nativepayment/sharedviewmodel/NaviCheckoutViewModelV2.kt +++ b/android/navi-payment/src/main/java/com/navi/payment/nativepayment/sharedviewmodel/NaviCheckoutViewModelV2.kt @@ -7,7 +7,11 @@ package com.navi.payment.nativepayment.sharedviewmodel +import android.app.Activity +import android.content.Intent import android.os.Bundle +import androidx.activity.compose.ManagedActivityResultLauncher +import androidx.activity.result.ActivityResult import androidx.lifecycle.viewModelScope import com.google.gson.Gson import com.navi.base.AppServiceManager @@ -23,11 +27,15 @@ import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper.NAVI_PMT_ONE_CLICK_CHECKOUT_API_TIMEOUT_MILLIS import com.navi.common.network.models.isSuccessWithData import com.navi.common.payments.arc.model.network.ArcNudgeBottomSheetData +import com.navi.common.upi.NAVI_PAY_RESPONSE +import com.navi.common.upi.NaviPayAction +import com.navi.common.upi.TYPE import com.navi.common.upi.UpiDataType import com.navi.common.usecase.LitmusExperimentsUseCase import com.navi.common.utils.CommonUtils.getDisplayableAmount import com.navi.common.utils.Constants.DEFAULT import com.navi.common.utils.EMPTY +import com.navi.common.utils.stringToJsonObject import com.navi.pay.common.model.view.NaviPayFlowType import com.navi.pay.common.setup.NaviPayManager import com.navi.pay.common.usecase.AccountListCheckBalanceUseCase @@ -50,6 +58,7 @@ import com.navi.payment.nativepayment.dataprovider.PaymentDataProvider import com.navi.payment.nativepayment.dataprovider.PaymentDataProvider.Companion.ACTION_TYPE import com.navi.payment.nativepayment.dataprovider.PaymentDataProvider.Companion.SCREEN_TYPE import com.navi.payment.nativepayment.dataprovider.PaymentDataProvider.Companion.UPI_LITE_MAX_PAYABLE_AMOUNT_PER_TRANSACTION +import com.navi.payment.nativepayment.dataprovider.getMpinSetAction import com.navi.payment.nativepayment.model.GetPaymentMethodsV3Request import com.navi.payment.nativepayment.model.InstrumentDetails import com.navi.payment.nativepayment.model.NaviPaymentScreenType @@ -95,6 +104,7 @@ import com.navi.payment.utils.getArcNudgeBottomSheetCampaignTitle import com.navi.payment.utils.getArcNudgeBottomSheetTitle import com.navi.payment.utils.getInstalledUpiAppsList import com.navi.payment.utils.getPMSMetricInfo +import com.navi.payment.utils.validateUpiProcessPayload import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds @@ -244,11 +254,45 @@ constructor( is OneClickScreenEvent.OnCheckBalanceClicked -> { handleCheckBalanceClicked() } + + is OneClickScreenEvent.OnNaviUpiResultReceived -> { + handleNaviUpiResultReceived( + result = event.result, + generateToken = event.generateToken, + ) + } } } } } + private fun handleNaviUpiResultReceived(result: ActivityResult, generateToken: () -> Unit) { + val resultResponse = result.data?.extras?.getString(NAVI_PAY_RESPONSE) + val payloadJson = resultResponse.stringToJsonObject() + if ( + result.resultCode == 200 && + payloadJson != null && + validateUpiProcessPayload(payloadJson) + ) { + val actionType = payloadJson.optString(TYPE) + if (actionType == NaviPayAction.SET_PIN.name) { + updateBottomSheetUIState( + showBottomSheet = true, + bottomSheetUIState = + OneClickBottomSheetUiState.RedirectingBottomSheet( + titleText = + resourceProvider.getString(R.string.redirecting_make_payment) + ), + ) + triggerTokenGeneration(generateToken) + } else { + // Do Nothing - Onboarding is handled by NaviPayPspManager + } + } else { + // Do Nothing + } + } + fun onTokenGenerated(paymentSdkInitParams: PaymentSdkInitParams) { viewModelScope.safeLaunch { naviPaymentAnalytics.onTokenReceived( @@ -605,16 +649,16 @@ constructor( isMpinSetOfSelectedAccount = linkedAccountEntity.isMPinSet, ctaAction = ctaAction.toString(), ) - naviPayPspManager.evaluateAndOnboardPspForFlow( - naviPayFlowType = NaviPayFlowType.PIN_MANAGEMENT, - vpaEntityList = linkedAccountEntity.vpaEntityList, - screenName = NaviPaymentScreenType.ONE_CLICK_CHECKOUT_SCREEN.name, - onPspEvaluated = { pspEvaluationResult -> - if (pspEvaluationResult.onboardingDataEntity.isNotNull()) { - resetCheckBalanceStates() - } - }, - ) + val pinSetPayLoad = getMpinSetAction(state.value.selectedAccount?.accountId.orEmpty()) + _effect.emit(OneClickScreenEffect.StartNaviUpiMPinSetAction(payload = pinSetPayLoad)) + } + + fun startAction( + activity: Activity, + upiResultLauncher: ManagedActivityResultLauncher, + data: JSONObject, + ) { + naviPayManager.startAction(activity, upiResultLauncher, data) } private suspend fun startPayment(generateToken: () -> Unit) { @@ -811,7 +855,12 @@ constructor( val pspType = pspEvaluationResult.onboardingDataEntity?.pspType ?: return if (selectedBankAccount.isMPinSet.not().orFalse()) { - handleSetPinClick(selectedBankAccount) + _effect.emit( + OneClickScreenEffect.StartNaviUpiMPinSetAction( + payload = getMpinSetAction(selectedBankAccount.accountId) + ) + ) + return } if (pspEvaluationResult.isOnboardingTriggered) {